Skip to content

Commit 66d5f84

Browse files
authored
Merge pull request #6 from labstreaminglayer/fix/macos-cli-libusb-linkage
Bundle and re-sign libusb for the signed macOS CLI
2 parents 4d07421 + c31cdbc commit 66d5f84

1 file changed

Lines changed: 49 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,16 +218,63 @@ jobs:
218218
./scripts/sign_and_notarize.sh "$APP_PATH" --notarize
219219
fi
220220
221-
# Sign CLI and its bundled lsl.framework
221+
# Sign CLI and its bundled lsl.framework + libusb
222222
CLI_PATH=$(find packages -name "MCCOutletCLI" -type f | head -1)
223223
if [[ -n "$CLI_PATH" ]]; then
224224
CLI_DIR=$(dirname "$CLI_PATH")
225-
# Sign framework first (dependency must be signed before dependent)
225+
mkdir -p "$CLI_DIR/Frameworks"
226+
227+
# -----------------------------------------------------------------
228+
# Bundle libusb next to the CLI, exactly like lsl.framework.
229+
#
230+
# The CLI links libusb by an absolute Homebrew path. Once the CLI
231+
# is Developer-ID signed with the hardened runtime it is subject to
232+
# library validation and may only load dylibs signed by Apple or
233+
# the same Team ID. Homebrew's libusb bottle is signed by a
234+
# different team, so dyld refuses it unconditionally and the signed
235+
# CLI is unrunnable on every machine. Fix: copy libusb in, normalize
236+
# its install name to @rpath (resolved via the CLI's existing
237+
# @executable_path/Frameworks rpath), repoint the CLI, and sign it
238+
# with our identity BEFORE the CLI (dependency before dependent).
239+
# -----------------------------------------------------------------
240+
LIBUSB_DEST="$CLI_DIR/Frameworks/libusb-1.0.0.dylib"
241+
if [[ ! -f "$LIBUSB_DEST" ]]; then
242+
# Prefer the copy macdeployqt already placed in the app bundle,
243+
# otherwise fall back to the reference the CLI currently links
244+
# (brew prefix differs: arm64 /opt/homebrew, x86_64 /usr/local).
245+
APP_LIBUSB=$(find packages -path "*.app/Contents/Frameworks/libusb-1.0.0.dylib" -type f | head -1)
246+
if [[ -n "$APP_LIBUSB" ]]; then
247+
cp "$APP_LIBUSB" "$LIBUSB_DEST"
248+
else
249+
cp "$(otool -L "$CLI_PATH" | awk '/libusb-1\.0\.0\.dylib/{print $1; exit}')" "$LIBUSB_DEST"
250+
fi
251+
chmod u+w "$LIBUSB_DEST"
252+
fi
253+
install_name_tool -id @rpath/libusb-1.0.0.dylib "$LIBUSB_DEST"
254+
255+
# Repoint the CLI from the absolute brew path to the bundled copy.
256+
CLI_LIBUSB_REF=$(otool -L "$CLI_PATH" | awk '/libusb-1\.0\.0\.dylib/{print $1; exit}')
257+
if [[ -n "$CLI_LIBUSB_REF" && "$CLI_LIBUSB_REF" != "@rpath/libusb-1.0.0.dylib" ]]; then
258+
install_name_tool -change "$CLI_LIBUSB_REF" @rpath/libusb-1.0.0.dylib "$CLI_PATH"
259+
fi
260+
261+
# Sign bundled dependencies first (must precede the dependent CLI).
226262
if [[ -d "$CLI_DIR/Frameworks/lsl.framework" ]]; then
227263
codesign --force --sign "$APPLE_CODE_SIGN_IDENTITY_APP" --options runtime \
228264
"$CLI_DIR/Frameworks/lsl.framework"
229265
fi
266+
codesign --force --sign "$APPLE_CODE_SIGN_IDENTITY_APP" --options runtime \
267+
"$LIBUSB_DEST"
268+
230269
./scripts/sign_and_notarize.sh "$CLI_PATH" --notarize
270+
271+
# Guardrail: a signed CLI that still links an absolute brew dylib is
272+
# dead on arrival under library validation. Fail the build instead.
273+
if otool -L "$CLI_PATH" | grep -qE '/(opt/homebrew|usr/local)/'; then
274+
echo "ERROR: signed CLI links non-bundled dylibs:"
275+
otool -L "$CLI_PATH"
276+
exit 1
277+
fi
231278
fi
232279
233280
# -----------------------------------------------------------------------

0 commit comments

Comments
 (0)