diff options
| -rw-r--r-- | wireguard-go-rs/build.rs | 228 |
1 files changed, 119 insertions, 109 deletions
diff --git a/wireguard-go-rs/build.rs b/wireguard-go-rs/build.rs index 4a99a9a6d6..f13f034116 100644 --- a/wireguard-go-rs/build.rs +++ b/wireguard-go-rs/build.rs @@ -14,13 +14,18 @@ fn main() -> anyhow::Result<()> { // Mark "daita" as a conditional configuration flag println!("cargo::rustc-check-cfg=cfg(daita)"); + // Enable the DAITA (rust) feature flag + println!(r#"cargo::rustc-cfg=daita"#); + // Rerun build-script if libwg (or wireguard-go) is changed println!("cargo::rerun-if-changed=libwg"); - let target_os = target_os()?; - match target_os { - Os::Windows | Os::Linux | Os::Macos => build_desktop_lib(target_os)?, - Os::Android => build_android_dynamic_lib()?, + let out_dir = env::var("OUT_DIR").context("Missing OUT_DIR")?; + match target_os()? { + Os::Windows => build_windows_dynamic_lib(&out_dir)?, + Os::Linux => build_linux_static_lib(&out_dir)?, + Os::Macos => build_macos_static_lib(&out_dir)?, + Os::Android => build_android_dynamic_lib(&out_dir)?, } Ok(()) @@ -108,128 +113,137 @@ fn target_arch() -> anyhow::Result<Arch> { } } -/// Compile libwg as a library and place it in `OUT_DIR`. -fn build_desktop_lib(target_os: Os) -> anyhow::Result<()> { - let out_dir = env::var("OUT_DIR").context("Missing OUT_DIR")?; - - let target_arch = target_arch()?; +/// Compile libwg and maybenot and place them in the target dir relative to `OUT_DIR`. +fn build_windows_dynamic_lib(out_dir: &str) -> anyhow::Result<()> { + let target_dir = Path::new(out_dir) + .ancestors() + .nth(3) + .context("Failed to find target dir")?; + build_shared_maybenot_lib(target_dir).context("Failed to build maybenot")?; + let dll_path = target_dir.join("libwg.dll"); let mut go_build = Command::new("go"); - go_build.env("CGO_ENABLED", "1").current_dir("./libwg"); - - // are we cross compiling? - let cross_compiling = host_os() != target_os || host_arch() != target_arch; + go_build + .env("CGO_ENABLED", "1") + .current_dir("./libwg") + .args(["build", "-v"]) + .arg("-o") + .arg(&dll_path) + .args(["--tags", "daita"]) + // Build DLL + .args(["-buildmode", "c-shared"]) + // Needed for linking against maybenot-ffi + .env("CGO_LDFLAGS", format!("-L{}", target_dir.to_str().unwrap())) + .env("GOOS", "windows"); + let target_arch = target_arch()?; + // We explicitly use zig for compiling libwg. Any MinGW-compatible toolchain should work. match target_arch { - Arch::Amd64 => go_build.env("GOARCH", "amd64"), - Arch::Arm64 => go_build.env("GOARCH", "arm64"), - }; - - match target_os { - Os::Android => bail!("Android is not a desktop platform!"), - Os::Windows => { - let target_dir = Path::new(&out_dir) - .ancestors() - .nth(3) - .context("Failed to find target dir")?; - - // building maybenot is required for DAITA - wireguard-go will link to it at runtime. - build_shared_maybenot_lib(target_dir).context("Failed to build maybenot")?; + Arch::Amd64 => { + go_build.env("CC", "zig cc -target x86_64-windows"); + go_build.env("GOARCH", "amd64"); + } + Arch::Arm64 => { + go_build.env("CC", "zig cc -target aarch64-windows"); + go_build.env("GOARCH", "arm64"); + } + } - let dll_path = target_dir.join("libwg.dll"); + generate_windows_lib(target_arch, target_dir)?; - go_build - .args(["build", "-v"]) - .arg("-o") - .arg(&dll_path) - .args(["--tags", "daita"]) - // Build DLL - .args(["-buildmode", "c-shared"]) - // Needed for linking against maybenot-ffi - .env("CGO_LDFLAGS", format!("-L{}", target_dir.to_str().unwrap())) - .env("GOOS", "windows"); + exec(go_build)?; - // Build using zig - match target_arch { - Arch::Amd64 => { - go_build.env("CC", "zig cc -target x86_64-windows"); - } - Arch::Arm64 => { - go_build.env("CC", "zig cc -target aarch64-windows"); - } - } + println!("cargo::rustc-link-search={}", target_dir.to_str().unwrap()); + println!("cargo::rustc-link-lib=dylib=libwg"); - generate_windows_lib(target_arch, target_dir)?; + Ok(()) +} - println!("cargo::rustc-link-search={}", target_dir.to_str().unwrap()); - println!("cargo::rustc-link-lib=dylib=libwg"); - } - Os::Linux => { - let out_file = format!("{out_dir}/libwg.a"); - go_build - .args(["build", "-v", "-o", &out_file]) - .args(["--tags", "daita"]); +/// Compile libwg and place it in `OUT_DIR`. +fn build_linux_static_lib(out_dir: &str) -> anyhow::Result<()> { + let out_file = format!("{out_dir}/libwg.a"); + let mut go_build = Command::new("go"); + go_build + .env("CGO_ENABLED", "1") + .current_dir("./libwg") + .args(["build", "-v", "-o", &out_file]) + .args(["--tags", "daita"]) + // Build static lib + .args(["-buildmode", "c-archive"]) + .env("GOOS", "linux"); - // Build static lib - go_build.args(["-buildmode", "c-archive"]); + let target_arch = target_arch()?; + match target_arch { + Arch::Amd64 => go_build.env("GOARCH", "amd64"), + Arch::Arm64 => go_build.env("GOARCH", "arm64"), + }; - go_build.env("GOOS", "linux"); + if is_cross_compiling()? { + match target_arch { + Arch::Arm64 => go_build.env("CC", "aarch64-linux-gnu-gcc"), + Arch::Amd64 => bail!("cross-compiling to linux x86_64 is not implemented"), + }; + } - if cross_compiling { - match target_arch { - Arch::Arm64 => go_build.env("CC", "aarch64-linux-gnu-gcc"), - Arch::Amd64 => bail!("cross-compiling to linux x86_64 is not implemented"), - }; - } + exec(go_build)?; - // make sure to link to the resulting binary - println!("cargo::rustc-link-search={out_dir}"); - println!("cargo::rustc-link-lib=static=wg"); - } - Os::Macos => { - let out_file = format!("{out_dir}/libwg.a"); - go_build - .args(["build", "-v", "-o", &out_file]) - .args(["--tags", "daita"]); + // make sure to link to the resulting binary + println!("cargo::rustc-link-search={out_dir}"); + println!("cargo::rustc-link-lib=static=wg"); - // Build static lib - go_build.args(["-buildmode", "c-archive"]); + Ok(()) +} - go_build.env("GOOS", "darwin"); +/// Compile libwg and place it in `OUT_DIR`. +fn build_macos_static_lib(out_dir: &str) -> anyhow::Result<()> { + let out_file = format!("{out_dir}/libwg.a"); + let mut go_build = Command::new("go"); + go_build + .env("CGO_ENABLED", "1") + .current_dir("./libwg") + .args(["build", "-v", "-o", &out_file]) + .args(["--tags", "daita"]) + // Build static lib + .args(["-buildmode", "c-archive"]) + .env("GOOS", "darwin"); - if cross_compiling { - let sdkroot = env::var("SDKROOT").context("Missing 'SDKROOT'")?; + let target_arch = target_arch()?; + match target_arch { + Arch::Amd64 => go_build.env("GOARCH", "amd64"), + Arch::Arm64 => go_build.env("GOARCH", "arm64"), + }; - let c_arch = match target_arch { - Arch::Amd64 => "x86_64", - Arch::Arm64 => "arm64", - }; + if is_cross_compiling()? { + let sdkroot = env::var("SDKROOT").context("Missing 'SDKROOT'")?; - let xcrun_output = - exec(Command::new("xcrun").args(["-sdk", &sdkroot, "--find", "clang"]))?; - go_build.env("CC", xcrun_output); + let c_arch = match target_arch { + Arch::Amd64 => "x86_64", + Arch::Arm64 => "arm64", + }; - let cflags = format!("-isysroot {sdkroot} -arch {c_arch} -I{sdkroot}/usr/include"); - go_build.env("CFLAGS", cflags); - go_build.env("CGO_CFLAGS", format!("-isysroot {sdkroot} -arch {c_arch}")); - go_build.env("CGO_LDFLAGS", format!("-isysroot {sdkroot} -arch {c_arch}")); - go_build.env("LD_LIBRARY_PATH", format!("{sdkroot}/usr/lib")); - } + let xcrun_output = exec(Command::new("xcrun").args(["-sdk", &sdkroot, "--find", "clang"]))?; + go_build.env("CC", xcrun_output); - // make sure to link to the resulting binary - println!("cargo::rustc-link-search={out_dir}"); - println!("cargo::rustc-link-lib=static=wg"); - } + let cflags = format!("-isysroot {sdkroot} -arch {c_arch} -I{sdkroot}/usr/include"); + go_build.env("CFLAGS", cflags); + go_build.env("CGO_CFLAGS", format!("-isysroot {sdkroot} -arch {c_arch}")); + go_build.env("CGO_LDFLAGS", format!("-isysroot {sdkroot} -arch {c_arch}")); + go_build.env("LD_LIBRARY_PATH", format!("{sdkroot}/usr/lib")); } exec(go_build)?; - // Enable the DAITA (rust) feature flag - println!(r#"cargo::rustc-cfg=daita"#); + println!("cargo::rustc-link-search={out_dir}"); + println!("cargo::rustc-link-lib=static=wg"); Ok(()) } +/// Return whether compiling for an architecture or OS other than the host +fn is_cross_compiling() -> anyhow::Result<bool> { + Ok(host_os() != target_os()? || host_arch() != target_arch()?) +} + // Build dynamically library for maybenot fn build_shared_maybenot_lib(out_dir: impl AsRef<Path>) -> anyhow::Result<()> { let target_triple = env::var("TARGET").context("Missing 'TARGET'")?; @@ -279,8 +293,8 @@ fn build_shared_maybenot_lib(out_dir: impl AsRef<Path>) -> anyhow::Result<()> { Ok(()) } -/// Generate a library for the exported functions. Required for linking. -/// This requires `lib.exe` in the path. +/// Generate a library for the exported functions. Required for load-time linking. +/// This requires `msbuild.exe` in the path. fn generate_windows_lib(arch: Arch, out_dir: impl AsRef<Path>) -> anyhow::Result<()> { let exports_def_path = out_dir.as_ref().join("exports.def"); generate_exports_def(&exports_def_path).context("Failed to generate exports.def")?; @@ -288,7 +302,7 @@ fn generate_windows_lib(arch: Arch, out_dir: impl AsRef<Path>) -> anyhow::Result .context("Failed to generate lib from exports.def") } -/// Find the correct lib.exe for this host and the target arch. +/// Find the correct `lib.exe` for this host and the target arch. fn find_lib_exe() -> anyhow::Result<PathBuf> { let msbuild_exe = find_msbuild_exe()?; @@ -387,17 +401,14 @@ fn generate_exports_def(exports_path: impl AsRef<Path>) -> anyhow::Result<()> { writeln!(file, "LIBRARY libwg").context("Write LIBRARY statement")?; writeln!(file, "EXPORTS").context("Write EXPORTS statement")?; - let mut libwg_exports = vec![]; for path in &[ "./libwg/libwg.go", "./libwg/libwg_windows.go", "./libwg/libwg_daita.go", ] { - libwg_exports.extend(gather_exports(path).context("Failed to find exports")?); - } - - for export in libwg_exports { - writeln!(file, "\t{export}").context("Failed to output exported function")?; + for export in gather_exports(path).context("Failed to find exports")? { + writeln!(file, "\t{export}").context("Failed to output exported function")?; + } } Ok(()) @@ -430,8 +441,7 @@ fn gather_exports(go_src_path: impl AsRef<Path>) -> anyhow::Result<Vec<String>> /// Compile libwg as a dynamic library for android and place it in [`android_output_path`]. // NOTE: We use dynamic linking as Go cannot produce static binaries specifically for Android. -fn build_android_dynamic_lib() -> anyhow::Result<()> { - let out_dir = env::var("OUT_DIR").context("Missing OUT_DIR")?; +fn build_android_dynamic_lib(out_dir: &str) -> anyhow::Result<()> { let target_triple = env::var("TARGET").context("Missing 'TARGET'")?; let target = AndroidTarget::from_str(&target_triple)?; |
