Skip to content

Commit eb43963

Browse files
committed
Build Linux releases with musl target
1 parent 81f398a commit eb43963

4 files changed

Lines changed: 63 additions & 8 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ jobs:
4242
working-directory: frontend
4343
run: npm run build
4444

45+
- name: Test release packaging script
46+
run: node --test scripts/package-release.test.mjs
47+
4548
- name: Test backend
4649
working-directory: backend
4750
run: cargo test

.github/workflows/release.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ jobs:
3131
- package: linux_amd64
3232
platform: linux
3333
os: ubuntu-latest
34+
rust_target: x86_64-unknown-linux-musl
3435
asset: dist/*.tar.gz
3536
- package: linux_arm64
3637
platform: linux
3738
os: ubuntu-24.04-arm
39+
rust_target: aarch64-unknown-linux-musl
3840
asset: dist/*.tar.gz
3941

4042
runs-on: ${{ matrix.os }}
@@ -53,12 +55,21 @@ jobs:
5355
- name: Setup Rust
5456
uses: dtolnay/rust-toolchain@stable
5557

58+
- name: Install Rust target
59+
if: matrix.platform == 'linux'
60+
run: rustup target add ${{ matrix.rust_target }}
61+
62+
- name: Install Linux musl toolchain
63+
if: matrix.platform == 'linux'
64+
run: sudo apt-get update && sudo apt-get install -y musl-tools
65+
5666
- name: Build package
5767
run: node scripts/package-release.mjs
5868
env:
5969
VERSION: ${{ github.ref_type == 'tag' && github.ref_name || '0.1.0' }}
6070
RELEASE_PLATFORM: ${{ matrix.platform }}
6171
RELEASE_PACKAGE_SUFFIX: ${{ matrix.package }}
72+
CARGO_BUILD_TARGET: ${{ matrix.rust_target }}
6273

6374
- name: Upload release assets
6475
uses: softprops/action-gh-release@v2

scripts/package-release.mjs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { mkdir, rm, cp, chmod, writeFile } from 'node:fs/promises'
22
import { basename, dirname, join, resolve } from 'node:path'
3-
import { fileURLToPath } from 'node:url'
3+
import { fileURLToPath, pathToFileURL } from 'node:url'
44
import { spawnSync } from 'node:child_process'
55

6-
const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), '..')
6+
export const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), '..')
77
const appName = 'log-search'
88
const version = (process.env.VERSION || '0.1.0').replace(/^v/, '')
99
const platform = process.env.RELEASE_PLATFORM || process.platform
1010
const arch = process.env.RELEASE_ARCH || normalizedArch(process.arch)
1111
const packageSuffix = process.env.RELEASE_PACKAGE_SUFFIX || `${platform}-${arch}`
12+
const cargoTarget = process.env.CARGO_BUILD_TARGET || ''
1213
const distDir = join(rootDir, 'dist')
1314
const releaseName = `${appName}_${version}_${packageSuffix}`
1415
const releaseDir = join(distDir, releaseName)
@@ -31,6 +32,20 @@ function run(command, args, options = {}) {
3132
}
3233
}
3334

35+
export function cargoBuildArgs(target = cargoTarget) {
36+
const args = ['build', '--release']
37+
if (target) {
38+
args.push('--target', target)
39+
}
40+
return args
41+
}
42+
43+
export function cargoReleaseDir(target = cargoTarget) {
44+
return target
45+
? join(rootDir, 'backend', 'target', target, 'release')
46+
: join(rootDir, 'backend', 'target', 'release')
47+
}
48+
3449
async function copyIfExists(source, target) {
3550
try {
3651
await cp(source, target, { recursive: true })
@@ -46,11 +61,11 @@ async function build() {
4661

4762
run('npm', ['ci'], { cwd: join(rootDir, 'frontend') })
4863
run('npm', ['run', 'build'], { cwd: join(rootDir, 'frontend') })
49-
run('cargo', ['build', '--release'], { cwd: join(rootDir, 'backend') })
64+
run('cargo', cargoBuildArgs(), { cwd: join(rootDir, 'backend') })
5065

5166
const binaryName = platform === 'windows' ? `${appName}.exe` : appName
5267
const builtBinaryName = platform === 'windows' ? 'backend.exe' : 'backend'
53-
await cp(join(rootDir, 'backend', 'target', 'release', builtBinaryName), join(releaseDir, binaryName))
68+
await cp(join(cargoReleaseDir(), builtBinaryName), join(releaseDir, binaryName))
5469
await cp(join(rootDir, 'frontend', 'dist'), join(releaseDir, 'frontend'), { recursive: true })
5570
await cp(join(rootDir, 'config.example.toml'), join(releaseDir, 'config.toml'))
5671
await cp(join(rootDir, 'packaging', 'README.txt'), join(releaseDir, 'README.txt'))
@@ -116,7 +131,9 @@ async function createTarGzArchive() {
116131
return archivePath
117132
}
118133

119-
build().catch((error) => {
120-
console.error(error)
121-
process.exit(1)
122-
})
134+
if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
135+
build().catch((error) => {
136+
console.error(error)
137+
process.exit(1)
138+
})
139+
}

scripts/package-release.test.mjs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import assert from 'node:assert/strict'
2+
import { test } from 'node:test'
3+
import { join } from 'node:path'
4+
import { cargoBuildArgs, cargoReleaseDir, rootDir } from './package-release.mjs'
5+
6+
test('cargoBuildArgs builds default release binary without a target', () => {
7+
assert.deepEqual(cargoBuildArgs(''), ['build', '--release'])
8+
})
9+
10+
test('cargoBuildArgs adds the configured Rust target', () => {
11+
assert.deepEqual(cargoBuildArgs('x86_64-unknown-linux-musl'), [
12+
'build',
13+
'--release',
14+
'--target',
15+
'x86_64-unknown-linux-musl',
16+
])
17+
})
18+
19+
test('cargoReleaseDir reads target-specific release binaries when cross compiling', () => {
20+
assert.equal(
21+
cargoReleaseDir('x86_64-unknown-linux-musl'),
22+
join(rootDir, 'backend', 'target', 'x86_64-unknown-linux-musl', 'release'),
23+
)
24+
})

0 commit comments

Comments
 (0)