fix release mode link path in final elf output
This commit is contained in:
parent
15522c41a8
commit
d6cab46c99
3 changed files with 86 additions and 2 deletions
15
README.md
15
README.md
|
@ -20,6 +20,7 @@ The application uses ALSA's default device, which is configured in `alsa.conf`.
|
|||
### Prerequisites
|
||||
- Zig 0.15.1 (configured via mise)
|
||||
- Nix development environment configured for ALSA, and audio libraries
|
||||
- patchelf (for fixing RPATH in release builds): `nix-env -iA nixpkgs.patchelf`
|
||||
|
||||
### Vosk Model Download
|
||||
The application uses the Vosk small English model for speech recognition:
|
||||
|
@ -33,6 +34,20 @@ The application uses the Vosk small English model for speech recognition:
|
|||
2. Build application: `zig build`
|
||||
3. Run: `zig build run`
|
||||
|
||||
### Release Builds and Portability
|
||||
|
||||
When building in release mode (`-Doptimize=ReleaseSafe`), Zig embeds the full path to libvosk.so in the ELF NEEDED entries, making the binary non-portable. The build system automatically fixes this by running `fix_needed.sh` which uses `patchelf` to replace the full path with just the library name.
|
||||
|
||||
**Automatic fix**: Just run `zig build -Doptimize=ReleaseSafe` - the NEEDED entries are fixed automatically.
|
||||
|
||||
**Manual fix**: If needed, you can run `./fix_needed.sh [binary_path] [library_name]` manually.
|
||||
|
||||
The script uses `patchelf` (via nix-shell if not installed) to replace entries like:
|
||||
- Before: `NEEDED: [/home/user/.cache/zig/.../libvosk.so]`
|
||||
- After: `NEEDED: [libvosk.so]`
|
||||
|
||||
This makes the binary portable while using the existing RPATH (`$ORIGIN/../lib`) to find the library at runtime.
|
||||
|
||||
## Usage
|
||||
The application will:
|
||||
- Initialize audio capture from default microphone
|
||||
|
|
18
build.zig
18
build.zig
|
@ -32,7 +32,7 @@ pub fn build(b: *std.Build) void {
|
|||
// Create the STT library
|
||||
const stt_lib = b.addLibrary(.{
|
||||
.name = "stt",
|
||||
.linkage = .static,
|
||||
// .linkage = .static,
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/stt.zig"),
|
||||
.target = target,
|
||||
|
@ -73,7 +73,21 @@ pub fn build(b: *std.Build) void {
|
|||
exe.addLibraryPath(vosk_dep.path(""));
|
||||
exe.linkSystemLibrary("vosk");
|
||||
|
||||
b.installArtifact(exe);
|
||||
const install_exe = b.addInstallArtifact(exe, .{});
|
||||
|
||||
// Fix NEEDED entries in release builds to make binary portable
|
||||
if (optimize != .Debug) {
|
||||
const script_path = b.pathFromRoot("fix_needed.sh");
|
||||
const fix_needed = b.addSystemCommand(&.{script_path});
|
||||
fix_needed.step.dependOn(&install_exe.step);
|
||||
_ = fix_needed.captureStdOut();
|
||||
b.getInstallStep().dependOn(&fix_needed.step);
|
||||
|
||||
const fix_step = b.step("fix-needed", "Fix NEEDED entries to make binary portable");
|
||||
fix_step.dependOn(&fix_needed.step);
|
||||
} else {
|
||||
b.getInstallStep().dependOn(&install_exe.step);
|
||||
}
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
|
|
55
fix_needed.sh
Executable file
55
fix_needed.sh
Executable file
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash
|
||||
# Fix NEEDED entries in release builds
|
||||
# This script replaces full paths with just library names in NEEDED entries
|
||||
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
echo "Usage: $0 [binary_path] [library_name]"
|
||||
echo " binary_path: Path to binary (default: script_dir/zig-out/bin/stt)"
|
||||
echo " library_name: Library to fix (default: libvosk.so)"
|
||||
echo ""
|
||||
echo "Example: $0 my_binary libfoo.so"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BINARY="${1:-$SCRIPT_DIR/zig-out/bin/stt}"
|
||||
LIBRARY="${2:-libvosk.so}"
|
||||
|
||||
if [ ! -f "$BINARY" ]; then
|
||||
echo "Binary not found: $BINARY" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Fixing NEEDED entries for $BINARY..."
|
||||
|
||||
# Get the current NEEDED entries
|
||||
if command -v readelf >/dev/null 2>&1; then
|
||||
FULL_PATH=$(readelf --dynamic "$BINARY" | grep "NEEDED" | grep "$LIBRARY" | head -1 | sed 's/.*\[\(.*\)\]/\1/')
|
||||
elif command -v nix-shell >/dev/null 2>&1; then
|
||||
echo "Using nix-shell to run readelf..."
|
||||
FULL_PATH=$(nix-shell -p binutils --run "readelf --dynamic '$BINARY'" | grep "NEEDED" | grep "$LIBRARY" | head -1 | sed 's/.*\[\(.*\)\]/\1/')
|
||||
else
|
||||
echo "Error: Neither readelf nor nix-shell found" >&2
|
||||
echo "Install binutils or nix to check NEEDED entries" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$FULL_PATH" == *"/"* ]]; then
|
||||
echo "Found full path: $FULL_PATH"
|
||||
echo "Replacing with: $LIBRARY"
|
||||
|
||||
# Try patchelf directly, fall back to nix-shell
|
||||
if command -v patchelf >/dev/null 2>&1; then
|
||||
patchelf --replace-needed "$FULL_PATH" "$LIBRARY" "$BINARY"
|
||||
elif command -v nix-shell >/dev/null 2>&1; then
|
||||
echo "Using nix-shell to run patchelf..."
|
||||
nix-shell -p patchelf --run "patchelf --replace-needed '$FULL_PATH' '$LIBRARY' '$BINARY'"
|
||||
else
|
||||
echo "Error: Neither patchelf nor nix-shell found" >&2
|
||||
echo "Install patchelf or nix to fix NEEDED entries" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Fixed!"
|
||||
else
|
||||
echo "No full path found, binary is already portable"
|
||||
fi
|
Loading…
Add table
Reference in a new issue