trifid/nebula-ffi/build.rs

185 lines
5.9 KiB
Rust
Raw Normal View History

2023-06-27 03:17:49 +00:00
use std::path::Path;
2023-11-23 20:23:52 +00:00
use std::path::PathBuf;
use std::{env, process};
use bindgen::CargoCallbacks;
2023-06-26 02:00:36 +00:00
2023-10-10 13:21:37 +00:00
fn get_cargo_target_dir() -> Result<std::path::PathBuf, Box<dyn std::error::Error>> {
2023-12-16 03:59:20 +00:00
let skip_triple = std::env::var("TARGET")? == std::env::var("HOST")?;
let skip_parent_dirs = if skip_triple { 4 } else { 5 };
2023-10-10 13:21:37 +00:00
let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR")?);
2023-12-16 03:59:20 +00:00
let mut current = out_dir.as_path();
for _ in 0..skip_parent_dirs {
current = current.parent().ok_or("not found")?;
2023-10-10 13:21:37 +00:00
}
2023-12-16 03:59:20 +00:00
Ok(std::path::PathBuf::from(current))
2023-10-10 13:21:37 +00:00
}
2023-06-26 02:00:36 +00:00
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()
}
}
2023-09-25 00:20:14 +00:00
};
2023-06-27 03:17:49 +00:00
println!("using go compiler {}", compiler);
let c_compiler = cc::Build::new().try_get_compiler().unwrap();
let compile_config = get_compile_config();
let out_dir = env::var("OUT_DIR").unwrap();
let out_path = PathBuf::from(out_dir);
let out_file = compile_config.lib_filename.clone();
let out = out_path.join(out_file);
let mut command = process::Command::new(compiler);
2023-11-23 20:23:52 +00:00
command.args([
"build",
"-buildmode",
compile_config.link_type.as_str(),
2023-11-23 20:23:52 +00:00
"-o",
out.display().to_string().as_str(),
"main.go",
]);
command.env("CGO_ENABLED", "1");
command.env("CC", c_compiler.path());
command.env("GOARCH", compile_config.goarch.clone());
command.env("GOOS", compile_config.goos.clone());
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");
2023-06-26 02:00:36 +00:00
2023-11-23 20:23:52 +00:00
println!(
"cargo:rustc-link-search={}",
2023-11-23 20:23:52 +00:00
env::var("OUT_DIR").unwrap()
);
if compile_config.link_type == "c-shared" {
copy_shared_lib(&compile_config);
println!("cargo:rustc-link-lib=dylib=nebula");
} else {
println!("cargo:rustc-link-lib=static=nebula");
}
//let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
2023-06-26 02:00:36 +00:00
//println!("cargo:rustc-link-search={}", out_path.display());
2023-06-26 02:00:36 +00:00
println!("cargo:rerun-if-changed=go.mod");
println!("cargo:rerun-if-changed=go.sum");
println!("cargo:rerun-if-changed=main.go");
println!("Generating bindings");
2023-06-26 02:00:36 +00:00
let bindings = bindgen::Builder::default()
.header(out_path.join(compile_config.header_filename).display().to_string())
.parse_callbacks(Box::new(CargoCallbacks::new()))
2023-06-26 02:00:36 +00:00
.generate()
.expect("Error generating CFFI bindings");
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
fn copy_shared_lib(go_compile_config: &GoCompileConfig) {
2023-10-10 13:21:37 +00:00
let target_dir = get_cargo_target_dir().unwrap();
let target_file = target_dir.join(go_compile_config.lib_filename.clone());
2023-10-10 13:21:37 +00:00
let out_dir = env::var("OUT_DIR").unwrap();
let out_path = PathBuf::from(out_dir);
let out_file = go_compile_config.lib_filename.clone();
2023-10-10 13:21:37 +00:00
let out = out_path.join(out_file);
std::fs::copy(out, target_file).unwrap();
}
// Go build supported modes.
// Pulled from golang/go/src/internal/platform/supported.go
// c-archive:
// aix, darwin, ios, windows
// linux/386, linux/amd64, linux/arm, linux/armbe, linux/arm64, linux/arm64be, linux/loong64, linux/ppc64le, linux/riscv64, linux/s390x
// freebsd/amd64
// c-shared:
// linux/amd64, linux/arm, linux/arm64, linux/loong64, linux/386, linux/ppc64le, linux/riscv64, linux/s390x
// android/amd64, android/arm, android/arm64, android/386
// freebsd/amd64
// darwin/amd64, darwin/arm64
// windows/amd64, windows/386, windows/arm64
struct GoCompileConfig {
goarch: String,
goos: String,
link_type: String,
lib_filename: String,
header_filename: String
}
fn get_compile_config() -> GoCompileConfig {
let goarch = goarch();
let goos = goos();
let platform_value = format!("{}/{}", goos, goarch);
let (preferred_link_type, lib_filename, header_filename) = match (goos.as_str(), goarch.as_str()) {
("darwin", _) => ("c-archive", "libnebula.a", "libnebula.h"),
("windows", _) => ("c-archive", "libnebula.a", "libnebula.h"),
("linux", "386") | ("linux", "amd64") | ("linux", "arm") | ("linux", "armbe") | ("linux", "arm64") | ("linux", "arm64be") | ("linux", "loong64") | ("linux", "ppc64le") | ("linux", "riscv64") | ("linux", "s390x") => ("c-archive", "libnebula.a", "libnebula.h"),
("freebsd", "amd64") => ("c-archive", "libnebula.a", "libnebula.h"),
_ => panic!("unsupported platform {} / {}", env::var("TARGET").unwrap(), platform_value)
};
GoCompileConfig {
goarch,
goos,
link_type: preferred_link_type.to_string(),
lib_filename: lib_filename.to_string(),
header_filename: header_filename.to_string()
}
}
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",
2023-11-23 20:23:52 +00:00
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",
2023-11-23 20:23:52 +00:00
os => panic!("unsupported operating system {os}"),
}
.to_string()
}