From a16ca18b07918f6d5125ba5190183d6f73002fd0 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 28 Oct 2026 06:57:38 -0500 Subject: [PATCH 1/2] Link the static CRT so the Windows zip runs on a clean install The build linked /MD, so sendspin-cli.exe imported MSVCP140, VCRUNTIME140 and VCRUNTIME140_1 from the Visual C++ Redistributable, which Windows does not ship and nothing in the zip or the installer provides. CI and dev machines have it, so every check passed while a fresh PC would fail to start the binary. CMAKE_MSVC_RUNTIME_LIBRARY now selects the static CRT for every target, GoogleTest included, unless a parent project or -D already chose one. The Windows leg asserts the binary imports no Redistributable DLL, since the smoke test on a runner that has it cannot tell. --- .github/workflows/build.yml | 16 ++++++++++++++++ CMakeLists.txt | 7 +++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f135355..a593f03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -323,6 +323,22 @@ jobs: - name: Build run: cmake --build build + # The zip ships the .exe alone, and this runner has the Redistributable, so only the imports can tell. + - name: Assert the binary needs no Visual C++ Redistributable (Windows) + if: runner.os == 'Windows' + run: | + dumpbin -nologo -dependents build/sendspin-cli.exe >imports.txt + cat imports.txt + if grep -Eiq '^[[:space:]]*(msvcp|vcruntime|concrt)[0-9_]*\.dll' imports.txt; then + echo '::error::sendspin-cli.exe imports a Visual C++ Redistributable DLL, which a clean Windows install does not have' + exit 1 + fi + grep -Eiq '^[[:space:]]*kernel32\.dll' imports.txt || { + echo '::error::dumpbin listed no imports at all, so the check above proved nothing' + exit 1 + } + rm -f imports.txt + # Read the target architecture off the linked binary, which covers every dependency, before running the suite. - name: Assert the binary is built for the architecture this leg claims if: matrix.arm32 diff --git a/CMakeLists.txt b/CMakeLists.txt index 86b5ae4..eaafeef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,11 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +# Static CRT for every target, so the Windows .exe runs without the Visual C++ Redistributable. +if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +endif() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) endif() @@ -475,8 +480,6 @@ if(SENDSPIN_CLI_BUILD_TESTS) ) set(INSTALL_GTEST OFF CACHE BOOL "Install GoogleTest alongside our own targets") set(BUILD_GMOCK OFF CACHE BOOL "Build GoogleMock") - # The CRT the rest of the build links (/MD), not GoogleTest's own /MT default. - set(gtest_force_shared_crt ON CACHE BOOL "Use the shared CRT for GoogleTest") FetchContent_MakeAvailable(googletest) if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") # GoogleTest builds itself with /WX, which newer clang-cl warnings break. From cd44756a62223b59fe1ae87f3dab41a8b55c766b Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 28 Oct 2026 13:10:12 -0500 Subject: [PATCH 2/2] Catch Redistributable DLLs with lettered suffixes MSVCP140_ATOMIC_WAIT.dll and MSVCP140_CODECVT_IDS.dll slipped past the digits-and-underscores suffix. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a593f03..03430e2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -329,7 +329,7 @@ jobs: run: | dumpbin -nologo -dependents build/sendspin-cli.exe >imports.txt cat imports.txt - if grep -Eiq '^[[:space:]]*(msvcp|vcruntime|concrt)[0-9_]*\.dll' imports.txt; then + if grep -Eiq '^[[:space:]]*(msvcp|vcruntime|concrt)[0-9a-z_]*\.dll' imports.txt; then echo '::error::sendspin-cli.exe imports a Visual C++ Redistributable DLL, which a clean Windows install does not have' exit 1 fi