diff --git a/src/linux/mod.rs b/src/linux/mod.rs index 72162cc..9f12dad 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -18,3 +18,16 @@ pub static FCNTL_H: &str = r#" __asm__(".symver fcntl64, fcntl@GLIBC_2.2.5"); #endif "#; + +pub static MUSL_WEAK_SYMBOLS_MAPPING_SCRIPT: &str = r#" +PROVIDE (open64 = open); +PROVIDE (stat64 = stat); +PROVIDE (lstat64 = lstat); +PROVIDE (fstat64 = fstat); +PROVIDE (fstatat64 = fstatat); +PROVIDE (ftruncate64 = ftruncate); +PROVIDE (lseek64 = lseek); +PROVIDE (pread64 = pread); +PROVIDE (pwrite64 = pwrite); +PROVIDE (readdir64 = readdir); +"#; diff --git a/src/zig.rs b/src/zig.rs index f4290fd..e0e4134 100644 --- a/src/zig.rs +++ b/src/zig.rs @@ -104,7 +104,7 @@ impl Zig { // zig doesn't provide gcc_eh alternative // We use libc++ to replace it on windows gnu targets return Some("-lc++".to_string()); - } else if arg == "-Wl,-Bdynamic" && Self::is_zig_above_0_11_0(&zig_version) { + } else if arg == "-Wl,-Bdynamic" && is_zig_above_0_11_0(&zig_version) { // https://github.com/ziglang/zig/pull/16058 // zig changes the linker behavior, -Bdynamic won't search *.a for mingw, but this may be fixed in the later version // here is a workaround to replace the linker switch with -search_paths_first, which will search for *.dll,*lib first, @@ -391,25 +391,12 @@ impl Zig { .iter() .map(|target| target.split_once('.').map(|(t, _)| t).unwrap_or(target)) .collect::>(); - let zig_version = Zig::zig_version()?; let rustc_meta = rustc_version::version_meta()?; let host_target = &rustc_meta.host; for (parsed_target, raw_target) in rust_targets.iter().zip(&cargo.target) { let env_target = parsed_target.replace('-', "_"); let zig_wrapper = prepare_zig_linker(raw_target)?; - // as zig 0.11.0 is released, its musl has been upgraded to 1.2.4 with break changes - // but rust is still with musl 1.2.3 - // we need this workaround until rust adopts new musl or removes LFS64 symbols - // https://github.com/ziglang/zig/pull/16098 - if Self::is_zig_above_0_11_0(&zig_version) && raw_target.contains("musl") { - Self::add_env_if_missing( - cmd, - format!("CARGO_TARGET_{}_LINKER", env_target.to_uppercase()), - "rust-lld", - ) - } - if is_mingw_shell() { let zig_cc = zig_wrapper.cc.to_slash_lossy(); let zig_cxx = zig_wrapper.cxx.to_slash_lossy(); @@ -514,10 +501,6 @@ impl Zig { Ok(()) } - fn is_zig_above_0_11_0(zig_version: &semver::Version) -> bool { - zig_version >= &semver::Version::new(0, 11, 0) - } - /// Collects compiler options used by `zig cc` for given target. /// Used for the case where `zig cc` cannot be used but underlying options should be retained, /// for example, as in bindgen (which requires libclang.so and thus is independent from zig). @@ -891,6 +874,14 @@ set(CMAKE_RANLIB {ranlib})"#, } } +fn is_zig_above_0_11_0(zig_version: &semver::Version) -> bool { + zig_version >= &semver::Version::new(0, 11, 0) +} + +fn is_rust_below_1_72(rustc_version: &semver::Version) -> bool { + rustc_version < &semver::Version::new(1, 72, 0) +} + fn cache_dir() -> PathBuf { env::var("CARGO_ZIGBUILD_CACHE_DIR") .ok() @@ -1035,8 +1026,8 @@ pub fn prepare_zig_linker(target: &str) -> Result { let zig_linker_dir = cache_dir(); fs::create_dir_all(&zig_linker_dir)?; - if triple.operating_system == OperatingSystem::Linux - && matches!( + if triple.operating_system == OperatingSystem::Linux { + if matches!( triple.environment, Environment::Gnu | Environment::Gnuspe @@ -1045,35 +1036,58 @@ pub fn prepare_zig_linker(target: &str) -> Result { | Environment::Gnuabi64 | Environment::GnuIlp32 | Environment::Gnueabihf - ) - { - let glibc_version = if abi_suffix.is_empty() { - (2, 17) - } else { - let mut parts = abi_suffix[1..].split('.'); - let major: usize = parts.next().unwrap().parse()?; - let minor: usize = parts.next().unwrap().parse()?; - (major, minor) - }; - // See https://github.com/ziglang/zig/issues/9485 - if glibc_version < (2, 28) { - use crate::linux::{FCNTL_H, FCNTL_MAP}; + ) { + let glibc_version = if abi_suffix.is_empty() { + (2, 17) + } else { + let mut parts = abi_suffix[1..].split('.'); + let major: usize = parts.next().unwrap().parse()?; + let minor: usize = parts.next().unwrap().parse()?; + (major, minor) + }; + // See https://github.com/ziglang/zig/issues/9485 + if glibc_version < (2, 28) { + use crate::linux::{FCNTL_H, FCNTL_MAP}; + use std::fmt::Write as _; + + let zig_version = Zig::zig_version()?; + if !is_zig_above_0_11_0(&zig_version) { + let fcntl_map = zig_linker_dir.join("fcntl.map"); + fs::write(&fcntl_map, FCNTL_MAP)?; + let fcntl_h = zig_linker_dir.join("fcntl.h"); + fs::write(&fcntl_h, FCNTL_H)?; + + write!( + cc_args, + " -Wl,--version-script={} -include {}", + fcntl_map.display(), + fcntl_h.display() + ) + .unwrap(); + } + } + } else if matches!( + triple.environment, + Environment::Musl + | Environment::Muslabi64 + | Environment::Musleabi + | Environment::Musleabihf + ) { + use crate::linux::MUSL_WEAK_SYMBOLS_MAPPING_SCRIPT; use std::fmt::Write as _; let zig_version = Zig::zig_version()?; - if zig_version.major == 0 && zig_version.minor < 11 { - let fcntl_map = zig_linker_dir.join("fcntl.map"); - fs::write(&fcntl_map, FCNTL_MAP)?; - let fcntl_h = zig_linker_dir.join("fcntl.h"); - fs::write(&fcntl_h, FCNTL_H)?; - - write!( - cc_args, - " -Wl,--version-script={} -include {}", - fcntl_map.display(), - fcntl_h.display() - ) - .unwrap(); + let rustc_version = rustc_version::version_meta()?.semver; + + // as zig 0.11.0 is released, its musl has been upgraded to 1.2.4 with break changes + // but rust is still with musl 1.2.3 + // we need this workaround before rust 1.72 + // https://github.com/ziglang/zig/pull/16098 + if is_zig_above_0_11_0(&zig_version) && !is_rust_below_1_72(&rustc_version) { + let weak_symbols_map = zig_linker_dir.join("musl_weak_symbols_map.ld"); + fs::write(&weak_symbols_map, MUSL_WEAK_SYMBOLS_MAPPING_SCRIPT)?; + + write!(cc_args, " -Wl,-T,{}", weak_symbols_map.display()).unwrap() } } }