Skip to content

Commit 6ac1454

Browse files
authored
Merge pull request #6 from OpenWhispr/fix/bundle-msvc-runtime-dlls
build: bundle MSVC runtime DLLs into win32 zips
2 parents 3b3fba9 + 8f60cef commit 6ac1454

2 files changed

Lines changed: 83 additions & 10 deletions

File tree

‎.github/workflows/build-binaries.yml‎

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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.

‎.github/workflows/build-freebsd.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,17 @@ concurrency:
2929

3030
jobs:
3131
freeBSD-latest:
32-
runs-on: macos-13
32+
runs-on: ubuntu-latest
3333

3434
steps:
3535
- name: Clone
3636
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
3737

3838
- name: Build
39-
uses: cross-platform-actions/action@fe0167d8082ac584754ef3ffb567fded22642c7d # v0.27.0
39+
uses: cross-platform-actions/action@5ea7e8e4677bd726033a10b094ba1c5762b15dee # v1.3.0
4040
with:
4141
operating_system: freebsd
42-
version: '14.2'
42+
version: '14.4'
4343
run: |
4444
sudo pkg update
4545
sudo pkg install -y gmake sdl2 cmake git

0 commit comments

Comments
 (0)