diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 7285546..0000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -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 diff --git a/Cargo.toml b/Cargo.toml index 7bb9e98..4767899 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,6 @@ thiserror = "2" [build-dependencies] bindgen = "0.72" cmake = "0.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 84abc99..13e0431 100644 --- a/build.rs +++ b/build.rs @@ -5,11 +5,6 @@ use std::path::{Path, PathBuf}; 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}; fn find_static_lib(dir: &Path, base_name: &str, target_is_windows: bool) -> Option { @@ -76,6 +71,46 @@ impl Error { } } +fn restore_importexport(libcziapi_inc: &Path) -> Result<(), Box> { + 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, Box> { + 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> { let toolchain_key = format!( "CMAKE_TOOLCHAIN_FILE_{}", @@ -120,7 +155,14 @@ fn main() -> Result<(), Box> { if env::var("DOCS_RS").is_err() { let host = env::var("HOST")?; 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_macos = target.contains("apple"); @@ -177,6 +219,13 @@ fn main() -> Result<(), Box> { if target.contains("aarch64") { 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> { cmake_config.build_target("libCZIAPIStatic"); } + let _importexport_guard = patch_importexport(&libcziapi_inc)?; let dst = cmake_config.build(); #[cfg(not(feature = "dynamic"))] - let bindings = { - 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, - )?)) - }; + let bindings = bindgen::Builder::default(); #[cfg(feature = "dynamic")] let bindings = bindgen::Builder::default(); @@ -346,106 +381,3 @@ fn main() -> Result<(), Box> { println!("cargo::rerun-if-changed=build.rs"); Ok(()) } - -#[cfg(not(feature = "dynamic"))] -#[derive(Debug)] -struct DeMangler { - map: HashMap, -} - -#[cfg(not(feature = "dynamic"))] -impl DeMangler { - fn new(a_file: PathBuf, use_llvm_nm: bool) -> Result> { - 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 { - // 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"))] -impl bindgen::callbacks::ParseCallbacks for DeMangler { - fn generated_link_name_override(&self, item_info: ItemInfo<'_>) -> Option { - self.map.get(item_info.name).cloned() - } -} diff --git a/src/interop.rs b/src/interop.rs index 91b3e2e..fe24854 100644 --- a/src/interop.rs +++ b/src/interop.rs @@ -1127,6 +1127,7 @@ impl CompositionChannelInfo { pub fn get_look_up_table_element_count(&self) -> i32 { self.0.look_up_table_element_count } + #[allow(clippy::unnecessary_cast)] pub fn get_look_up_table(&self) -> Vec { unsafe { Vec::from_raw_parts(