From 9eefa1016d73ffd978964f2a7ff69ca1052dca9a Mon Sep 17 00:00:00 2001 From: "w.pomp" Date: Tue, 14 Jul 2026 18:10:43 +0200 Subject: [PATCH] - cross-compilation to macOS --- Cargo.toml | 3 +- build.rs | 168 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 107 insertions(+), 64 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 00c4476..7bb9e98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,8 @@ thiserror = "2" [build-dependencies] bindgen = "0.72" cmake = "0.1" -regex = "1" +cpp_demangle = "0.5" +msvc-demangler = "0.11" [features] dynamic = [] \ No newline at end of file diff --git a/build.rs b/build.rs index f0c14ff..525f195 100644 --- a/build.rs +++ b/build.rs @@ -8,8 +8,6 @@ use std::fmt::Debug; #[cfg(not(feature = "dynamic"))] use bindgen::callbacks::ItemInfo; -#[cfg(not(feature = "dynamic"))] -use regex::Regex; #[cfg(not(feature = "dynamic"))] use std::collections::HashMap; use std::fmt::{Display, Formatter}; @@ -42,7 +40,9 @@ fn lib_name_from_path(lib_path: &Path) -> Result Result<(), Box> { .define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_RAPIDJSON", "OFF") .define("LIBCZI_BUILD_LIBCZIAPI", "ON"); - if is_cross && is_windows { - cmake_config - .define("CMAKE_SYSTEM_NAME", "Windows") - .define("CRASH_ON_UNALIGNED_ACCESS", "FALSE") - .define("ADDITIONAL_LIBS_REQUIRED_FOR_ATOMIC", ""); - - let has_toolchain_file = env::var("TARGET_CMAKE_TOOLCHAIN_FILE").is_ok() - || env::var(format!( - "CMAKE_TOOLCHAIN_FILE_{}", - target.replace('-', "_") - )) - .is_ok() - || env::var("CMAKE_TOOLCHAIN_FILE").is_ok(); - - if !has_toolchain_file { + if is_cross { + if is_windows { cmake_config - .define("CMAKE_C_COMPILER", "clang") - .define("CMAKE_CXX_COMPILER", "clang++") - .define("CMAKE_RC_COMPILER", "llvm-rc"); - } + .define("CMAKE_SYSTEM_NAME", "Windows") + .define("CRASH_ON_UNALIGNED_ACCESS", "FALSE") + .define("ADDITIONAL_LIBS_REQUIRED_FOR_ATOMIC", ""); - fix_xwin_lib_case()?; + let has_toolchain_file = env::var("TARGET_CMAKE_TOOLCHAIN_FILE").is_ok() + || env::var(format!( + "CMAKE_TOOLCHAIN_FILE_{}", + target.replace('-', "_") + )) + .is_ok() + || env::var("CMAKE_TOOLCHAIN_FILE").is_ok(); + + if !has_toolchain_file { + cmake_config + .define("CMAKE_C_COMPILER", "clang") + .define("CMAKE_CXX_COMPILER", "clang++") + .define("CMAKE_RC_COMPILER", "llvm-rc"); + } + + fix_xwin_lib_case()?; + } else if target.contains("apple") { + cmake_config + .define("CMAKE_SYSTEM_NAME", "Darwin") + .define("ADDITIONAL_LIBS_REQUIRED_FOR_ATOMIC", "") + .define("CRASH_ON_UNALIGNED_ACCESS", "OFF"); + if target.contains("aarch64") { + cmake_config.define("NEON_INTRINSICS_CAN_BE_USED", "ON"); + } + } } if is_cross && is_windows { @@ -340,54 +350,86 @@ impl DeMangler { .arg("--defined-only") .arg(&a_file) .output()?; - let itanium_pat = Regex::new(r"^[\da-f]*\s[A-Z]\s(.*_Z(\d+)(libCZI_.*))$")?; - let msvc_pat = Regex::new(r"^[\da-f]*\s[TDB]\s(\?(libCZI_\w+)@@.*)$")?; let mut map = HashMap::new(); for line in std::str::from_utf8(&cmd.stdout)?.lines() { let line = line.trim(); - if let Some(caps) = itanium_pat.captures(line) { - if let (Some(symbol), Some(n), Some(name)) = (caps.get(1), caps.get(2), caps.get(3)) - { - let n: usize = n.as_str().parse()?; - let name = name.as_str(); - let demangled = name[..n].to_string(); - let mangled = symbol.as_str().to_string(); - if let Some(existing_mangled) = map.get(&demangled) { - if existing_mangled != &mangled { - return Err(Error::msg(format!( - "conflicting mangled symbols for {} in {}: {}, {}", - demangled, - a_file.to_string_lossy(), - existing_mangled, - mangled - ))); - } - } else { - map.insert(demangled, mangled); - } - } - } else if let Some(caps) = msvc_pat.captures(line) { - let mangled = caps.get(1).unwrap().as_str().to_string(); - if let Some(name_match) = caps.get(2) { - let demangled = name_match.as_str().to_string(); - if let Some(existing_mangled) = map.get(&demangled) { - if existing_mangled != &mangled { - return Err(Error::msg(format!( - "conflicting mangled symbols for {} in {}: {}, {}", - demangled, - a_file.to_string_lossy(), - existing_mangled, - mangled - ))); - } - } else { - map.insert(demangled, mangled); - } + let mangled = if let Some(sym) = line.split_whitespace().last() { + sym + } else { + continue; + }; + let plain_name = Self::demangle(mangled); + if let Some(name) = plain_name { + if name.starts_with("libCZI_") { + Self::insert_mapping(&mut map, &name, mangled, &a_file)?; } } } Ok(Self { map }) } + + fn demangle(symbol: &str) -> Option { + // Only demangle actual function symbols, not catch/dtor/cppxdata metadata + if let Some(rest) = symbol.strip_prefix('?') { + // MSVC: real functions start with "libCZI_", not "catch$", "dtor$", etc. + if !rest.starts_with("libCZI_") { + return None; + } + let flags = msvc_demangler::DemangleFlags::llvm(); + let demangled = msvc_demangler::demangle(symbol, flags).ok()?; + Self::extract_msvc_name(&demangled) + } else if symbol.starts_with("_Z") { + // Itanium: demangle and extract the function name + let sym = cpp_demangle::Symbol::new(symbol.as_bytes()).ok()?; + let demangled = sym.demangle().ok()?; + // e.g. "libCZI_Foo(int, bool)" -> "libCZI_Foo" + // e.g. "ns::libCZI_Foo(int)" -> "libCZI_Foo" + demangled.split('(').next().and_then(|s| { + let s = s.trim(); + if let Some(name) = s.rsplit("::").next() { + Some(name.to_string()) + } else { + Some(s.to_string()) + } + }) + } else { + None + } + } + + fn extract_msvc_name(demangled: &str) -> Option { + // Find the identifier that looks like a function name. + // MSVC demangled output: "return_type calling_conv name(params)" + for word in demangled.split_whitespace() { + if let Some(rest) = word.strip_prefix("libCZI_") { + let name = format!("libCZI_{}", rest.split('(').next().unwrap_or(rest)); + return Some(name); + } + } + None + } + + fn insert_mapping( + map: &mut HashMap, + demangled: &str, + mangled: &str, + a_file: &Path, + ) -> Result<(), Box> { + if let Some(existing_mangled) = map.get(demangled) { + if existing_mangled != mangled { + return Err(Error::msg(format!( + "conflicting mangled symbols for {} in {}: {}, {}", + demangled, + a_file.to_string_lossy(), + existing_mangled, + mangled + ))); + } + } else { + map.insert(demangled.to_string(), mangled.to_string()); + } + Ok(()) + } } #[cfg(not(feature = "dynamic"))]