@@ -184,9 +184,37 @@ jobs:
184184 mkdir dist
185185 Copy-Item build\bin\Release\whisper-cli.exe dist\whisper-cpp-win32-x64-cpu.exe
186186 Copy-Item build\bin\Release\whisper-server.exe dist\whisper-server-win32-x64-cpu.exe
187+
188+ # Both exes link the dynamic MSVC runtime: CMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded
189+ # is a silent no-op while CMake policy CMP0091 is unset, and MSVC OpenMP links
190+ # vcomp140.dll dynamically regardless. On a machine without the VC++ 2015-2022
191+ # redistributable the loader kills a bare exe with 0xC0000135 (STATUS_DLL_NOT_FOUND)
192+ # before main(), so ship the runtime app-locally (OpenWhispr CUS-113). Glob the
193+ # toolset dir (Microsoft.VC143.* today) — the version moves with the runner image.
194+ $crt = (Get-Item "$env:VCToolsRedistDir\x64\Microsoft.VC*.CRT" | Select-Object -First 1).FullName
195+ $omp = (Get-Item "$env:VCToolsRedistDir\x64\Microsoft.VC*.OpenMP" | Select-Object -First 1).FullName
196+ $runtimeDlls = @("msvcp140.dll", "vcruntime140.dll", "vcruntime140_1.dll")
197+ foreach ($dll in $runtimeDlls) { Copy-Item (Join-Path $crt $dll) dist\ }
198+ Copy-Item (Join-Path $omp "vcomp140.dll") dist\
199+ $runtimeDlls += "vcomp140.dll"
200+
187201 Set-Location dist
188- Compress-Archive -Path whisper-cpp-win32-x64-cpu.exe -DestinationPath whisper-cpp-win32-x64-cpu.zip
189- Compress-Archive -Path whisper-server-win32-x64-cpu.exe -DestinationPath whisper-server-win32-x64-cpu.zip
202+ Compress-Archive -Path (@("whisper-cpp-win32-x64-cpu.exe") + $runtimeDlls) -DestinationPath whisper-cpp-win32-x64-cpu.zip
203+ Compress-Archive -Path (@("whisper-server-win32-x64-cpu.exe") + $runtimeDlls) -DestinationPath whisper-server-win32-x64-cpu.zip
204+
205+ - name : Verify zips contain the MSVC runtime DLLs
206+ shell : pwsh
207+ run : |
208+ Add-Type -AssemblyName System.IO.Compression.FileSystem
209+ $required = @("msvcp140.dll", "vcruntime140.dll", "vcruntime140_1.dll", "vcomp140.dll")
210+ foreach ($zip in Get-ChildItem dist\*.zip) {
211+ $archive = [System.IO.Compression.ZipFile]::OpenRead($zip.FullName)
212+ $names = $archive.Entries.Name
213+ $archive.Dispose()
214+ Write-Host "$($zip.Name): $($names -join ', ')"
215+ $missing = $required | Where-Object { $names -notcontains $_ }
216+ if ($missing) { throw "$($zip.Name) missing: $($missing -join ', ')" }
217+ }
190218
191219 - name : Upload whisper-cli artifact
192220 uses : actions/upload-artifact@v4
@@ -329,6 +357,16 @@ jobs:
329357 exit 1
330358 }
331359
360+ # MSVC runtime DLLs — the exes link the dynamic CRT; see the CPU job comment.
361+ $crt = (Get-Item "$env:VCToolsRedistDir\x64\Microsoft.VC*.CRT" | Select-Object -First 1).FullName
362+ $omp = (Get-Item "$env:VCToolsRedistDir\x64\Microsoft.VC*.OpenMP" | Select-Object -First 1).FullName
363+ foreach ($dll in @("msvcp140.dll", "vcruntime140.dll", "vcruntime140_1.dll")) {
364+ Copy-Item (Join-Path $crt $dll) dist\
365+ $bundledDlls += $dll
366+ }
367+ Copy-Item (Join-Path $omp "vcomp140.dll") dist\
368+ $bundledDlls += "vcomp140.dll"
369+
332370 # Create zip archives with dynamically built file lists
333371 Set-Location dist
334372 $cliFiles = @("whisper-cpp-win32-x64-cuda.exe") + $bundledDlls
@@ -337,6 +375,20 @@ jobs:
337375 Compress-Archive -Path $cliFiles -DestinationPath whisper-cpp-win32-x64-cuda.zip
338376 Compress-Archive -Path $serverFiles -DestinationPath whisper-server-win32-x64-cuda.zip
339377
378+ - name : Verify zips contain the MSVC runtime DLLs
379+ shell : pwsh
380+ run : |
381+ Add-Type -AssemblyName System.IO.Compression.FileSystem
382+ $required = @("msvcp140.dll", "vcruntime140.dll", "vcruntime140_1.dll", "vcomp140.dll")
383+ foreach ($zip in Get-ChildItem dist\*.zip) {
384+ $archive = [System.IO.Compression.ZipFile]::OpenRead($zip.FullName)
385+ $names = $archive.Entries.Name
386+ $archive.Dispose()
387+ Write-Host "$($zip.Name): $($names -join ', ')"
388+ $missing = $required | Where-Object { $names -notcontains $_ }
389+ if ($missing) { throw "$($zip.Name) missing: $($missing -join ', ')" }
390+ }
391+
340392 - name : Upload whisper-cli artifact
341393 uses : actions/upload-artifact@v4
342394 with :
@@ -621,13 +673,34 @@ jobs:
621673 Copy-Item build\bin\Release\whisper-server.exe dist\whisper-server-win32-x64-vulkan.exe
622674
623675 # vulkan-1.dll is provided by the user's GPU driver install — do not bundle.
624- # whisper-server is statically linked against ggml-vulkan, so no other runtime DLLs are needed.
676+ # whisper-server is statically linked against ggml-vulkan, but the exe still
677+ # links the dynamic MSVC runtime; bundle it — see the CPU job comment.
678+ $crt = (Get-Item "$env:VCToolsRedistDir\x64\Microsoft.VC*.CRT" | Select-Object -First 1).FullName
679+ $omp = (Get-Item "$env:VCToolsRedistDir\x64\Microsoft.VC*.OpenMP" | Select-Object -First 1).FullName
680+ $runtimeDlls = @("msvcp140.dll", "vcruntime140.dll", "vcruntime140_1.dll")
681+ foreach ($dll in $runtimeDlls) { Copy-Item (Join-Path $crt $dll) dist\ }
682+ Copy-Item (Join-Path $omp "vcomp140.dll") dist\
683+ $runtimeDlls += "vcomp140.dll"
625684
626685 Write-Host "Contents of dist folder:"
627686 Get-ChildItem dist | Format-Table Name, Length
628687
629688 Set-Location dist
630- Compress-Archive -Path whisper-server-win32-x64-vulkan.exe -DestinationPath whisper-server-win32-x64-vulkan.zip
689+ Compress-Archive -Path (@("whisper-server-win32-x64-vulkan.exe") + $runtimeDlls) -DestinationPath whisper-server-win32-x64-vulkan.zip
690+
691+ - name : Verify zip contains the MSVC runtime DLLs
692+ shell : pwsh
693+ run : |
694+ Add-Type -AssemblyName System.IO.Compression.FileSystem
695+ $required = @("msvcp140.dll", "vcruntime140.dll", "vcruntime140_1.dll", "vcomp140.dll")
696+ foreach ($zip in Get-ChildItem dist\*.zip) {
697+ $archive = [System.IO.Compression.ZipFile]::OpenRead($zip.FullName)
698+ $names = $archive.Entries.Name
699+ $archive.Dispose()
700+ Write-Host "$($zip.Name): $($names -join ', ')"
701+ $missing = $required | Where-Object { $names -notcontains $_ }
702+ if ($missing) { throw "$($zip.Name) missing: $($missing -join ', ')" }
703+ }
631704
632705 - name : Upload whisper-server artifact
633706 uses : actions/upload-artifact@v4
@@ -705,9 +778,9 @@ jobs:
705778 - `whisper-server-linux-x64-vulkan.zip` - Linux x64 with Vulkan (uses system Vulkan loader)
706779
707780 ## Requirements
708- - **Windows CUDA build**: No additional requirements - CUDA DLLs are bundled.
709- - **Windows Vulkan build**: Requires an up-to-date GPU driver that ships the Vulkan runtime (`vulkan-1.dll`). All modern NVIDIA/AMD/Intel drivers include it.
710- - **Windows CPU build**: No requirements.
781+ - **Windows CUDA build**: No additional requirements - CUDA and MSVC runtime DLLs are bundled.
782+ - **Windows Vulkan build**: Requires an up-to-date GPU driver that ships the Vulkan runtime (`vulkan-1.dll`). All modern NVIDIA/AMD/Intel drivers include it. MSVC runtime DLLs are bundled.
783+ - **Windows CPU build**: No requirements - MSVC runtime DLLs are bundled .
711784 - **Linux CUDA build**: Install latest NVIDIA drivers and CUDA toolkit for GPU acceleration.
712785 - **Linux Vulkan build**: Requires the system Vulkan loader (`libvulkan.so.1`, typically from the `libvulkan1` package) and a Vulkan-capable GPU driver (Mesa for AMD/Intel, NVIDIA proprietary driver for NVIDIA).
713786 - **Linux CPU build**: No requirements.
0 commit comments