-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathbuild-rust.sh
More file actions
executable file
·166 lines (137 loc) · 5.79 KB
/
build-rust.sh
File metadata and controls
executable file
·166 lines (137 loc) · 5.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
RUST_DIR="$SCRIPT_DIR/phemy-core"
DEPS_DIR="$RUST_DIR/target/release/deps"
echo "==> Building phemy-core Rust library..."
export PATH="$HOME/.cargo/bin:$PATH"
export CXXFLAGS="-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1"
cd "$RUST_DIR"
# ===========================================================================
# Optional: Audit Rust dependencies for known vulnerabilities
# ===========================================================================
if command -v cargo-audit &> /dev/null; then
echo "==> Running cargo audit..."
cargo audit --deny warnings || echo "WARNING: cargo audit found issues (see above)"
else
echo " (cargo audit not installed — run 'cargo install cargo-audit' for dependency security checks)"
fi
# ===========================================================================
# Pass 1: Normal build — produces all rlibs including whisper-rs-sys
# ===========================================================================
cargo build --release
# ===========================================================================
# Fix ggml symbol conflict between whisper-rs-sys and llama-cpp-sys-2.
#
# Both crates bundle their own ggml (ABI-incompatible versions) and embed
# native .o files into their rlibs. When linked into the cdylib, the linker
# resolves duplicate ggml symbols to ONE copy, causing the other crate to
# crash (wrong ABI).
#
# Fix: Use `ld -r -unexported_symbols_list` to pre-link whisper's native
# objects into a single merged .o with ggml/gguf symbols made private.
# Whisper uses its own (local) ggml; llama uses its own (global) ggml.
# ===========================================================================
localize_ggml_in_whisper_rlib() {
local rlib="$1"
local work_dir="$2"
echo " Checking $(basename "$rlib")..."
# List rlib members
local members
members=$(ar t "$rlib")
# Check if already merged (idempotent)
if echo "$members" | grep -q "^whisper_merged\.o$"; then
echo " Already merged, skipping."
return 1 # Signal no modification
fi
# Find native C/C++ objects (not Rust codegen units which have .rcgu.o)
local native_objects=()
while IFS= read -r member; do
case "$member" in
*.c.o) native_objects+=("$member") ;;
*.cpp.o)
if [[ "$member" != *rcgu* ]]; then
native_objects+=("$member")
fi
;;
esac
done <<< "$members"
if [ ${#native_objects[@]} -eq 0 ]; then
echo " No native objects found, skipping."
return 1
fi
echo " Found ${#native_objects[@]} native objects: ${native_objects[*]}"
local merge_dir="$work_dir/whisper_merge"
mkdir -p "$merge_dir"
# Extract native .o files
(cd "$merge_dir" && ar x "$rlib" "${native_objects[@]}")
# Build paths for extracted objects
local obj_paths=()
for obj in "${native_objects[@]}"; do
obj_paths+=("$merge_dir/$obj")
done
# Write unexported symbols list (ggml/gguf become private)
local unexport_file="$merge_dir/ggml_unexport.txt"
printf '_ggml_*\n_gguf_*\n' > "$unexport_file"
# Pre-link into single relocatable object with ggml symbols made private
local merged="$merge_dir/whisper_merged.o"
echo " Running ld -r -unexported_symbols_list..."
/usr/bin/ld -r \
-unexported_symbols_list "$unexport_file" \
-o "$merged" \
"${obj_paths[@]}"
# Verify ggml symbols are now local
local global_ggml
global_ggml=$(nm -gU "$merged" 2>/dev/null | grep -c "^.* [TSD] _ggml_" || true)
echo " Global ggml symbols remaining: $global_ggml (should be 0 or near 0)"
# Remove original native .o files from rlib
for obj in "${native_objects[@]}"; do
ar d "$rlib" "$obj"
done
# Add merged object
ar r "$rlib" "$merged"
ranlib "$rlib"
echo " Done! Merged ${#native_objects[@]} objects into whisper_merged.o"
return 0 # Signal modification was made
}
RLIB_MODIFIED=false
for rlib in "$DEPS_DIR"/libwhisper_rs_sys-*.rlib; do
[ -f "$rlib" ] || continue
work_dir=$(mktemp -d)
if localize_ggml_in_whisper_rlib "$rlib" "$work_dir"; then
RLIB_MODIFIED=true
fi
rm -rf "$work_dir"
done
# ===========================================================================
# Pass 2: Re-link the cdylib with the modified rlib
# ===========================================================================
if [ "$RLIB_MODIFIED" = true ]; then
echo "==> Re-linking cdylib with localized ggml symbols..."
# Touch lib.rs to force cargo to re-link the cdylib
touch "$RUST_DIR/src/lib.rs"
cargo build --release
fi
# Generate C header with cbindgen
if command -v cbindgen &> /dev/null; then
echo "==> Generating C header with cbindgen..."
cbindgen --config cbindgen.toml --crate phemy-core --output include/phemy_core.h
else
echo "WARNING: cbindgen not installed. Run: cargo install cbindgen"
echo "Using existing header if available."
fi
# Copy the dylib to project root
DYLIB_PATH="$RUST_DIR/target/release/libphemy_core.dylib"
if [ -f "$DYLIB_PATH" ]; then
cp "$DYLIB_PATH" "$SCRIPT_DIR/libphemy_core.dylib"
# Set the install name to absolute path for development.
install_name_tool -id "$SCRIPT_DIR/libphemy_core.dylib" "$SCRIPT_DIR/libphemy_core.dylib" 2>/dev/null \
&& codesign -f -s - "$SCRIPT_DIR/libphemy_core.dylib" 2>/dev/null \
|| echo " (install_name_tool skipped — using build path as install name)"
echo "==> Copied libphemy_core.dylib to project root"
else
echo "ERROR: libphemy_core.dylib not found at $DYLIB_PATH"
exit 1
fi
echo "==> Done! Library: $SCRIPT_DIR/libphemy_core.dylib"
echo "==> Header: $RUST_DIR/include/phemy_core.h"