trifid/nebula-ffi/build.rs

171 lines
4.7 KiB
Rust

use bindgen::CargoCallbacks;
use std::path::Path;
use std::path::PathBuf;
use std::{env, process};
fn get_cargo_target_dir() -> Result<std::path::PathBuf, Box<dyn std::error::Error>> {
let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR")?);
let profile = std::env::var("PROFILE")?;
let mut target_dir = None;
let mut sub_path = out_dir.as_path();
while let Some(parent) = sub_path.parent() {
if parent.ends_with(&profile) {
target_dir = Some(parent);
break;
}
sub_path = parent;
}
let target_dir = target_dir.ok_or("not found")?;
Ok(target_dir.to_path_buf())
}
fn main() {
// Find compiler:
// 1. GOC
// 2. /usr/local/go/bin/go
// 3. system "go"
let compiler = match env::var("GOC") {
Ok(c) => c,
Err(_) => {
if Path::new("/usr/local/go/bin/go").exists() {
"/usr/local/go/bin/go".to_string()
} else {
"go".to_string()
}
}
};
println!("using go compiler {}", compiler);
//gobuild::Build::new().compiler(compiler).buildmode(BuildMode::CArchive).file("main.go").compile("nebulaffi");
let c_compiler = cc::Build::new().try_get_compiler().unwrap();
let out_dir = env::var("OUT_DIR").unwrap();
let out_path = PathBuf::from(out_dir);
let out_file = lib_name();
let out = out_path.join(out_file);
let mut command = process::Command::new(compiler);
command.args([
"build",
"-buildmode",
link_type().as_str(),
"-o",
out.display().to_string().as_str(),
"main.go",
]);
command.env("CGO_ENABLED", "1");
command.env("CC", c_compiler.path());
command.env("GOARCH", goarch());
command.env("GOOS", goos());
println!("running go compile command: {:?}", command);
let mut child = command.spawn().unwrap();
let status = child.wait().unwrap();
println!("{}", status);
if !status.success() {
panic!("`{:?}` exited with status code {}", command, status);
}
println!("Go compile success");
copy_if_windows();
print_link();
println!(
"cargo:rustc-link-search=native={}",
env::var("OUT_DIR").unwrap()
);
//let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
//println!("cargo:rustc-link-search={}", out_path.display());
println!("cargo:rerun-if-changed=go.mod");
println!("cargo:rerun-if-changed=go.sum");
println!("cargo:rerun-if-changed=main.go");
println!("Generating bindings");
let bindings = bindgen::Builder::default()
.header(out_path.join(header_name()).display().to_string())
.parse_callbacks(Box::new(CargoCallbacks))
.generate()
.expect("Error generating CFFI bindings");
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
fn lib_name() -> String {
if env::var("CARGO_CFG_TARGET_FAMILY").unwrap() == "windows" {
"nebula.dll".to_string()
} else {
"libnebula.a".to_string()
}
}
fn header_name() -> String {
if env::var("CARGO_CFG_TARGET_FAMILY").unwrap() == "windows" {
"nebula.h".to_string()
} else {
"libnebula.h".to_string()
}
}
fn copy_if_windows() {
let target_dir = get_cargo_target_dir().unwrap();
let target_file = target_dir.join(lib_name());
let out_dir = env::var("OUT_DIR").unwrap();
let out_path = PathBuf::from(out_dir);
let out_file = lib_name();
let out = out_path.join(out_file);
std::fs::copy(out, target_file).unwrap();
}
fn goarch() -> String {
match env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_str() {
"x86" => "386",
"x86_64" => "amd64",
"mips" => "mips",
"powerpc" => "ppc",
"powerpc64" => "ppc64",
"arm" => "arm",
"aarch64" => "arm64",
arch => panic!("unsupported architecture {arch}"),
}
.to_string()
}
fn goos() -> String {
match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
"windows" => "windows",
"macos" => "darwin",
"ios" => "darwin",
"linux" => "linux",
"android" => "android",
"freebsd" => "freebsd",
"dragonfly" => "dragonfly",
"openbsd" => "openbsd",
"netbsd" => "netbsd",
os => panic!("unsupported operating system {os}"),
}
.to_string()
}
fn print_link() {
if env::var("CARGO_CFG_TARGET_FAMILY").unwrap() == "windows" {
println!("cargo:rustc-link-lib=dylib=nebula");
} else {
println!("cargo:rustc-link-lib=static=nebula");
}
}
fn link_type() -> String {
if env::var("CARGO_CFG_TARGET_FAMILY").unwrap() == "windows" {
"c-shared".to_string()
} else {
"c-archive".to_string()
}
}