201 lines
6.2 KiB
Rust
201 lines
6.2 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 skip_triple = std::env::var("TARGET")? == std::env::var("HOST")?;
|
|
let skip_parent_dirs = if skip_triple { 4 } else { 5 };
|
|
|
|
let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR")?);
|
|
let mut current = out_dir.as_path();
|
|
for _ in 0..skip_parent_dirs {
|
|
current = current.parent().ok_or("not found")?;
|
|
}
|
|
|
|
Ok(std::path::PathBuf::from(current))
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
command.args([
|
|
"build",
|
|
"-buildmode",
|
|
compile_config.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", 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");
|
|
|
|
println!("cargo:rustc-link-search={}", 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());
|
|
|
|
//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(compile_config.header_filename)
|
|
.display()
|
|
.to_string(),
|
|
)
|
|
.parse_callbacks(Box::new(CargoCallbacks::new()))
|
|
.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) {
|
|
let target_dir = get_cargo_target_dir().unwrap();
|
|
let target_file = target_dir.join(go_compile_config.lib_filename.clone());
|
|
let out_dir = env::var("OUT_DIR").unwrap();
|
|
let out_path = PathBuf::from(out_dir);
|
|
let out_file = go_compile_config.lib_filename.clone();
|
|
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",
|
|
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()
|
|
}
|