Skip to content

Commit 12dc0c0

Browse files
committed
fix: statically link the Windows standalone CLI release (SYS-W11-06)
Downloaded and verified the real published meshcraft-cli-windows artifact from the first fully-green windows-2022 CI run, per SYS-W11-06's amended acceptance criteria (extract outside any build tree, run --version, reproduce the MC3->MCB/GLB fixture and check its SHA-256). The artifact failed at the first step: mc3togltf.exe wouldn't even start (STATUS_DLL_NOT_FOUND under a MinGW+Wine repro of the exact downloaded files) -- the artifact bundles only the two .exe files, but mc3togltf.exe dynamically links Manifold and tinyxml2 (both inherit Manifold's own BUILD_SHARED_LIBS=ON default) plus the MinGW toolchain's own runtime (libgcc_s_seh-1.dll/libwinpthread-1.dll/libstdc++-6.dll), none of which the "Publish qualified Windows CLI artifacts" step stages. Rather than enumerating and uploading every DLL (fragile, and the POST_BUILD $<TARGET_RUNTIME_DLLS:...> copy step doesn't even see the raw MinGW compiler runtime DLLs, only proper CMake library targets), fixed this the same way Mc3/Mcb/mc3togltf_lib already are: link everything statically. Added -DBUILD_SHARED_LIBS=OFF and -DCMAKE_EXE_LINKER_FLAGS="-static -static-libgcc -static-libstdc++" to the standalone-windows job's shared configure step (all 4 components). Also fixed a real CMake gotcha this surfaced: mc3togltf_stage_runtime_ dlls()'s POST_BUILD command failed outright once a target had zero DLL dependencies -- $<TARGET_RUNTIME_DLLS:target> expands to nothing, and `cmake -E copy_if_different` with no source arguments is an error, not a no-op. Fixed with the documented $<IF:$<BOOL:...>,copy_if_different,true> workaround. Verified via a real MinGW+Wine repro of the exact static-linked binaries: mc3togltf.exe and mc3tomcb.exe both now have zero DLL dependencies, both run --version standalone, and both reproduce test/house.mc3.xml's MC3->GLB/MCB conversion byte-identical to the existing fixture SHA-256 hashes (0ef25953c8bce.../4157f107e277a...). Also reran the full 28-test standalone mc3 suite under this same static config: 28/28 pass (one apparent timeout on a solo rerun was Wine process contention, not a real failure, matching an already-known pattern from earlier tonight).
1 parent 5f349d1 commit 12dc0c0

2 files changed

Lines changed: 29 additions & 8 deletions

File tree

.github/workflows/ci.yml

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,22 @@ jobs:
102102
$components = @('mc3', 'mcb', 'mc3togltf', 'mc3tomcb')
103103
foreach ($component in $components) {
104104
$buildDir = "build/$component"
105+
# BUILD_SHARED_LIBS=OFF + static-linking the MinGW runtime: without
106+
# this, mc3togltf.exe links against Manifold/tinyxml2 as DLLs
107+
# (they inherit Manifold's own BUILD_SHARED_LIBS=ON default) AND
108+
# the MinGW toolchain's own runtime (libgcc_s_seh-1.dll/
109+
# libwinpthread-1.dll/libstdc++-6.dll) -- none of which the
110+
# "Publish qualified Windows CLI artifacts" step below stages
111+
# alongside the .exe, so the *published* artifact fails to start
112+
# at all with STATUS_DLL_NOT_FOUND outside this build tree.
113+
# Confirmed via a real downloaded artifact + MinGW/Wine repro
114+
# (2026-07-27, SYS-W11-06 verification): fully static removes
115+
# every DLL dependency and produces byte-identical MC3->MCB/GLB
116+
# output to the dynamic build.
105117
cmake -S $component -B $buildDir -G Ninja `
106-
-DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON
118+
-DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON `
119+
-DBUILD_SHARED_LIBS=OFF `
120+
-DCMAKE_EXE_LINKER_FLAGS="-static -static-libgcc -static-libstdc++"
107121
cmake --build $buildDir --parallel 2
108122
ctest --test-dir $buildDir --output-on-failure --parallel 2
109123
}
@@ -119,12 +133,11 @@ jobs:
119133
120134
# SYS-W11-08: bundle the same notices/SHA-256 manifest the Linux
121135
# meshcraft_cli_release archive gets, so the Windows artifact isn't a
122-
# bare, unverifiable pair of executables. Does not attempt to stage
123-
# Manifold/tinyobjloader runtime DLLs here -- that is a separate,
124-
# already-tracked gap (the in-tree ctest run above can currently fail
125-
# with STATUS_DLL_NOT_FOUND for the same underlying reason), and adding
126-
# a manifest for an incomplete artifact is still strictly better than
127-
# no manifest at all.
136+
# bare, unverifiable pair of executables. No runtime DLLs to stage
137+
# (fixed 2026-07-27, SYS-W11-06 verification): the configure step above
138+
# now links everything -- Manifold, tinyxml2, and the MinGW runtime
139+
# itself -- statically, so these two .exe files have zero third-party
140+
# DLL dependencies at all.
128141
- name: Stage release manifest and notices
129142
shell: pwsh
130143
run: |

mc3togltf/CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,16 @@ endif()
111111
# is a no-op there.
112112
function(mc3togltf_stage_runtime_dlls target)
113113
if(WIN32)
114+
# $<TARGET_RUNTIME_DLLS:...> expands to nothing when a target has no
115+
# DLL dependencies at all (e.g. a fully statically-linked build) --
116+
# `cmake -E copy_if_different` with zero source arguments is itself
117+
# an error (prints usage, fails the build), not a harmless no-op. Pick
118+
# the `true` no-op subcommand instead of `copy_if_different` in that
119+
# case via $<IF:$<BOOL:...>,...>, a documented workaround for this
120+
# exact generator-expression gotcha.
114121
add_custom_command(TARGET ${target} POST_BUILD
115-
COMMAND ${CMAKE_COMMAND} -E copy_if_different
122+
COMMAND ${CMAKE_COMMAND} -E
123+
$<IF:$<BOOL:$<TARGET_RUNTIME_DLLS:${target}>>,copy_if_different,true>
116124
$<TARGET_RUNTIME_DLLS:${target}>
117125
$<TARGET_FILE_DIR:${target}>
118126
COMMAND_EXPAND_LISTS

0 commit comments

Comments
 (0)