This commit is contained in:
+2
-1
@@ -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 = []
|
||||
@@ -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<String, Box<dyn std::error::Err
|
||||
.ok_or(Error::msg("cannot get file stem"))?
|
||||
.to_str()
|
||||
.ok_or(Error::msg("cannot into string"))?;
|
||||
Ok(file_name.to_string())
|
||||
// cargo::rustc-link-lib=static=NAME tells the linker to find libNAME.a / NAME.lib,
|
||||
// so strip any leading "lib" prefix to avoid liblibNAME.
|
||||
Ok(file_name.strip_prefix("lib").unwrap_or(file_name).to_string())
|
||||
}
|
||||
|
||||
struct Error(String);
|
||||
@@ -135,28 +135,38 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.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<String> {
|
||||
// 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<String> {
|
||||
// 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<String, String>,
|
||||
demangled: &str,
|
||||
mangled: &str,
|
||||
a_file: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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"))]
|
||||
|
||||
Reference in New Issue
Block a user