Merge PR #8443: fix(natives): static-link win32 MSVC CRT so addon needs no VC++ redist (@roboomp)
This commit is contained in:
+14
-1
@@ -16,19 +16,32 @@ _ADDON_RUSTC_FLAGS = [
|
||||
]
|
||||
|
||||
def _addon_transition_impl(settings, attr):
|
||||
# Statically link the MSVC CRT for the shipped win32 addon: rustc gets
|
||||
# +crt-static via the crate's rustc_flags select, and the C dependencies
|
||||
# (opus/cmake, tree-sitter, blake3, ring) must move to /MT in lock-step so
|
||||
# the final .node imports no VCRUNTIME140.dll from the Visual C++
|
||||
# Redistributable (absent on a clean Windows install -> dlopen error 126).
|
||||
# The static_link_msvcrt cc feature flips the toolchain compile flags that
|
||||
# rules_rust forwards to cc-rs/cmake as CFLAGS/CXXFLAGS; it is inert for the
|
||||
# zig/darwin toolchains, so scoping it to win32 is belt-and-suspenders.
|
||||
features = list(settings["//command_line_option:features"])
|
||||
if "win32" in str(attr.platform):
|
||||
features = features + ["static_link_msvcrt"]
|
||||
return {
|
||||
"//command_line_option:platforms": str(attr.platform),
|
||||
"//command_line_option:compilation_mode": "opt",
|
||||
"//command_line_option:features": features,
|
||||
"@rules_rust//rust/settings:lto": "thin",
|
||||
"@rules_rust//rust/settings:extra_rustc_flags": _ADDON_RUSTC_FLAGS,
|
||||
}
|
||||
|
||||
_addon_transition = transition(
|
||||
implementation = _addon_transition_impl,
|
||||
inputs = [],
|
||||
inputs = ["//command_line_option:features"],
|
||||
outputs = [
|
||||
"//command_line_option:platforms",
|
||||
"//command_line_option:compilation_mode",
|
||||
"//command_line_option:features",
|
||||
"@rules_rust//rust/settings:lto",
|
||||
"@rules_rust//rust/settings:extra_rustc_flags",
|
||||
],
|
||||
|
||||
@@ -22,9 +22,16 @@ exec hosts. Replaces cargo-xwin.
|
||||
work from Bazel actions (cwd = execroot) *and* from build scripts, where
|
||||
rules_rust `${pwd}`-expands `CC`/`AR` to absolute paths and cc-rs/cmake spawn
|
||||
tools from other cwds.
|
||||
- **CRT: dynamic `/MD`** (rules_cc's msvc branch default outside `dbg` without
|
||||
the `static_link_msvcrt` feature) — matches what napi/cc-rs produced under
|
||||
cargo-xwin (rust msvc targets default to dynamic CRT without `+crt-static`).
|
||||
- **CRT: static `/MT` for the shipped addon.** The toolchain *default* is
|
||||
dynamic `/MD` (rules_cc's msvc branch default outside `dbg` without the
|
||||
`static_link_msvcrt` feature), matching what napi/cc-rs produced under
|
||||
cargo-xwin. But `//:natives-win32-x64-baseline` overrides to static CRT:
|
||||
`-Ctarget-feature=+crt-static` for rustc (crate BUILD select) plus the
|
||||
`static_link_msvcrt` cc feature (enabled for win32 in the `native_addon`
|
||||
transition, `bazel/defs.bzl`) so the C deps compile `/MT` in lock-step.
|
||||
Without this the `.node` imports `VCRUNTIME140.dll` from the Visual C++
|
||||
Redistributable, which is absent on a clean Windows install and makes the
|
||||
loader's dlopen fail with error 126 (issue #8439).
|
||||
- **SSE floor in the wrapper, not annotations**: `-msse4.1 -msse4.2` live in the
|
||||
clang-cl wrapper, which only ever targets win32-x64 (baseline = x86-64-v2 ⊇
|
||||
SSE4.2). This is the old build-native.ts CFLAGS hack, windows-only by
|
||||
@@ -95,7 +102,8 @@ exec hosts. Replaces cargo-xwin.
|
||||
defaults to the Debug config → `/MDd` → `msvcrtd.lib`, which the lean splat
|
||||
(like cargo-xwin's) does not carry; toolchain.cmake pins
|
||||
`CMAKE_TRY_COMPILE_CONFIGURATION=Release`, `CMAKE_POLICY_DEFAULT_CMP0091=NEW`
|
||||
and `CMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL` (/MD everywhere).
|
||||
and `CMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded` (static release `/MT`
|
||||
everywhere, matching the addon's static-CRT policy — issue #8439).
|
||||
Verified on darwin: scratch `project(C)` + `add_executable` configures with
|
||||
"Clang 20.1.7 with MSVC-like command-line" and links a valid PE32+ exe
|
||||
through vs_link_exe with the wrapper rc/mt/linker.
|
||||
@@ -103,8 +111,9 @@ exec hosts. Replaces cargo-xwin.
|
||||
## What to verify on can.internal (linux-x64)
|
||||
|
||||
1. `bazel build //:natives-win32-x64-baseline` end-to-end link; check the
|
||||
produced `pi_natives.win32-x64-baseline.node` imports (dumpbin/llvm-readobj:
|
||||
expect VCRUNTIME140/api-ms-win-crt-* → `/MD`, no static CRT).
|
||||
produced `pi_natives.win32-x64-baseline.node` imports (dumpbin/llvm-readobj):
|
||||
expect **no** `VCRUNTIME140.dll` and **no** `api-ms-win-crt-*` (static CRT);
|
||||
only core Windows system DLLs (kernel32, ntdll, advapi32, …) should remain.
|
||||
2. LLVM 20.1.7 Linux-X64 binaries are built on a newish Ubuntu: confirm the
|
||||
kata runner image's glibc is ≥ 2.35-ish and has `libtinfo6`/`libstdc++6`
|
||||
(usual LLVM release-binary runtime deps).
|
||||
|
||||
@@ -124,15 +124,20 @@ set(CMAKE_CXX_COMPILER "${CMAKE_CURRENT_LIST_DIR}/bin/clang-cl")
|
||||
set(CMAKE_LINKER "${CMAKE_CURRENT_LIST_DIR}/bin/lld-link")
|
||||
set(CMAKE_RC_COMPILER "${CMAKE_CURRENT_LIST_DIR}/bin/llvm-rc")
|
||||
set(CMAKE_MT "${CMAKE_CURRENT_LIST_DIR}/bin/llvm-mt")
|
||||
# The xwin splat carries release CRT import libs only (msvcrt.lib, no
|
||||
# msvcrtd.lib — same as cargo-xwin). try_compile defaults to the Debug
|
||||
# configuration, whose /MDd would demand the debug CRT; pin try_compile to
|
||||
# Release and the runtime library to dynamic release /MD for every config
|
||||
# (CMP0091 NEW makes CMAKE_MSVC_RUNTIME_LIBRARY authoritative even for
|
||||
# projects with ancient cmake_minimum_required, e.g. bundled opus).
|
||||
# The xwin splat carries release CRT import + static libs only (msvcrt.lib /
|
||||
# libcmt.lib, no debug msvcrtd.lib / libcmtd.lib — same as cargo-xwin).
|
||||
# try_compile defaults to the Debug configuration, whose debug CRT the splat
|
||||
# lacks; pin try_compile to Release. The shipped win32 addon statically links
|
||||
# the CRT (rustc +crt-static + the static_link_msvcrt cc feature; see
|
||||
# bazel/defs.bzl and crates/pi-natives/BUILD.bazel), so pin the runtime library
|
||||
# to the static release CRT /MT for every config as well — otherwise CMake's
|
||||
# authoritative CMAKE_MSVC_RUNTIME_LIBRARY (CMP0091 NEW) would emit /MD for the
|
||||
# bundled opus objects, which then import VCRUNTIME140.dll and conflict with the
|
||||
# static CRT the rest of the addon links (issue #8439). Keep this in lock-step
|
||||
# with the static_link_msvcrt feature: both must select the static CRT together.
|
||||
set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0091 NEW)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
|
||||
"""
|
||||
|
||||
_BUILD = """\
|
||||
|
||||
@@ -40,6 +40,13 @@ rust_shared_library(
|
||||
# cdylib at all; napi musl addons have always linked the dynamic CRT.
|
||||
"//bazel/triples:x86_64-unknown-linux-musl": ["-Ctarget-feature=-crt-static"],
|
||||
"//bazel/triples:aarch64-unknown-linux-musl": ["-Ctarget-feature=-crt-static"],
|
||||
# Statically link the MSVC CRT so the shipped .node does not import
|
||||
# VCRUNTIME140.dll from the Visual C++ Redistributable, which is absent
|
||||
# on a clean Windows install and makes the loader's dlopen fail with
|
||||
# "The specified module could not be found" (error 126). The C deps are
|
||||
# switched to /MT in lock-step via the static_link_msvcrt cc feature in
|
||||
# the native_addon transition (bazel/defs.bzl).
|
||||
"//bazel/triples:x86_64-pc-windows-msvc": ["-Ctarget-feature=+crt-static"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
version = "17.1.5",
|
||||
|
||||
@@ -64,7 +64,7 @@ Notes:
|
||||
|
||||
This mirrors the old cargo `ci` profile. Because the profile lives **in the transition**, a bare `bazel build //:natives-<t>` is always release-grade regardless of `-c`, and every addon shares one cache entry per (platform, source) pair. The rule then symlinks the produced shared library to the loader's canonical `pi_natives.<platform>-<arch>[-<variant>].node` name, scoped under the rule name (`bazel-bin/natives-<t>/…`) so gnu/musl outputs with identical basenames cannot collide at the package level.
|
||||
|
||||
Per-target codegen that is not part of the transition lives in `crates/pi-natives/BUILD.bazel` `rustc_flags` selects: `-Ctarget-cpu=x86-64-v2` (baseline) / `x86-64-v3` (modern) via `//bazel/variants`, the napi link args (`-Wl,-undefined,dynamic_lookup` on macOS, `-Wl,-z,nodelete` on linux — `build.rs`/`napi_build::setup()` is deliberately not wired in), and `-Ctarget-feature=-crt-static` for musl.
|
||||
Per-target codegen that is not part of the transition lives in `crates/pi-natives/BUILD.bazel` `rustc_flags` selects: `-Ctarget-cpu=x86-64-v2` (baseline) / `x86-64-v3` (modern) via `//bazel/variants`, the napi link args (`-Wl,-undefined,dynamic_lookup` on macOS, `-Wl,-z,nodelete` on linux — `build.rs`/`napi_build::setup()` is deliberately not wired in), `-Ctarget-feature=-crt-static` for musl, and `-Ctarget-feature=+crt-static` for win32-x64 msvc (paired with the `static_link_msvcrt` cc feature enabled in the `native_addon` transition so the C deps compile `/MT` in lock-step — the shipped `.node` then imports no `VCRUNTIME140.dll` from the VC++ Redistributable).
|
||||
|
||||
### 3) Platforms and toolchains
|
||||
|
||||
@@ -73,7 +73,7 @@ Per-target codegen that is not part of the transition lives in `crates/pi-native
|
||||
| linux gnu (x64/arm64) | `@zig_sdk//libc_aware/toolchain:linux_*_gnu.2.17` (hermetic zig cc) | glibc **2.17** portability floor — same floor the previous cross builds used |
|
||||
| linux musl (x64/arm64) | `@zig_sdk//libc_aware/toolchain:linux_*_musl` | dynamic CRT (`-Ctarget-feature=-crt-static` in the crate BUILD) |
|
||||
| darwin (x64/arm64) | host Xcode toolchain | Apple frameworks aren't redistributable; darwin addons build on mac hosts only |
|
||||
| win32-x64 msvc | `//bazel/toolchains/msvc` (`@msvc_cc`): clang-cl + lld-link + xwin CRT/SDK | hermetic cross-link from linux-x64 CI pods and darwin dev hosts; see `bazel/toolchains/msvc/NOTES.md` |
|
||||
| win32-x64 msvc | `//bazel/toolchains/msvc` (`@msvc_cc`): clang-cl + lld-link + xwin CRT/SDK | hermetic cross-link from linux-x64 CI pods and darwin dev hosts; **static CRT** (`+crt-static` + `static_link_msvcrt`) so the addon needs no VC++ Redistributable; see `bazel/toolchains/msvc/NOTES.md` |
|
||||
|
||||
Rust toolchains are nightly (pinned in `MODULE.bazel`), with repo-local musl re-registrations in `//bazel/toolchains` carrying an explicit `@zig_sdk//libc:musl` constraint (rules_rust's generated gnu and musl toolchains otherwise share (os, cpu) constraints).
|
||||
|
||||
@@ -217,7 +217,7 @@ bazelisk build --nobuild //:natives-win32-x64-baseline
|
||||
| rstest macro: "Cargo.toml not found" in a vendored test | rstest verifies `Cargo.toml` exists in the manifest dir | `compile_data = ["Cargo.toml"]` on the `rust_test` (see `crates/vendor/uu-tail/BUILD.bazel`) |
|
||||
| vendored tests fail on bare `test_data/...` paths / symlink into srcs | tests assume cargo's cwd, incompatible with runfiles execution | `tags = ["manual"]`; run via `cargo nextest` when touching the fork; hermetic sibling test covers the contract |
|
||||
| blake3 msvc: `ml64.exe` not found | cc-rs resolves MASM from build-script PATH on non-windows hosts | `bin/ml64.exe → llvm-ml -m64` shim in `@msvc_cc`, prepended via the `blake3` annotation PATH |
|
||||
| audiopus_sys msvc: cmake demands VS generator / rc+mt tools; `try_compile` wants `msvcrtd.lib` | cross cmake on linux/mac hosts; Debug config → `/MDd` which the lean xwin splat lacks | `CMAKE_GENERATOR_x86_64_pc_windows_msvc=Ninja` + `@msvc_cc`'s `toolchain.cmake` (`CMAKE_TOOLCHAIN_FILE_x86_64_pc_windows_msvc`) pinning wrappers + Release try-compile + `/MD` |
|
||||
| audiopus_sys msvc: cmake demands VS generator / rc+mt tools; `try_compile` wants `msvcrtd.lib` | cross cmake on linux/mac hosts; Debug config → `/MDd` which the lean xwin splat lacks | `CMAKE_GENERATOR_x86_64_pc_windows_msvc=Ninja` + `@msvc_cc`'s `toolchain.cmake` (`CMAKE_TOOLCHAIN_FILE_x86_64_pc_windows_msvc`) pinning wrappers + Release try-compile + `/MT` (static CRT, matches the addon policy) |
|
||||
| win32 link oddities generally | — | read `bazel/toolchains/msvc/NOTES.md` first: wrapper self-location, `lld-link` flavor/driver-link behavior, `LIB`, `/MD` CRT choice, xwin splat caveats |
|
||||
| `rust_test(crate = ...)` "can't find crate" at macro expansion | rmeta-only pipelined deps break macro_rules re-export harness compiles | rust pipelined_compilation stays OFF (`.bazelrc` note) |
|
||||
| build script can't find cmake/ninja | `--incompatible_strict_action_env` — no host env leaks | explicit `PATH` in the crate annotation (`MODULE.bazel`), not host env |
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `omp` failing to start on a clean Windows install with `Failed to load pi_natives native addon for win32-x64 ... The specified module could not be found` (LoadLibrary error 126). The shipped win32-x64 addon linked the dynamic MSVC CRT (`/MD`) and imported `VCRUNTIME140.dll` from the Visual C++ Redistributable, which is absent on a fresh Windows install. The addon now statically links the CRT (`+crt-static` for rustc plus the `static_link_msvcrt` cc feature for its C dependencies), so the `.node` imports only core Windows system DLLs ([#8439](https://github.com/can1357/oh-my-pi/issues/8439)).
|
||||
|
||||
## [17.3.0] - 2026-08-13
|
||||
|
||||
### Fixed
|
||||
|
||||
Reference in New Issue
Block a user