Summary
simics_build_utils::emit_link_info() emits cargo:rustc-link-lib=dylib:+verbatim=<name>.dll for libsimics-common, libvtutils, and the bundled Python DLL on Windows. This works with the MinGW/GNU Rust target (MinGW's ld/lld can import directly from a PE DLL) but fails on the default x86_64-pc-windows-msvc host, because link.exe requires a proper import library (.lib).
Reproduction
Default Rust install on Windows (MSVC host), building any crate that depends on simics-build-utils — for example, TSFFS:
$env:SIMICS_BASE = "C:\...\Simics\simics-6.0.185"
cargo build --release # defaults to x86_64-pc-windows-msvc
Result:
warning: Using Python environment for linking: PythonEnvironment { ...
lib: C:\...\simics-6.0.185\win64\bin\python310.dll, ... }
error: linking with `link.exe` failed: exit code: 1107
= note: ...\libsimics-common.dll : fatal error LNK1107:
invalid or corrupt file: cannot read at 0x4F8
link.exe is being handed the raw DLL and chokes on the PE header where it expects a COFF archive.
Workaround: cargo build --release --target x86_64-pc-windows-gnu (requires MinGW-w64 installed). This is what TSFFS's docs recommend, but it should not be a requirement for consumers on a default Rust Windows install.
Root cause
In simics-build-utils/src/lib.rs, the #[cfg(windows)] branch of emit_link_info() resolves DLL filenames and emits them verbatim:
let libsimics_common = bin_dir.join(\"libsimics-common.dll\").canonicalize()?;
// ...
println!(\"cargo:rustc-link-lib=dylib:+verbatim={}\",
libsimics_common.file_name()...); // => libsimics-common.dll
+verbatim passes the string directly to the linker. MinGW accepts this; MSVC does not.
Similarly, simics_python_utils::PythonEnvironment::lib_filename() returns python310.dll for the bundled Python case (the banner shows lib: ...\bin\python310.dll), when MSVC needs python310.lib.
Proposed fix
Branch on target_env in the build script (not on host cfg(windows), since cross-compiles exist):
// Windows GNU: keep current behavior (link directly against DLL)
// Windows MSVC: emit import-library filenames
#[cfg(all(windows, target_env = \"msvc\"))] // or examine CARGO_CFG_TARGET_ENV
{
println!(\"cargo:rustc-link-lib=dylib:+verbatim=libsimics-common.lib\");
println!(\"cargo:rustc-link-lib=dylib:+verbatim=libvtutils.lib\");
println!(\"cargo:rustc-link-lib=dylib:+verbatim=python310.lib\");
}
On my Simics 6.0.185 install, libsimics-common.lib, libvtutils.lib, and python310.lib already exist in win64\bin alongside the DLLs, so no extra generation step is needed for this version. For installs where the .lib is missing, lib.exe /def: from a generated .def (via gendef or by dumping exports) is the standard workaround.
simics-python-utils needs a matching change so PythonEnvironment::lib_filename() returns the import lib name under MSVC.
Caveats (worth flagging, not blockers)
Simics's Windows DLLs ship alongside libgcc_s_seh-1.dll, libstdc++-6.dll, and libwinpthread-1.dll, indicating they were built with MinGW GCC. The linker fix above makes the build link, but runtime ABI compatibility for MSVC consumers depends on:
- public Simics API being pure C (appears to be the case);
- no C++ exceptions,
longjmp, or TLS crossing the DLL boundary;
- CRT consistency (both UCRT — probably fine).
Basic usage should work; edge cases may need validation. Happy to help test if a fix lands.
Environment
- Windows 11
- Rust 1.90.0, host `x86_64-pc-windows-msvc`
- Simics 6.0.185 (bundled Python 3.10)
- `simics-build-utils` 0.2.6, `simics-python-utils` 0.2.6
- Consumer: tsffs 0.2.4
Summary
simics_build_utils::emit_link_info()emitscargo:rustc-link-lib=dylib:+verbatim=<name>.dllforlibsimics-common,libvtutils, and the bundled Python DLL on Windows. This works with the MinGW/GNU Rust target (MinGW'sld/lldcan import directly from a PE DLL) but fails on the defaultx86_64-pc-windows-msvchost, becauselink.exerequires a proper import library (.lib).Reproduction
Default Rust install on Windows (MSVC host), building any crate that depends on
simics-build-utils— for example, TSFFS:Result:
link.exeis being handed the raw DLL and chokes on the PE header where it expects a COFF archive.Workaround:
cargo build --release --target x86_64-pc-windows-gnu(requires MinGW-w64 installed). This is what TSFFS's docs recommend, but it should not be a requirement for consumers on a default Rust Windows install.Root cause
In
simics-build-utils/src/lib.rs, the#[cfg(windows)]branch ofemit_link_info()resolves DLL filenames and emits them verbatim:+verbatimpasses the string directly to the linker. MinGW accepts this; MSVC does not.Similarly,
simics_python_utils::PythonEnvironment::lib_filename()returnspython310.dllfor the bundled Python case (the banner showslib: ...\bin\python310.dll), when MSVC needspython310.lib.Proposed fix
Branch on
target_envin the build script (not on hostcfg(windows), since cross-compiles exist):On my Simics 6.0.185 install,
libsimics-common.lib,libvtutils.lib, andpython310.libalready exist inwin64\binalongside the DLLs, so no extra generation step is needed for this version. For installs where the.libis missing,lib.exe /def:from a generated.def(viagendefor by dumping exports) is the standard workaround.simics-python-utilsneeds a matching change soPythonEnvironment::lib_filename()returns the import lib name under MSVC.Caveats (worth flagging, not blockers)
Simics's Windows DLLs ship alongside
libgcc_s_seh-1.dll,libstdc++-6.dll, andlibwinpthread-1.dll, indicating they were built with MinGW GCC. The linker fix above makes the build link, but runtime ABI compatibility for MSVC consumers depends on:longjmp, or TLS crossing the DLL boundary;Basic usage should work; edge cases may need validation. Happy to help test if a fix lands.
Environment