Skip to content

Commit e16d039

Browse files
Copilotlmangani
andcommitted
feat: add Windows Electron build support with precompiled binaries
- electron/main.js: prepend BIN_DIR to PATH on win32 in setupLibraryPaths() so spawned ace-lm.exe / ace-synth.exe child processes find bundled DLLs - electron-release.yml: add build-windows job (windows-latest) that downloads acestep-windows-x64.zip, extracts .exe + .dll files, rebuilds native modules, and produces an NSIS installer - publish job: add build-windows to needs, upload *.exe artifacts, update release notes table to include Windows entry Co-authored-by: lmangani <1423657+lmangani@users.noreply.github.com>
1 parent 0bad80a commit e16d039

2 files changed

Lines changed: 109 additions & 6 deletions

File tree

.github/workflows/electron-release.yml

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,104 @@ jobs:
277277
if-no-files-found: warn
278278
retention-days: 7
279279

280+
# ────────────────────────────────────────────────────────────────────────────
281+
# Windows — x86_64 → ACE-Step UI-*.exe (NSIS installer)
282+
#
283+
# The Windows binary archive ships .exe binaries and .dll files in a flat
284+
# zip archive. All files are extracted directly into bin/ so that both the
285+
# executables and the DLLs sit in the same directory. At runtime,
286+
# electron/main.js prepends BIN_DIR to PATH so that spawned child processes
287+
# can resolve the bundled DLLs without any system-wide installation.
288+
# ────────────────────────────────────────────────────────────────────────────
289+
build-windows:
290+
name: Build — Windows x64
291+
runs-on: windows-latest
292+
permissions:
293+
contents: write
294+
295+
steps:
296+
- uses: actions/checkout@v4
297+
298+
- uses: actions/setup-node@v4
299+
with:
300+
node-version: ${{ env.NODE_VERSION }}
301+
cache: "npm"
302+
303+
- name: Install root dependencies
304+
run: npm install
305+
306+
- name: Install server dependencies
307+
run: npm install
308+
working-directory: server
309+
310+
- name: Build frontend
311+
run: npm run build
312+
313+
- name: Build server
314+
run: npm run build
315+
working-directory: server
316+
317+
- name: Download & extract acestep.cpp Windows binaries
318+
shell: pwsh
319+
run: |
320+
$archive = "acestep-windows-x64.zip"
321+
$url = "https://github.com/audiohacking/acestep.cpp/releases/download/$env:BINARY_VERSION/$archive"
322+
Write-Host "Downloading $archive from $url ..."
323+
Invoke-WebRequest -Uri $url -OutFile $archive -UseBasicParsing
324+
New-Item -ItemType Directory -Force -Path bin | Out-Null
325+
Expand-Archive -Path $archive -DestinationPath bin -Force
326+
Write-Host "bin/ contents:"
327+
Get-ChildItem bin | Format-Table Name, Length
328+
329+
- name: Verify Windows binaries & DLLs
330+
shell: pwsh
331+
run: |
332+
$warn = 0
333+
foreach ($bin in @("ace-lm.exe", "ace-synth.exe", "neural-codec.exe")) {
334+
if (Test-Path "bin\$bin") { Write-Host "OK bin\$bin" }
335+
else { Write-Warning "MISSING bin\$bin"; $warn++ }
336+
}
337+
$dlls = Get-ChildItem bin -Filter "*.dll"
338+
if ($dlls.Count -gt 0) {
339+
Write-Host "OK $($dlls.Count) DLL(s) found in bin\"
340+
} else {
341+
Write-Warning "No DLLs found in bin\ — verify BINARY_VERSION=$env:BINARY_VERSION"
342+
$warn++
343+
}
344+
if ($warn -gt 0) { Write-Warning "Some files missing — verify BINARY_VERSION=$env:BINARY_VERSION" }
345+
346+
- name: Rebuild native modules for Electron
347+
run: npx @electron/rebuild --module-dir server --only better-sqlite3
348+
349+
- name: Resolve release tag
350+
id: tag
351+
shell: pwsh
352+
run: |
353+
$tag = "$env:GITHUB_REF_NAME"
354+
if (-not $tag.StartsWith("v")) {
355+
$tag = "${{ github.event.inputs.tag || 'v0.0.2-electron' }}"
356+
}
357+
"tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
358+
359+
- name: Build Electron package (Windows)
360+
run: npm run electron:build:win -- --publish=never
361+
env:
362+
npm_package_version: ${{ steps.tag.outputs.tag }}
363+
364+
- name: Upload Windows artifacts
365+
uses: actions/upload-artifact@v4
366+
with:
367+
name: electron-windows-x64
368+
path: release/**/*.exe
369+
if-no-files-found: warn
370+
retention-days: 7
371+
280372
# ────────────────────────────────────────────────────────────────────────────
281373
# Publish a GitHub Release with all platform artifacts attached.
282374
# ────────────────────────────────────────────────────────────────────────────
283375
publish:
284376
name: Publish GitHub Release
285-
needs: [build-mac, build-linux]
377+
needs: [build-mac, build-linux, build-windows]
286378
runs-on: ubuntu-latest
287379
permissions:
288380
contents: write
@@ -341,6 +433,7 @@ jobs:
341433
| `*.dmg` | macOS — Apple Silicon (arm64) |
342434
| `*.AppImage` | Linux — x86_64 (portable, any distro) |
343435
| `*.snap` | Linux — x86_64 (Snap Store / snapd) |
436+
| `*.exe` | Windows — x86_64 (NSIS installer) |
344437
345438
346439
- name: Upload to release
@@ -352,4 +445,5 @@ jobs:
352445
release-artifacts/*.snap \
353446
release-artifacts/*.AppImage \
354447
release-artifacts/*.dmg \
448+
release-artifacts/*.exe \
355449
--clobber

electron/main.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
* ─────────────────
66
* 1. ensureDirs() create user-space directories
77
* 2. setupLibraryPaths() set LD_LIBRARY_PATH (Linux) / DYLD_LIBRARY_PATH
8-
* (macOS) to BIN_DIR so that ace-lm / ace-synth
9-
* child processes find their shared libraries.
10-
* Linux ELFs have a hardcoded RUNPATH to the CI
11-
* build tree; macOS dylibs use versioned install
12-
* names — both need the env var override.
8+
* (macOS) / PATH (Windows) to BIN_DIR so that
9+
* ace-lm / ace-synth child processes find their
10+
* shared libraries. Linux ELFs have a hardcoded
11+
* RUNPATH to the CI build tree; macOS dylibs use
12+
* versioned install names; Windows DLLs are found
13+
* via PATH — all need the env var override.
1314
* 3. fixSonameLinks() Linux only: archive ships libggml.so /
1415
* libggml-base.so (unversioned) but ELFs link
1516
* against libggml.so.0 / libggml-base.so.0 —
@@ -138,6 +139,11 @@ function ensureDirs () {
138139
* the bundled libraries are found regardless of what paths were baked in
139140
* at compile time. DYLD_FALLBACK_LIBRARY_PATH is set as an additional
140141
* safety net for transitive dylib-to-dylib dependencies.
142+
*
143+
* Windows: DLLs must be in the same directory as the executable or in a
144+
* directory listed in PATH. Since both the .exe binaries and the bundled
145+
* .dll files all live in BIN_DIR, we prepend BIN_DIR to PATH so that every
146+
* child process spawned by the Express server can resolve the DLLs.
141147
*/
142148
function setupLibraryPaths () {
143149
if (!fs.existsSync(BIN_DIR)) return;
@@ -151,6 +157,9 @@ function setupLibraryPaths () {
151157
// Also set DYLD_FALLBACK_LIBRARY_PATH as an extra safety net
152158
const prev2 = process.env.DYLD_FALLBACK_LIBRARY_PATH || '';
153159
process.env.DYLD_FALLBACK_LIBRARY_PATH = prev2 ? `${BIN_DIR}:${prev2}` : BIN_DIR;
160+
} else if (process.platform === 'win32') {
161+
const prev = process.env.PATH || '';
162+
process.env.PATH = prev ? `${BIN_DIR};${prev}` : BIN_DIR;
154163
}
155164
}
156165

0 commit comments

Comments
 (0)