Skip to content

feat(build): Windows runtime-DLL deployment beside the executable (v0.0.73)#185

Merged
Sunrisepeak merged 1 commit into
mainfrom
feat/windows-runtime-dll-deploy
Jun 29, 2026
Merged

feat(build): Windows runtime-DLL deployment beside the executable (v0.0.73)#185
Sunrisepeak merged 1 commit into
mainfrom
feat/windows-runtime-dll-deploy

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

Summary

A directly-launched Windows .exe cannot RUNPATH-locate a dependency's runtime DLL — PE has no rpath mechanism, so mcpp's existing [runtime].library_dirs → RPATH path (ELF/Mach-O) is a no-op on Windows. This PR adds the symmetric PE backend: each *.dll found in a linked dependency's [runtime] library_dirs is staged into bin/ beside the produced executable via a ninja copy edge that the executable target takes as an implicit dependency.

This completes an abstraction already designed but unimplemented on PE:

  • ELF / Mach-O → -Wl,-rpath,<dir> (unchanged)
  • PE → copy *.dll beside the .exe (new)

Both are "make the runtime library locatable." It unblocks a Windows compat.openblas (import-lib + runtime DLL) and any future prebuilt-DLL package (fftw / hdf5 / …).

Design choice: *.dll-glob filter, not a platform if constexpr, no schema change

The deploy list is populated by globbing *.dll in each dependency runtime dir — not gated by if constexpr(is_windows) and with no manifest.cppm schema change:

  • A real Linux/macOS dependency ships .so/.dylib (never .dll), so the glob matches nothing → non-Windows builds are byte-for-byte unchanged.
  • A recipe declares [runtime] library_dirs globally; only a Windows prebuilt-DLL package populates the deploy list. (This is the design's §7 "declare it globally — harmless on Linux" option, made safe by the extension filter.)
  • The same code path is therefore testable on a Linux host, no Windows runner needed for the mechanism.

Changes

  • src/build/plan.cppmBuildPlan::runtimeDeployFiles: glob *.dll from each dep [runtime] library_dirs, dedup by dest (bin/<dll>).
  • src/build/ninja_backend.cppm — emit one cp_bmi copy edge per staged DLL; executables (Binary/TestBinary) implicitly depend on them; added to default. (Ninja auto-creates the bin/ parent dir before the edge runs.)
  • tests/e2e/84_runtime_dll_deploy.sh — new e2e: a dummy dependency ships a stub libdummy.dll; asserts mcpp stages it beside the exe byte-for-byte and does not deploy a non-DLL sibling.
  • Version bump 0.0.72 → 0.0.73 (mcpp.toml + fingerprint.cppm).
  • Design doc updated with the implementation note / deviation.

Verification

  • New e2e 84_runtime_dll_deploy.sh — PASS (Linux host, exercises the exact Windows copy path).
  • Unit + integration suite (mcpp test) — 27 ok, 0 failed.
  • Regression e2e: 74_run_no_loader_env_leak, 80_feature_defines, 81_capability_binding, 83_feature_defines_propagate — PASS.
  • Self-host build at v0.0.73 — clean.

The Windows link/run half (clang-cl linking libopenblas.lib, DLL loading at launch, cblas_dgemm result) is verified in mcpp-index CI — Phase D of the design doc.

See .agents/docs/2026-06-29-windows-runtime-dll-deployment-and-openblas.md.

….0.73

A directly-launched Windows .exe cannot RUNPATH-locate a dependency's runtime
DLL (PE has no rpath). mcpp now stages every *.dll found in a linked
dependency's [runtime] library_dirs into bin/, beside the produced executable,
via a ninja copy edge the executable takes as an implicit dependency. This
completes an abstraction already designed but unimplemented on PE: RPATH on
ELF/Mach-O, copy-beside-exe on PE — both 'make the runtime library locatable'.

The deploy is filtered by the *.dll extension, NOT by if constexpr(is_windows)
and with no schema change: a real Linux/macOS dependency ships .so/.dylib
(never .dll), so the glob matches nothing and non-Windows builds are
byte-for-byte unchanged. A recipe declares [runtime] library_dirs globally;
only a Windows prebuilt-DLL package populates the deploy list. This unblocks a
Windows compat.openblas (import-lib + runtime DLL) and any future prebuilt-DLL
package.

Test: tests/e2e/84_runtime_dll_deploy.sh exercises the exact copy path on a
Linux host via a dummy dependency shipping a stub libdummy.dll (asserts the DLL
is staged beside the exe byte-for-byte; a non-DLL sibling is not). The Windows
link/run half is verified in mcpp-index CI (design Phase D). Regression: unit
suite (27 ok), e2e 74/80/81/83, self-host build.

See .agents/docs/2026-06-29-windows-runtime-dll-deployment-and-openblas.md.
@Sunrisepeak Sunrisepeak merged commit 9cba34b into main Jun 29, 2026
5 checks passed
@Sunrisepeak Sunrisepeak deleted the feat/windows-runtime-dll-deploy branch June 29, 2026 10:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant