From 281e0f094d1bb6df7552a58d9f67b4f51393292d Mon Sep 17 00:00:00 2001 From: messense Date: Wed, 29 Dec 2021 14:07:02 +0800 Subject: [PATCH] Add C++ support for `--zig` Set `TARGET_CC` and `TARGET_CXX` to support both cc-rs and cmake-rs --- src/compile.rs | 67 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/src/compile.rs b/src/compile.rs index 7babc4e8b..bbf72cc0e 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -111,7 +111,7 @@ fn compile_universal2( /// /// We create different files for different args because otherwise cargo might skip recompiling even /// if the linker target changed -fn prepare_zig_linker(context: &BuildContext) -> Result { +fn prepare_zig_linker(context: &BuildContext) -> Result<(PathBuf, PathBuf)> { let target = &context.target; let arch = if target.cross_compiling() { if matches!(target.target_arch(), Arch::Armv7L) { @@ -122,20 +122,24 @@ fn prepare_zig_linker(context: &BuildContext) -> Result { } else { "native".to_string() }; - let (zig_linker, cc_args) = match context.platform_tag { + let (zig_cc, zig_cxx, cc_args) = match context.platform_tag { // Not sure branch even has any use case, but it doesn't hurt to support it - None | Some(PlatformTag::Linux) => { - ("./zigcc-gnu.sh".to_string(), format!("{}-linux-gnu", arch)) - } + None | Some(PlatformTag::Linux) => ( + "./zigcc-gnu.sh".to_string(), + "./zigcxx-gnu.sh".to_string(), + format!("{}-linux-gnu", arch), + ), Some(PlatformTag::Musllinux { x, y }) => { println!("⚠️ Warning: zig with musl is unstable"); ( format!("./zigcc-musl-{}-{}.sh", x, y), + format!("./zigcxx-musl-{}-{}.sh", x, y), format!("{}-linux-musl", arch), ) } Some(PlatformTag::Manylinux { x, y }) => ( format!("./zigcc-gnu-{}-{}.sh", x, y), + format!("./zigcxx-gnu-{}-{}.sh", x, y), // https://github.com/ziglang/zig/issues/10050#issuecomment-956204098 format!( "${{@/-lgcc_s/-lunwind}} -target {}-linux-gnu.{}.{}", @@ -150,21 +154,36 @@ fn prepare_zig_linker(context: &BuildContext) -> Result { .join(env!("CARGO_PKG_NAME")) .join(env!("CARGO_PKG_VERSION")); fs::create_dir_all(&zig_linker_dir)?; - let zig_linker = zig_linker_dir.join(zig_linker); + let zig_cc = zig_linker_dir.join(zig_cc); + let zig_cxx = zig_linker_dir.join(zig_cxx); + + let mut zig_cc_file = create_linker_script(&zig_cc)?; + writeln!(&mut zig_cc_file, "#!/bin/bash")?; + writeln!(&mut zig_cc_file, "python -m ziglang cc {}", cc_args)?; + drop(zig_cc_file); + + let mut zig_cxx_file = create_linker_script(&zig_cxx)?; + writeln!(&mut zig_cxx_file, "#!/bin/bash")?; + writeln!(&mut zig_cxx_file, "python -m ziglang c++ {}", cc_args)?; + drop(zig_cxx_file); + + Ok((zig_cc, zig_cxx)) +} - #[cfg(target_family = "unix")] - let mut custom_linker_file = OpenOptions::new() +#[cfg(target_family = "unix")] +fn create_linker_script(path: &Path) -> Result { + let custom_linker_file = OpenOptions::new() .create(true) .write(true) .truncate(true) .mode(0o700) - .open(&zig_linker)?; - #[cfg(not(target_family = "unix"))] - let mut custom_linker_file = File::create(&zig_linker)?; - writeln!(&mut custom_linker_file, "#!/bin/bash")?; - writeln!(&mut custom_linker_file, "python -m ziglang cc {}", cc_args)?; - drop(custom_linker_file); - Ok(zig_linker) + .open(path)?; + Ok(custom_linker_file) +} + +#[cfg(not(target_family = "unix"))] +fn create_linker_script(path: &Path) -> Result { + File::create(path) } fn compile_target( @@ -172,10 +191,12 @@ fn compile_target( python_interpreter: Option<&PythonInterpreter>, bindings_crate: &BridgeModel, ) -> Result> { - let zig_linker = if context.zig && context.target.is_linux() { - Some(prepare_zig_linker(context).context("Failed to create zig linker wrapper")?) + let (zig_cc, zig_cxx) = if context.zig && context.target.is_linux() { + let (cc, cxx) = + prepare_zig_linker(context).context("Failed to create zig linker wrapper")?; + (Some(cc), Some(cxx)) } else { - None + (None, None) }; let mut shared_args = vec!["--manifest-path", context.manifest_path.to_str().unwrap()]; @@ -279,14 +300,18 @@ fn compile_target( // but forwarding stderr is still useful in case there some non-json error .stderr(Stdio::inherit()); - if let Some(zig_linker) = zig_linker { + // Also set TARGET_CC and TARGET_CXX for cc-rs and cmake-rs + if let Some(zig_cc) = zig_cc { let env_target = context .target .target_triple() .to_uppercase() .replace("-", "_"); - build_command.env(format!("{}_CC", env_target), &zig_linker); - build_command.env(format!("CARGO_TARGET_{}_LINKER", env_target), &zig_linker); + build_command.env("TARGET_CC", &zig_cc); + build_command.env(format!("CARGO_TARGET_{}_LINKER", env_target), &zig_cc); + } + if let Some(zig_cxx) = zig_cxx { + build_command.env("TARGET_CXX", &zig_cxx); } if let BridgeModel::BindingsAbi3(_, _) = bindings_crate {