5.2 KiB
Homebrew Library Dependencies Issue
Summary
VibeTunnel beta 7 shipped with Homebrew library dependencies, causing the app to fail on systems without Homebrew installed. This document explains the issue, how to identify it, and how to prevent it in future releases.
The Problem
When users without Homebrew installed tried to run VibeTunnel beta 7, they received errors like:
dyld: Library not loaded: /opt/homebrew/opt/brotli/lib/libbrotlidec.1.dylib
Referenced from: /Applications/VibeTunnel.app/Contents/Resources/vibetunnel
Reason: image not found
Binary Dependencies Comparison
Beta 6 (Working) vs Beta 7 (Broken)
| Component | Beta 6 | Beta 7 |
|---|---|---|
| Main App Binary | System frameworks only | System frameworks + Thread Sanitizer |
| vibetunnel Server | System libraries only (106MB) | System + 10 Homebrew libraries (63MB) |
| Frameworks Directory | Clean | Contains libclang_rt.tsan_osx_dynamic.dylib |
Beta 7 Homebrew Dependencies
The vibetunnel server binary in beta 7 linked to these Homebrew libraries:
/opt/homebrew/opt/libuv/lib/libuv.1.dylib
/opt/homebrew/opt/brotli/lib/libbrotlidec.1.dylib
/opt/homebrew/opt/brotli/lib/libbrotlienc.1.dylib
/opt/homebrew/opt/c-ares/lib/libcares.2.dylib
/opt/homebrew/opt/libnghttp2/lib/libnghttp2.14.dylib
/opt/homebrew/opt/openssl@3/lib/libcrypto.3.dylib
/opt/homebrew/opt/openssl@3/lib/libssl.3.dylib
/opt/homebrew/opt/icu4c@77/lib/libicui18n.77.dylib
/opt/homebrew/opt/icu4c@77/lib/libicuuc.77.dylib
Root Cause
The issue was introduced by commit 826d8de4 which added node-path-setup.sh with:
export PATH="/opt/homebrew/bin:/usr/local/bin:..."
This prioritized Homebrew in PATH during the build process, causing:
- Node.js to be built linking against Homebrew libraries
- Native modules (node-pty, authenticate-pam) to link against Homebrew
- The final vibetunnel binary to inherit these dependencies
How to Test for Homebrew Dependencies
Quick Check with otool
Check any binary for Homebrew dependencies:
# Check for Homebrew paths
otool -L /path/to/binary | grep -E "/opt/homebrew|/usr/local/Cellar"
# Show all dependencies
otool -L /path/to/binary
Automated Verification Script
Use the provided verification script:
./verify-release-build.sh /Applications/VibeTunnel.app
This script checks for:
- Homebrew dependencies in all binaries
- Thread/Address/UB Sanitizer libraries
- Debug symbols and settings
- Code signing status
Manual Testing Process
-
Check the main app binary:
otool -L /Applications/VibeTunnel.app/Contents/MacOS/VibeTunnel -
Check the server binary:
otool -L /Applications/VibeTunnel.app/Contents/Resources/vibetunnel -
Check native modules:
otool -L /Applications/VibeTunnel.app/Contents/Resources/pty.node otool -L /Applications/VibeTunnel.app/Contents/Resources/authenticate_pam.node -
Check for sanitizer libraries:
ls -la /Applications/VibeTunnel.app/Contents/Frameworks/ | grep -i "clang\|san"
What Dependencies Are Acceptable?
✅ Good (System Libraries Only)
/usr/lib/libz.1.dylib
/System/Library/Frameworks/CoreFoundation.framework/...
/System/Library/Frameworks/Security.framework/...
/usr/lib/libc++.1.dylib
/usr/lib/libSystem.B.dylib
❌ Bad (Homebrew/External)
Any path containing:
/opt/homebrew//usr/local/Cellar//usr/local/opt/libclang_rt.*san*(sanitizer libraries)
Prevention
Build Environment
The fix involves using a clean PATH during builds:
# Set this before building
export VIBETUNNEL_BUILD_CLEAN_ENV=true
This modifies node-path-setup.sh to put Homebrew at the END of PATH instead of the beginning.
Xcode Settings
Ensure these are disabled in the scheme:
- Thread Sanitizer (
enableThreadSanitizer) - Address Sanitizer (
enableAddressSanitizer) - ASan Stack Use After Return (
enableASanStackUseAfterReturn) - NSZombieEnabled
Check with:
./mac/scripts/check-xcode-settings.sh
CI/CD Integration
Add to your release workflow:
- name: Verify Release Build
run: ./.github/scripts/verify-release.sh "${{ steps.build.outputs.app-path }}"
Testing on a Clean System
To properly test a release:
- Find a Mac without Homebrew (or temporarily rename
/opt/homebrew) - Install the app from the DMG
- Run the app and verify it starts without library errors
- Check Console.app for any dlopen or library loading errors
The Fix
The solution involved:
- Modifying PATH priority - Homebrew paths moved to end during builds
- Clean environment - Removing LDFLAGS, LIBRARY_PATH, etc. during compilation
- Configure flags - Using
--shared-zlibto prefer system libraries - Verification tools - Scripts to catch these issues before release
Key Takeaways
- Always check library dependencies before releasing
- Homebrew should never be required for the release build
- Build environments can contaminate the final binary
- Automated verification prevents these issues
- The size difference (106MB → 63MB) wasn't from optimization alone - it included external libraries