- replace demangling with never mangling

This commit is contained in:
w.pomp
2026-08-07 10:59:48 +02:00
parent 8c67d8c592
commit a4de4a359f
4 changed files with 58 additions and 183 deletions
-56
View File
@@ -1,56 +0,0 @@
name: Publish
on: [push, pull_request, workflow_call]
permissions:
contents: read
jobs:
crates_io_publish:
name: Publish (crates.io)
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v5
with:
submodules: 'true'
- uses: dtolnay/rust-toolchain@stable
- name: cargo-release Cache
id: cargo_release_cache
uses: actions/cache@v3
with:
path: ~/.cargo/bin/cargo-release
key: ${{ runner.os }}-cargo-release
- run: cargo install cargo-release
if: steps.cargo_release_cache.outputs.cache-hit != 'true'
- name: cargo login
run: cargo login ${{ secrets.CRATES_IO_API_TOKEN }}
# allow-branch HEAD is because GitHub actions switches
# to the tag while building, which is a detached head
# Publishing is currently messy, because:
#
# * `peace_rt_model_core` exports `NativeError` or `WebError` depending on the target.
# * `peace_rt_model_web` fails to build when publishing the workspace for a native target.
# * `peace_rt_model_web` still needs its dependencies to be published before it can be
# published.
# * `peace_rt_model_hack` needs `peace_rt_model_web` to be published before it can be
# published.
#
# We *could* pass through `--no-verify` so `cargo` doesn't build the crate before publishing,
# which is reasonable, since this job only runs after the Linux, Windows, and WASM builds
# have passed.
- name: "cargo release publish"
run: |-
cargo release \
publish \
--workspace \
--all-features \
--allow-branch "main" \
--no-confirm \
--no-verify \
--execute
-2
View File
@@ -22,8 +22,6 @@ thiserror = "2"
[build-dependencies] [build-dependencies]
bindgen = "0.72" bindgen = "0.72"
cmake = "0.1" cmake = "0.1"
cpp_demangle = "0.5"
msvc-demangler = "0.11"
[features] [features]
dynamic = [] dynamic = []
+57 -125
View File
@@ -5,11 +5,6 @@ use std::path::{Path, PathBuf};
use std::fmt::Debug; use std::fmt::Debug;
#[cfg(not(feature = "dynamic"))]
use bindgen::callbacks::ItemInfo;
#[cfg(not(feature = "dynamic"))]
use std::collections::HashMap;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
fn find_static_lib(dir: &Path, base_name: &str, target_is_windows: bool) -> Option<PathBuf> { fn find_static_lib(dir: &Path, base_name: &str, target_is_windows: bool) -> Option<PathBuf> {
@@ -76,6 +71,46 @@ impl Error {
} }
} }
fn restore_importexport(libcziapi_inc: &Path) -> Result<(), Box<dyn std::error::Error>> {
let header = libcziapi_inc.join("importexport.h");
let relative = header.strip_prefix("libczi").unwrap_or(&header);
let status = std::process::Command::new("git")
.args(["checkout", "HEAD", "--", relative.to_str().unwrap()])
.current_dir("libczi")
.status()?;
if !status.success() {
return Err(Error::msg("failed to restore importexport.h"));
}
Ok(())
}
struct ImportExportGuard<'a> {
libcziapi_inc: &'a Path,
}
impl<'a> Drop for ImportExportGuard<'a> {
fn drop(&mut self) {
if let Err(e) = restore_importexport(self.libcziapi_inc) {
eprintln!("warning: failed to restore importexport.h: {e}");
}
}
}
fn patch_importexport(
libcziapi_inc: &Path,
) -> Result<ImportExportGuard<'_>, Box<dyn std::error::Error>> {
let path = libcziapi_inc.join("importexport.h");
let original = std::fs::read_to_string(&path)?;
let patched = original.replace(
"#define EXTERNALLIBCZIAPI_API(_returntype_) _returntype_",
"#define EXTERNALLIBCZIAPI_API(_returntype_) extern \"C\" _returntype_",
);
if patched != original {
std::fs::write(&path, &patched)?;
}
Ok(ImportExportGuard { libcziapi_inc })
}
fn fix_xwin_lib_case() -> Result<(), Box<dyn std::error::Error>> { fn fix_xwin_lib_case() -> Result<(), Box<dyn std::error::Error>> {
let toolchain_key = format!( let toolchain_key = format!(
"CMAKE_TOOLCHAIN_FILE_{}", "CMAKE_TOOLCHAIN_FILE_{}",
@@ -120,7 +155,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if env::var("DOCS_RS").is_err() { if env::var("DOCS_RS").is_err() {
let host = env::var("HOST")?; let host = env::var("HOST")?;
let target = env::var("TARGET")?; let target = env::var("TARGET")?;
let is_cross = host != target; let is_cross = host != target
|| env::var(format!(
"CMAKE_TOOLCHAIN_FILE_{}",
target.replace('-', "_")
))
.is_ok()
|| env::var("TARGET_CMAKE_TOOLCHAIN_FILE").is_ok()
|| env::var("CMAKE_TOOLCHAIN_FILE").is_ok();
let is_windows = target.contains("windows"); let is_windows = target.contains("windows");
let _is_macos = target.contains("apple"); let _is_macos = target.contains("apple");
@@ -177,6 +219,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if target.contains("aarch64") { if target.contains("aarch64") {
cmake_config.define("NEON_INTRINSICS_CAN_BE_USED", "ON"); cmake_config.define("NEON_INTRINSICS_CAN_BE_USED", "ON");
} }
} else {
cmake_config
.define("CRASH_ON_UNALIGNED_ACCESS", "OFF")
.define("_UNALIGNED_ACCESS_RESULT_EXITCODE", "0");
if target.contains("aarch64") {
cmake_config.define("_NEON_INTRINSICS_RESULT_EXITCODE", "0");
}
} }
} }
@@ -184,25 +233,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
cmake_config.build_target("libCZIAPIStatic"); cmake_config.build_target("libCZIAPIStatic");
} }
let _importexport_guard = patch_importexport(&libcziapi_inc)?;
let dst = cmake_config.build(); let dst = cmake_config.build();
#[cfg(not(feature = "dynamic"))] #[cfg(not(feature = "dynamic"))]
let bindings = { let bindings = bindgen::Builder::default();
let libcziapi_search_dirs = [
dst.join("build/Src/libCZIAPI"),
dst.join("Src/libCZIAPI"),
dst.join("lib"),
dst.join("lib64"),
];
let libcziapi_static = libcziapi_search_dirs
.iter()
.find_map(|dir| find_static_lib(dir, "libCZIAPIStatic", is_windows))
.ok_or(Error::msg("cannot find libCZIAPIStatic library"))?;
bindgen::Builder::default().parse_callbacks(Box::new(DeMangler::new(
libcziapi_static,
is_cross && is_windows,
)?))
};
#[cfg(feature = "dynamic")] #[cfg(feature = "dynamic")]
let bindings = bindgen::Builder::default(); let bindings = bindgen::Builder::default();
@@ -346,106 +381,3 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo::rerun-if-changed=build.rs"); println!("cargo::rerun-if-changed=build.rs");
Ok(()) Ok(())
} }
#[cfg(not(feature = "dynamic"))]
#[derive(Debug)]
struct DeMangler {
map: HashMap<String, String>,
}
#[cfg(not(feature = "dynamic"))]
impl DeMangler {
fn new(a_file: PathBuf, use_llvm_nm: bool) -> Result<Self, Box<dyn std::error::Error>> {
let nm_cmd = if use_llvm_nm { "llvm-nm" } else { "nm" };
let cmd = std::process::Command::new(nm_cmd)
.arg("--defined-only")
.arg(&a_file)
.output()?;
let mut map = HashMap::new();
for line in std::str::from_utf8(&cmd.stdout)?.lines() {
let line = line.trim();
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"))]
impl bindgen::callbacks::ParseCallbacks for DeMangler {
fn generated_link_name_override(&self, item_info: ItemInfo<'_>) -> Option<String> {
self.map.get(item_info.name).cloned()
}
}
+1
View File
@@ -1127,6 +1127,7 @@ impl CompositionChannelInfo {
pub fn get_look_up_table_element_count(&self) -> i32 { pub fn get_look_up_table_element_count(&self) -> i32 {
self.0.look_up_table_element_count self.0.look_up_table_element_count
} }
#[allow(clippy::unnecessary_cast)]
pub fn get_look_up_table(&self) -> Vec<u8> { pub fn get_look_up_table(&self) -> Vec<u8> {
unsafe { unsafe {
Vec::from_raw_parts( Vec::from_raw_parts(