feat(build): Windows runtime-DLL deployment beside the executable (v0.0.73)#185
Merged
Merged
Conversation
….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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A directly-launched Windows
.execannot 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*.dllfound in a linked dependency's[runtime] library_dirsis staged intobin/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:
-Wl,-rpath,<dir>(unchanged)*.dllbeside 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 platformif constexpr, no schema changeThe deploy list is populated by globbing
*.dllin each dependency runtime dir — not gated byif constexpr(is_windows)and with nomanifest.cppmschema change:.so/.dylib(never.dll), so the glob matches nothing → non-Windows builds are byte-for-byte unchanged.[runtime] library_dirsglobally; 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.)Changes
src/build/plan.cppm—BuildPlan::runtimeDeployFiles: glob*.dllfrom each dep[runtime] library_dirs, dedup by dest (bin/<dll>).src/build/ninja_backend.cppm— emit onecp_bmicopy edge per staged DLL; executables (Binary/TestBinary) implicitly depend on them; added todefault. (Ninja auto-creates thebin/parent dir before the edge runs.)tests/e2e/84_runtime_dll_deploy.sh— new e2e: a dummy dependency ships a stublibdummy.dll; asserts mcpp stages it beside the exe byte-for-byte and does not deploy a non-DLL sibling.0.0.72 → 0.0.73(mcpp.toml+fingerprint.cppm).Verification
84_runtime_dll_deploy.sh— PASS (Linux host, exercises the exact Windows copy path).mcpp test) — 27 ok, 0 failed.74_run_no_loader_env_leak,80_feature_defines,81_capability_binding,83_feature_defines_propagate— PASS.The Windows link/run half (clang-cl linking
libopenblas.lib, DLL loading at launch,cblas_dgemmresult) 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.