This commit is contained in:
+2
-1
@@ -22,7 +22,8 @@ thiserror = "2"
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.72"
|
bindgen = "0.72"
|
||||||
cmake = "0.1"
|
cmake = "0.1"
|
||||||
regex = "1"
|
cpp_demangle = "0.5"
|
||||||
|
msvc-demangler = "0.11"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
dynamic = []
|
dynamic = []
|
||||||
@@ -8,8 +8,6 @@ use std::fmt::Debug;
|
|||||||
#[cfg(not(feature = "dynamic"))]
|
#[cfg(not(feature = "dynamic"))]
|
||||||
use bindgen::callbacks::ItemInfo;
|
use bindgen::callbacks::ItemInfo;
|
||||||
|
|
||||||
#[cfg(not(feature = "dynamic"))]
|
|
||||||
use regex::Regex;
|
|
||||||
#[cfg(not(feature = "dynamic"))]
|
#[cfg(not(feature = "dynamic"))]
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{Display, Formatter};
|
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"))?
|
.ok_or(Error::msg("cannot get file stem"))?
|
||||||
.to_str()
|
.to_str()
|
||||||
.ok_or(Error::msg("cannot into string"))?;
|
.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);
|
struct Error(String);
|
||||||
@@ -135,7 +135,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_RAPIDJSON", "OFF")
|
.define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_RAPIDJSON", "OFF")
|
||||||
.define("LIBCZI_BUILD_LIBCZIAPI", "ON");
|
.define("LIBCZI_BUILD_LIBCZIAPI", "ON");
|
||||||
|
|
||||||
if is_cross && is_windows {
|
if is_cross {
|
||||||
|
if is_windows {
|
||||||
cmake_config
|
cmake_config
|
||||||
.define("CMAKE_SYSTEM_NAME", "Windows")
|
.define("CMAKE_SYSTEM_NAME", "Windows")
|
||||||
.define("CRASH_ON_UNALIGNED_ACCESS", "FALSE")
|
.define("CRASH_ON_UNALIGNED_ACCESS", "FALSE")
|
||||||
@@ -157,6 +158,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fix_xwin_lib_case()?;
|
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 {
|
if is_cross && is_windows {
|
||||||
@@ -340,54 +350,86 @@ impl DeMangler {
|
|||||||
.arg("--defined-only")
|
.arg("--defined-only")
|
||||||
.arg(&a_file)
|
.arg(&a_file)
|
||||||
.output()?;
|
.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();
|
let mut map = HashMap::new();
|
||||||
for line in std::str::from_utf8(&cmd.stdout)?.lines() {
|
for line in std::str::from_utf8(&cmd.stdout)?.lines() {
|
||||||
let line = line.trim();
|
let line = line.trim();
|
||||||
if let Some(caps) = itanium_pat.captures(line) {
|
let mangled = if let Some(sym) = line.split_whitespace().last() {
|
||||||
if let (Some(symbol), Some(n), Some(name)) = (caps.get(1), caps.get(2), caps.get(3))
|
sym
|
||||||
{
|
|
||||||
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 {
|
} else {
|
||||||
map.insert(demangled, mangled);
|
continue;
|
||||||
}
|
};
|
||||||
}
|
let plain_name = Self::demangle(mangled);
|
||||||
} else if let Some(caps) = msvc_pat.captures(line) {
|
if let Some(name) = plain_name {
|
||||||
let mangled = caps.get(1).unwrap().as_str().to_string();
|
if name.starts_with("libCZI_") {
|
||||||
if let Some(name_match) = caps.get(2) {
|
Self::insert_mapping(&mut map, &name, mangled, &a_file)?;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Self { map })
|
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"))]
|
#[cfg(not(feature = "dynamic"))]
|
||||||
|
|||||||
Reference in New Issue
Block a user