Skip to content

Commit 712c13c

Browse files
committed
Improve Linux build stability and model download robustness
Cross-platform build improvements: - Add Linux-specific linker configuration in Cargo config - Use bundled whisper-rs-sys bindings to avoid libclang/libLLVM coupling - Update .envrc for better cross-platform compiler detection - Add ELF interpreter patching in build.sh for Nix-built binaries Model downloader improvements: - Add atomic file operations with temp file cleanup - Implement proper checksum verification with error recovery - Add retry logic with exponential backoff for failed downloads - Clean up stale temporary files before new downloads - Verify models exist before listing as downloaded These changes ensure stable builds across different Linux environments (Nix, system, mixed) and more reliable model downloads. Fix Windows build by making WHISPER_DONT_GENERATE_BINDINGS target-specific The WHISPER_DONT_GENERATE_BINDINGS flag was set globally, causing whisper-rs-sys to use bundled (Linux) bindings on Windows, which led to compilation errors due to platform-specific struct size mismatches. Now only Linux and macOS targets use bundled bindings, while Windows generates bindings at build time as intended. Fix CI builds by setting WHISPER_DONT_GENERATE_BINDINGS env var The target-specific environment variables in .cargo/config.toml only apply when building with explicit --target flags. CI builds without --target flags don't pick up these settings, causing whisper-rs-sys to try building from source and fail. Solution: Set WHISPER_DONT_GENERATE_BINDINGS=1 as an environment variable in the CI and release workflows for Linux and macOS. Windows correctly generates bindings at build time and doesn't need this flag. Fix CI cache issue preventing WHISPER_DONT_GENERATE_BINDINGS from taking effect - Update cache key from v1 to v2 to bust old cache - Add explicit cargo clean -p whisper-rs-sys to force rebuild with correct env - This ensures whisper-rs-sys uses bundled bindings instead of building from source fix Fix TUI default model to use ggml-base.en without .bin extension The TUI was using 'ggml-base.en.bin' as the default model path, but the model registry and Rust code use model IDs without file extensions (e.g., 'ggml-base.en'). This caused the TUI to create configs with incorrect model paths. Now matches the Rust default in src/config.rs Adding readme and uninstall for windows
1 parent 9b90337 commit 712c13c

File tree

13 files changed

+772
-237
lines changed

13 files changed

+772
-237
lines changed

.cargo/config.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
[target.aarch64-apple-darwin]
22
linker = "/usr/bin/clang"
33

4+
[target.x86_64-unknown-linux-gnu]
5+
linker = "/usr/bin/cc"
6+
47
[target.x86_64-apple-darwin]
58
linker = "/usr/bin/clang"
69

@@ -13,3 +16,18 @@ CC_x86_64_apple_darwin = "/usr/bin/clang"
1316
CXX_x86_64_apple_darwin = "/usr/bin/clang++"
1417
# Disable BLAS in whisper.cpp to avoid symbol mismatch with macOS Accelerate framework
1518
GGML_BLAS = "OFF"
19+
20+
# Use bundled whisper-rs-sys bindings on Linux/macOS to avoid runtime libclang/libLLVM coupling.
21+
# This keeps builds stable across Linux/macOS (including mixed Nix/system shells).
22+
# Windows generates bindings at build time, so don't set this there.
23+
[target.x86_64-unknown-linux-gnu.env]
24+
WHISPER_DONT_GENERATE_BINDINGS = "1"
25+
26+
[target.aarch64-unknown-linux-gnu.env]
27+
WHISPER_DONT_GENERATE_BINDINGS = "1"
28+
29+
[target.aarch64-apple-darwin.env]
30+
WHISPER_DONT_GENERATE_BINDINGS = "1"
31+
32+
[target.x86_64-apple-darwin.env]
33+
WHISPER_DONT_GENERATE_BINDINGS = "1"

.envrc

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,36 @@
1-
# macOS SDK path for linking
2-
export SDKROOT=$(xcrun --show-sdk-path)
3-
export LIBRARY_PATH="/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib:${LIBRARY_PATH:-}"
1+
# Cross-platform compiler/tooling environment.
2+
# Keep per-OS logic isolated so local shell setup does not break other targets.
43

5-
# Force use of system clang instead of GCC (important for macOS)
6-
export CC=clang
7-
export CXX=clang++
4+
case "$(uname -s)" in
5+
Darwin)
6+
# macOS SDK path for linking
7+
if command -v xcrun >/dev/null 2>&1; then
8+
export SDKROOT="$(xcrun --show-sdk-path)"
9+
export LIBRARY_PATH="/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib:${LIBRARY_PATH:-}"
10+
fi
11+
12+
# Prefer clang toolchain on macOS
13+
export CC=clang
14+
export CXX=clang++
15+
;;
16+
Linux)
17+
# Prefer clang toolchain on Linux as well (used by native deps / CMake).
18+
if command -v clang >/dev/null 2>&1; then
19+
export CC=clang
20+
fi
21+
if command -v clang++ >/dev/null 2>&1; then
22+
export CXX=clang++
23+
fi
24+
25+
# Optional hint for bindgen-based crates.
26+
# onevox uses bundled whisper bindings in Cargo config, so libclang is not required.
27+
if command -v llvm-config >/dev/null 2>&1; then
28+
_llvm_libdir="$(llvm-config --libdir 2>/dev/null || true)"
29+
if [ -n "${_llvm_libdir}" ] && [ -d "${_llvm_libdir}" ]; then
30+
export LIBCLANG_PATH="${_llvm_libdir}"
31+
fi
32+
elif [ -d /usr/lib ]; then
33+
export LIBCLANG_PATH="/usr/lib"
34+
fi
35+
;;
36+
esac

.github/workflows/ci.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
uses: actions/cache@v4
4444
with:
4545
path: target
46-
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
46+
key: ${{ runner.os }}-cargo-build-target-v2-${{ hashFiles('**/Cargo.lock') }}
4747

4848
- name: Install Linux system dependencies
4949
if: runner.os == 'Linux'
@@ -58,13 +58,21 @@ jobs:
5858
libxfixes-dev \
5959
libxi-dev \
6060
libxtst-dev
61+
# Use bundled whisper-rs-sys bindings on Linux
62+
echo "WHISPER_DONT_GENERATE_BINDINGS=1" >> $GITHUB_ENV
63+
# Clean whisper-rs-sys to ensure it rebuilds with correct env
64+
cargo clean -p whisper-rs-sys || true
6165
6266
- name: Set whisper.cpp build flags for macOS
6367
if: runner.os == 'macOS'
6468
run: |
6569
# Use generic ARM64 target instead of native to avoid i8mm issues on CI
6670
echo "CFLAGS=-march=armv8-a" >> $GITHUB_ENV
6771
echo "CXXFLAGS=-march=armv8-a" >> $GITHUB_ENV
72+
# Use bundled whisper-rs-sys bindings on macOS
73+
echo "WHISPER_DONT_GENERATE_BINDINGS=1" >> $GITHUB_ENV
74+
# Clean whisper-rs-sys to ensure it rebuilds with correct env
75+
cargo clean -p whisper-rs-sys || true
6876
6977
- name: Check formatting
7078
run: cargo fmt --all -- --check

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
CC=clang CXX=clang++ \
5050
SDKROOT=$(xcrun --show-sdk-path) \
5151
MACOSX_DEPLOYMENT_TARGET=13.0 \
52+
WHISPER_DONT_GENERATE_BINDINGS=1 \
5253
cargo build --release --locked --target ${{ matrix.target }} $FEATURES
5354
5455
- name: Create app bundle
@@ -100,6 +101,8 @@ jobs:
100101
uses: dtolnay/rust-toolchain@stable
101102

102103
- name: Build release binary
104+
env:
105+
WHISPER_DONT_GENERATE_BINDINGS: "1"
103106
run: cargo build --release --locked
104107

105108
- name: Strip binary

DEVELOPMENT.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ cargo build --release --features onnx
8888
./build.sh release # Release
8989
```
9090

91+
`build.sh` is a build wrapper for consistent local/release builds across platforms.
92+
93+
- It configures platform-specific build environment before calling Cargo.
94+
- On Linux, it auto-patches the ELF interpreter when binaries are linked against a Nix loader path, preventing runtime failures like missing `libxcb.so.1` on non-Nix userland.
95+
- It is recommended for developer and release candidate builds, especially on mixed Nix/system environments.
96+
97+
For production releases, keep using CI per target OS and artifact verification/signing in addition to `build.sh`.
98+
9199
### GPU Acceleration
92100

93101
OneVox supports GPU acceleration for whisper.cpp backend:
@@ -237,11 +245,13 @@ CC=clang CXX=clang++ SDKROOT=$(xcrun --show-sdk-path) MACOSX_DEPLOYMENT_TARGET=1
237245
cargo build --release --locked --features onnx
238246

239247
# Linux - Default
240-
cargo build --release --locked
248+
./build.sh release
241249
strip target/release/onevox
242250

243251
# Linux - With ONNX
244252
cargo build --release --locked --features onnx
253+
# If built from a Nix shell and run on system userland, patch interpreter:
254+
# patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 target/release/onevox
245255
strip target/release/onevox
246256

247257
# Windows - Default

INSTALLATION.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,3 +409,131 @@ preload = true
409409
```
410410

411411
See [DEVELOPMENT.md](DEVELOPMENT.md) for detailed build instructions and troubleshooting.
412+
413+
---
414+
415+
## Uninstall
416+
417+
### macOS
418+
419+
**Quick Uninstall:**
420+
```bash
421+
curl -fsSL https://raw.githubusercontent.com/kssgarcia/onevox/main/scripts/uninstall_macos.sh | bash
422+
```
423+
424+
**Manual Uninstall:**
425+
```bash
426+
# Stop launchd service
427+
launchctl bootout "gui/$(id -u)" ~/Library/LaunchAgents/com.onevox.daemon.plist
428+
429+
# Remove service file
430+
rm -f ~/Library/LaunchAgents/com.onevox.daemon.plist
431+
432+
# Remove application
433+
rm -rf ~/Applications/Onevox.app
434+
rm -rf /Applications/Onevox.app # If installed system-wide
435+
436+
# Remove CLI symlinks
437+
rm -f /usr/local/bin/onevox
438+
rm -f /opt/homebrew/bin/onevox
439+
rm -f ~/.local/bin/onevox
440+
441+
# Remove config and data
442+
rm -rf ~/Library/Application\ Support/com.onevox.onevox
443+
rm -rf ~/Library/Caches/com.onevox.onevox
444+
rm -rf ~/Library/Logs/onevox
445+
```
446+
447+
---
448+
449+
### Linux
450+
451+
**Quick Uninstall:**
452+
```bash
453+
curl -fsSL https://raw.githubusercontent.com/kssgarcia/onevox/main/scripts/uninstall_linux.sh | bash
454+
```
455+
456+
**Manual Uninstall:**
457+
```bash
458+
# Stop and disable service
459+
systemctl --user stop onevox.service
460+
systemctl --user disable onevox.service
461+
462+
# Remove service file
463+
rm -f ~/.config/systemd/user/onevox.service
464+
systemctl --user daemon-reload
465+
466+
# Remove binary
467+
rm -f ~/.local/bin/onevox
468+
469+
# Remove desktop entry
470+
rm -f ~/.local/share/applications/onevox.desktop
471+
update-desktop-database ~/.local/share/applications 2>/dev/null || true
472+
473+
# Remove config and data
474+
rm -rf ~/.config/onevox
475+
rm -rf ~/.local/share/onevox
476+
rm -rf ~/.cache/onevox
477+
```
478+
479+
---
480+
481+
### Windows
482+
483+
**Quick Uninstall:**
484+
```powershell
485+
# Download and run uninstall script
486+
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/kssgarcia/onevox/main/scripts/uninstall_windows.ps1" -OutFile uninstall_windows.ps1
487+
.\uninstall_windows.ps1
488+
```
489+
490+
**Options:**
491+
```powershell
492+
# Keep configuration files
493+
.\uninstall_windows.ps1 -KeepConfig
494+
495+
# Skip confirmation prompt
496+
.\uninstall_windows.ps1 -Force
497+
498+
# Both options
499+
.\uninstall_windows.ps1 -KeepConfig -Force
500+
```
501+
502+
**Manual Uninstall:**
503+
```powershell
504+
# Stop and remove service (run as Administrator)
505+
sc.exe stop Onevox
506+
sc.exe delete Onevox
507+
508+
# Remove from PATH (requires reopening PowerShell after)
509+
$userPath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::User)
510+
$newPath = ($userPath -split ';' | Where-Object { $_ -ne "$env:LOCALAPPDATA\onevox" }) -join ';'
511+
[Environment]::SetEnvironmentVariable("Path", $newPath, [EnvironmentVariableTarget]::User)
512+
513+
# Remove files and directories
514+
Remove-Item -Path "$env:LOCALAPPDATA\onevox" -Recurse -Force
515+
Remove-Item -Path "$env:APPDATA\onevox" -Recurse -Force
516+
```
517+
518+
---
519+
520+
## What Gets Removed
521+
522+
The uninstaller removes the following on all platforms:
523+
524+
**Binaries:**
525+
- Application executable
526+
- CLI tools and symlinks
527+
528+
**Services:**
529+
- System service/daemon registration
530+
- LaunchAgent (macOS) / systemd service (Linux) / Windows Service
531+
532+
**Data:**
533+
- Configuration files
534+
- Downloaded models (can be large, ~100MB-3GB)
535+
- Transcription history
536+
- Application logs
537+
- Cache files
538+
539+
**Note:** On Windows, use the `-KeepConfig` flag to preserve your configuration and downloaded models if you plan to reinstall later.

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,37 @@ Backend selection is automatic based on model choice (see Configuration below).
9696

9797
For pre-built binaries, see the [Releases](https://github.com/kssgarcia/onevox/releases) page.
9898

99+
### Uninstall
100+
101+
**macOS**
102+
```bash
103+
curl -fsSL https://raw.githubusercontent.com/kssgarcia/onevox/main/scripts/uninstall_macos.sh | bash
104+
```
105+
106+
**Linux**
107+
```bash
108+
curl -fsSL https://raw.githubusercontent.com/kssgarcia/onevox/main/scripts/uninstall_linux.sh | bash
109+
```
110+
111+
**Windows**
112+
```powershell
113+
# Download and run the uninstall script
114+
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/kssgarcia/onevox/main/scripts/uninstall_windows.ps1" -OutFile uninstall_windows.ps1
115+
.\uninstall_windows.ps1
116+
117+
# To keep your config file
118+
.\uninstall_windows.ps1 -KeepConfig
119+
120+
# To skip confirmation prompt
121+
.\uninstall_windows.ps1 -Force
122+
```
123+
124+
The uninstaller removes:
125+
- All binaries and executables
126+
- Service/daemon registrations
127+
- Application data and cache
128+
- Configuration files (unless `-KeepConfig` is used on Windows)
129+
99130
## Quick Start
100131

101132
1. Install OneVox using the command above

build.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,39 @@ GREEN='\033[0;32m'
1010
YELLOW='\033[1;33m'
1111
NC='\033[0m' # No Color
1212

13+
patch_linux_interpreter() {
14+
local binary_path="$1"
15+
16+
# Only relevant on Linux for ELF binaries.
17+
if [ "$(uname -s)" != "Linux" ] || [ ! -f "$binary_path" ]; then
18+
return
19+
fi
20+
21+
if ! command -v readelf >/dev/null 2>&1 || ! command -v patchelf >/dev/null 2>&1; then
22+
return
23+
fi
24+
25+
local current_interp=""
26+
current_interp="$(readelf -l "$binary_path" 2>/dev/null | sed -n 's/.*Requesting program interpreter: \(.*\)]/\1/p' | head -n1)"
27+
28+
# Nix-linked binaries can fail to resolve transitive system libs outside nix env.
29+
if [[ "$current_interp" == /nix/store/* ]]; then
30+
local system_interp=""
31+
if [ -x /lib64/ld-linux-x86-64.so.2 ]; then
32+
system_interp="/lib64/ld-linux-x86-64.so.2"
33+
elif [ -x /usr/lib64/ld-linux-x86-64.so.2 ]; then
34+
system_interp="/usr/lib64/ld-linux-x86-64.so.2"
35+
fi
36+
37+
if [ -n "$system_interp" ]; then
38+
echo -e "${YELLOW}Patching Linux ELF interpreter:${NC} $current_interp -> $system_interp"
39+
patchelf --set-interpreter "$system_interp" "$binary_path"
40+
else
41+
echo -e "${YELLOW}Warning:${NC} binary uses Nix interpreter ($current_interp), but no system ld-linux was found to patch."
42+
fi
43+
fi
44+
}
45+
1346
# Detect platform
1447
OS="$(uname -s)"
1548
ARCH="$(uname -m)"
@@ -107,6 +140,8 @@ if [ $BUILD_STATUS -eq 0 ]; then
107140
fi
108141

109142
if [ -f "$BINARY_PATH" ]; then
143+
patch_linux_interpreter "$BINARY_PATH"
144+
110145
BINARY_SIZE=$(du -h "$BINARY_PATH" | cut -f1)
111146
echo "Binary: $BINARY_PATH ($BINARY_SIZE)"
112147
echo ""

packaging/linux/onevox.service

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ StandardError=journal
1313

1414
# Resource limits (optional, can be adjusted per system)
1515
MemoryMax=2G
16-
CPUQuota=80%
1716

1817
[Install]
1918
WantedBy=default.target

0 commit comments

Comments
 (0)