From a34d4a692062849318dc7dd3e532e49b5c86b16f Mon Sep 17 00:00:00 2001 From: noname <156155219+zxcloli666@users.noreply.github.com> Date: Thu, 2 Jul 2026 00:37:02 +0500 Subject: [PATCH 1/5] fix(libhermes-sys): use Config::generator("Ninja") instead of raw configure_arg cmake-rs only recognizes Ninja through its own generator field; on MSVC targets it otherwise assumes a Visual Studio generator and appends -Thost=x64 -Ax64, which conflicts with a Ninja generator passed as a raw configure_arg ("Generator Ninja does not support platform specification"). --- libhermes-sys/build.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libhermes-sys/build.rs b/libhermes-sys/build.rs index eb0407b..4aaf102 100644 --- a/libhermes-sys/build.rs +++ b/libhermes-sys/build.rs @@ -14,9 +14,16 @@ fn main() { // Build Hermes via cmake, targeting hermesvm_a (static VM with compiler). // All libraries are built as static archives. + // + // `.generator()` (not `.configure_arg("-G Ninja")`) — the `cmake` crate + // only recognizes a Ninja generator through its own `generator` field: on + // MSVC targets it otherwise assumes a Visual Studio generator and appends + // `-Thost=x64 -Ax64`, which conflicts with a Ninja generator supplied as + // a raw configure arg ("Generator Ninja does not support platform + // specification"). See cmake-rs's `Config::build()` generator handling. let hermes_build = Config::new(hermes_src_dir) .build_target("hermesvm_a") - .configure_arg("-G Ninja") + .generator("Ninja") .define("HERMES_ENABLE_EH_RTTI", "ON") .define("BUILD_SHARED_LIBS", "OFF") .define("HERMES_BUILD_SHARED_JSI", "OFF") From 80d19901d444691657f2d8f3e2f6992dcb16e375 Mon Sep 17 00:00:00 2001 From: noname <156155219+zxcloli666@users.noreply.github.com> Date: Thu, 2 Jul 2026 01:01:26 +0500 Subject: [PATCH 2/5] fix(libhermes-sys): probe C++17/exceptions/RTTI flags per-compiler for binding.cc .flag() passes GCC/Clang spellings (-std=c++17, -fexceptions, -frtti) straight through; cl.exe silently ignores unrecognized "-"-prefixed args instead of erroring, so binding.cc compiled in a pre-C++17 mode under MSVC and failed on structured bindings. flag_if_supported() probes the actual compiler and applies whichever spelling (GCC/Clang or MSVC) it accepts. --- libhermes-sys/build.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libhermes-sys/build.rs b/libhermes-sys/build.rs index 4aaf102..3a31c87 100644 --- a/libhermes-sys/build.rs +++ b/libhermes-sys/build.rs @@ -43,9 +43,18 @@ fn main() { .include(hermes_src.join("API/jsi")) .include(hermes_src.join("public")) .include("src") - .flag("-std=c++17") - .flag("-fexceptions") - .flag("-frtti") + // `.flag()` passes these through verbatim, so the GCC/Clang spellings + // silently do nothing under MSVC (cl.exe warns and ignores unknown + // "-"-prefixed args instead of erroring) — binding.cc then compiles + // in whatever pre-C++17 mode cl.exe defaults to, and fails on + // structured bindings. `flag_if_supported` probes each spelling + // against the actual compiler in use, so both sides get a real flag. + .flag_if_supported("-std=c++17") + .flag_if_supported("/std:c++17") + .flag_if_supported("-fexceptions") + .flag_if_supported("/EHsc") + .flag_if_supported("-frtti") + .flag_if_supported("/GR") .compile("hermes_binding"); // Discover and link all static libraries produced by the Hermes build. From 1dc16df0f85d05555e7c5c5fc8184f0deac13fce Mon Sep 17 00:00:00 2001 From: noname <156155219+zxcloli666@users.noreply.github.com> Date: Thu, 2 Jul 2026 01:18:22 +0500 Subject: [PATCH 3/5] fix(libhermes-sys): discover .lib archives and drop Unix-only system libs on Windows Two compounding bugs in the same linking step, the first masking the second: (1) the static-archive discovery walk only matched "*.a" files, so on MSVC (which produces "*.lib") it silently linked none of Hermes' own built libraries at all; (2) the system-library fallback branch unconditionally added "stdc++"/"icuuc"/"icui18n"/"icudata", which don't exist under those names on Windows and made the linker fail before ever reaching a symbol-resolution error that would have surfaced bug (1). --- libhermes-sys/build.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/libhermes-sys/build.rs b/libhermes-sys/build.rs index 3a31c87..d33f965 100644 --- a/libhermes-sys/build.rs +++ b/libhermes-sys/build.rs @@ -59,20 +59,26 @@ fn main() { // Discover and link all static libraries produced by the Hermes build. // Static archives don't embed transitive dependencies, so we need to link - // every .a file that CMake produced (the linker discards unused symbols). + // every archive CMake produced (the linker discards unused symbols). + // MSVC's static-library archives are named "*.lib", not "*.a" — a + // Windows build previously found none at all here (no hard error from + // that alone: it only surfaces once the linker fails to resolve Hermes' + // own symbols, downstream of other errors that used to mask it). + let lib_ext = if cfg!(target_os = "windows") { "lib" } else { "a" }; let build_path = PathBuf::from(&hermes_build_dir); let mut search_dirs = HashSet::new(); for entry in walkdir(&build_path) { if let Some(ext) = entry.extension() { - if ext == "a" { + if ext == lib_ext { let dir = entry.parent().unwrap(); if search_dirs.insert(dir.to_path_buf()) { println!("cargo:rustc-link-search=native={}", dir.display()); } - // Strip the "lib" prefix and ".a" suffix to get the link name. + // Strip the "lib" prefix (POSIX archives only — MSVC .lib + // files aren't prefixed) and extension to get the link name. let stem = entry.file_stem().unwrap().to_str().unwrap(); - let name = stem.strip_prefix("lib").unwrap_or(stem); + let name = if cfg!(target_os = "windows") { stem } else { stem.strip_prefix("lib").unwrap_or(stem) }; println!("cargo:rustc-link-lib=static={}", name); } } @@ -83,13 +89,18 @@ fn main() { println!("cargo:rustc-link-lib=c++"); // Hermes's Unicode support (PlatformUnicodeCF) uses CoreFoundation. println!("cargo:rustc-link-lib=framework=CoreFoundation"); - } else { + } else if cfg!(target_os = "linux") { println!("cargo:rustc-link-lib=stdc++"); // Hermes's Unicode support (PlatformUnicodeICU) uses ICU on Linux. println!("cargo:rustc-link-lib=icuuc"); println!("cargo:rustc-link-lib=icui18n"); println!("cargo:rustc-link-lib=icudata"); } + // Windows: MSVC's own C++ runtime is linked automatically (no "stdc++" + // by that name exists there), and CMake reported "Using Windows 10 + // built-in ICU" — Hermes' own Windows Unicode shim is just another + // static archive the walk above already discovers and links, not a + // separate system library to name here. } /// Recursively walk a directory and yield all file paths. From 60877481ee514d2bce41aad28857a060faf5bb3d Mon Sep 17 00:00:00 2001 From: noname <156155219+zxcloli666@users.noreply.github.com> Date: Thu, 2 Jul 2026 01:41:24 +0500 Subject: [PATCH 4/5] fix(libhermes-sys): force vendored Hermes build to CMAKE_BUILD_TYPE=Release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cmake-rs infers CMAKE_BUILD_TYPE from cargo's own profile ("Debug" for a plain cargo build). Under MSVC that pulls in CMake's default /MDd (debug CRT) flags for Hermes' object files, while Rust's linked output always expects the release CRT (/MD) regardless of --release — the mismatch surfaces as dozens of unresolved __imp__calloc_dbg (and other debug-CRT symbols) at final link. Force Release unconditionally: a vendored C++ VM built unoptimized to match our own dev profile buys nothing (we never edit it) and would just be slower to run. --- libhermes-sys/build.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libhermes-sys/build.rs b/libhermes-sys/build.rs index d33f965..45b7fd1 100644 --- a/libhermes-sys/build.rs +++ b/libhermes-sys/build.rs @@ -24,6 +24,17 @@ fn main() { let hermes_build = Config::new(hermes_src_dir) .build_target("hermesvm_a") .generator("Ninja") + // Without this, `cmake`-rs infers CMAKE_BUILD_TYPE from Cargo's own + // profile — "Debug" for a plain `cargo build`. On MSVC that pulls in + // CMake's default `/MDd` (debug CRT) flags for Hermes' own object + // files, while Rust's linked output always expects the release CRT + // (`/MD`) regardless of `--release` — the mismatch surfaces as + // dozens of "unresolved external symbol __imp__calloc_dbg" (and + // other debug-CRT-only symbols) at final link. Building the vendored + // Hermes in Release always sidesteps it, on every platform — a + // vendored C++ VM built unoptimized to match our own dev profile + // buys nothing (we never edit it) and would just make it slower. + .profile("Release") .define("HERMES_ENABLE_EH_RTTI", "ON") .define("BUILD_SHARED_LIBS", "OFF") .define("HERMES_BUILD_SHARED_JSI", "OFF") From 128c69e6da94c7dac8c47e72f563c780b7f62569 Mon Sep 17 00:00:00 2001 From: noname <156155219+zxcloli666@users.noreply.github.com> Date: Thu, 2 Jul 2026 02:03:04 +0500 Subject: [PATCH 5/5] fix(libhermes-sys): link Windows' icu.lib and winmm.lib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CMake reporting "Using Windows 10 built-in ICU" only means PlatformUnicodeICU.cpp calls the same unorm2_*/ucol_*/udat_*/u_str* symbols ICU4C exposes, backed by the OS's icu.dll instead of a vendored ICU — it doesn't embed that linkage into hermesvm_a.lib, and Windows' import library is named "icu", not "icuuc"/"icui18n"/"icudata" (those are POSIX ICU4C names). SamplingProfilerSampler.cpp's high-res timer also needs winmm's timeBeginPeriod/timeEndPeriod. --- libhermes-sys/build.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/libhermes-sys/build.rs b/libhermes-sys/build.rs index 45b7fd1..e7f9653 100644 --- a/libhermes-sys/build.rs +++ b/libhermes-sys/build.rs @@ -108,10 +108,18 @@ fn main() { println!("cargo:rustc-link-lib=icudata"); } // Windows: MSVC's own C++ runtime is linked automatically (no "stdc++" - // by that name exists there), and CMake reported "Using Windows 10 - // built-in ICU" — Hermes' own Windows Unicode shim is just another - // static archive the walk above already discovers and links, not a - // separate system library to name here. + // by that name exists there). CMake reporting "Using Windows 10 + // built-in ICU" only means Hermes' PlatformUnicodeICU.cpp calls the + // same unorm2_*/ucol_*/udat_*/u_str* entry points ICU4C exposes, + // backed by the OS's own icu.dll instead of a vendored ICU — it does + // NOT embed that linkage into hermesvm_a.lib for us; still our job as + // the consumer, just under Windows' own import-library name ("icu", + // not "icuuc"/"icui18n"/"icudata"). SamplingProfilerSampler.cpp's + // high-res timer needs winmm's timeBeginPeriod/timeEndPeriod too. + if cfg!(target_os = "windows") { + println!("cargo:rustc-link-lib=icu"); + println!("cargo:rustc-link-lib=winmm"); + } } /// Recursively walk a directory and yield all file paths.