feat: integrate TDLib bundling into macOS build process

- Updated package.json to include new scripts for bundling TDLib dylib during macOS builds.
- Enhanced CI workflow to automate the bundling and re-signing of the macOS app after TDLib integration, addressing "Library not loaded" issues.
- Introduced a new script for managing TDLib dependencies and ensuring proper installation paths within the app bundle.
This commit is contained in:
Steven Enamakel
2026-02-04 14:02:57 +05:30
parent 205089ecbc
commit aa1194b34c
3 changed files with 244 additions and 2 deletions
+24
View File
@@ -317,6 +317,30 @@ jobs:
owner: alphahumanxyz
repo: alphahuman
# Bundle TDLib dylib into macOS app (fixes "Library not loaded" crash)
- name: Bundle TDLib for macOS
if: matrix.settings.platform == 'macos-latest'
run: |
chmod +x ./src-tauri/scripts/bundle-tdlib-macos.sh
./src-tauri/scripts/bundle-tdlib-macos.sh release
# Re-sign the app after modifying the bundle (required for notarization)
- name: Re-sign macOS app after TDLib bundling
if: matrix.settings.platform == 'macos-latest' && secrets.APPLE_SIGNING_IDENTITY != ''
env:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
run: |
APP_BUNDLE=$(find src-tauri/target/release/bundle/macos -name "*.app" -type d | head -1)
if [ -n "$APP_BUNDLE" ]; then
echo "Re-signing app bundle: $APP_BUNDLE"
# Sign the TDLib dylib
codesign --force --options runtime --sign "$APPLE_SIGNING_IDENTITY" \
"$APP_BUNDLE/Contents/Frameworks/libtdjson.1.8.29.dylib" || true
# Re-sign the entire app bundle
codesign --force --deep --options runtime --sign "$APPLE_SIGNING_IDENTITY" "$APP_BUNDLE" || true
echo "App re-signed successfully"
fi
- name: Get file info
id: file-info
shell: bash
+3 -2
View File
@@ -10,9 +10,10 @@
"compile": "tsc --noEmit",
"preview": "vite preview",
"tauri": "tauri",
"macos:build": "tauri build --debug --bundles app",
"macos:build": "tauri build --debug --bundles app && ./src-tauri/scripts/bundle-tdlib-macos.sh debug",
"macos:build:release": "tauri build --bundles app dmg && ./src-tauri/scripts/bundle-tdlib-macos.sh release",
"macos:run": "open 'src-tauri/target/debug/bundle/macos/AlphaHuman.app'",
"macos:dev": "tauri build --debug --bundles app && open 'src-tauri/target/debug/bundle/macos/AlphaHuman.app'",
"macos:dev": "tauri build --debug --bundles app && ./src-tauri/scripts/bundle-tdlib-macos.sh debug && open 'src-tauri/target/debug/bundle/macos/AlphaHuman.app'",
"android:dev": "tauri android dev",
"android:build": "tauri android build",
"dev:app": "RUST_BACKTRACE=1 RUST_LOG=info tauri dev",
+217
View File
@@ -0,0 +1,217 @@
#!/bin/bash
# Script to bundle TDLib dylib and its dependencies into macOS app bundle
# This fixes the "Library not loaded: @rpath/libtdjson.1.8.29.dylib" error
set -e
TDLIB_VERSION="1.8.29"
DYLIB_NAME="libtdjson.${TDLIB_VERSION}.dylib"
# Determine build type (debug or release)
BUILD_TYPE="${1:-release}"
# Optional: specific target (e.g., aarch64-apple-darwin, x86_64-apple-darwin)
TARGET="${2:-}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
TAURI_DIR="$(dirname "$SCRIPT_DIR")"
# Determine target directory (handles cross-compilation targets)
if [ -n "$TARGET" ]; then
TARGET_DIR="${TAURI_DIR}/target/${TARGET}/${BUILD_TYPE}"
else
TARGET_DIR="${TAURI_DIR}/target/${BUILD_TYPE}"
fi
# Fallback: if target-specific dir doesn't exist, try without target
if [ ! -d "$TARGET_DIR" ]; then
TARGET_DIR="${TAURI_DIR}/target/${BUILD_TYPE}"
fi
echo "=== TDLib macOS Bundler ==="
echo "Build type: ${BUILD_TYPE}"
echo "Target: ${TARGET:-default}"
echo "Target dir: ${TARGET_DIR}"
# Find the app bundle - check multiple possible locations
APP_BUNDLE=""
for search_dir in \
"${TAURI_DIR}/target/${TARGET}/${BUILD_TYPE}/bundle/macos" \
"${TAURI_DIR}/target/${BUILD_TYPE}/bundle/macos" \
"${TAURI_DIR}/target/release/bundle/macos" \
"${TAURI_DIR}/target/debug/bundle/macos"; do
if [ -d "$search_dir" ]; then
found=$(find "$search_dir" -name "*.app" -type d 2>/dev/null | head -1)
if [ -n "$found" ]; then
APP_BUNDLE="$found"
break
fi
fi
done
if [ -z "$APP_BUNDLE" ]; then
echo "Warning: No .app bundle found"
echo "Searched in:"
echo " - ${TAURI_DIR}/target/${TARGET}/${BUILD_TYPE}/bundle/macos"
echo " - ${TAURI_DIR}/target/${BUILD_TYPE}/bundle/macos"
echo "This script should be run after 'tauri build'"
exit 0
fi
echo "Found app bundle: ${APP_BUNDLE}"
# Create Frameworks directory
FRAMEWORKS_DIR="${APP_BUNDLE}/Contents/Frameworks"
mkdir -p "$FRAMEWORKS_DIR"
echo "Created Frameworks directory: ${FRAMEWORKS_DIR}"
# Find the TDLib dylib in build artifacts - search in multiple locations
DYLIB_PATH=""
for search_dir in \
"${TAURI_DIR}/target/${TARGET}/${BUILD_TYPE}/build" \
"${TAURI_DIR}/target/${BUILD_TYPE}/build" \
"${TAURI_DIR}/target/release/build" \
"${TAURI_DIR}/target/debug/build"; do
if [ -d "$search_dir" ]; then
found=$(find "$search_dir" -name "${DYLIB_NAME}" -type f 2>/dev/null | head -1)
if [ -n "$found" ]; then
DYLIB_PATH="$found"
break
fi
fi
done
if [ -z "$DYLIB_PATH" ]; then
echo "Error: Could not find ${DYLIB_NAME} in build artifacts"
echo "Searched in target/*/build directories"
echo "Make sure TDLib was built correctly."
exit 1
fi
echo "Found TDLib dylib: ${DYLIB_PATH}"
# Copy the dylib to Frameworks
cp "$DYLIB_PATH" "${FRAMEWORKS_DIR}/"
echo "Copied ${DYLIB_NAME} to Frameworks"
# Also copy the symlink version if it exists
DYLIB_SYMLINK="${DYLIB_PATH%/*}/libtdjson.dylib"
if [ -f "$DYLIB_SYMLINK" ] || [ -L "$DYLIB_SYMLINK" ]; then
cp "$DYLIB_SYMLINK" "${FRAMEWORKS_DIR}/" 2>/dev/null || true
fi
# Find the main binary
BINARY_NAME=$(basename "${APP_BUNDLE}" .app)
BINARY_PATH="${APP_BUNDLE}/Contents/MacOS/${BINARY_NAME}"
if [ ! -f "$BINARY_PATH" ]; then
echo "Error: Binary not found at ${BINARY_PATH}"
exit 1
fi
echo "Found binary: ${BINARY_PATH}"
# Bundled dylib path
BUNDLED_DYLIB="${FRAMEWORKS_DIR}/${DYLIB_NAME}"
# Function to bundle a dependency and fix references
bundle_dependency() {
local dep_path="$1"
local dep_name=$(basename "$dep_path")
if [ ! -f "$dep_path" ]; then
echo "Warning: Dependency not found: $dep_path"
return 1
fi
# Copy to Frameworks if not already there
if [ ! -f "${FRAMEWORKS_DIR}/${dep_name}" ]; then
echo "Bundling dependency: ${dep_name}"
cp "$dep_path" "${FRAMEWORKS_DIR}/"
chmod 755 "${FRAMEWORKS_DIR}/${dep_name}"
# Change the dependency's install name to use @rpath
install_name_tool -id "@rpath/${dep_name}" "${FRAMEWORKS_DIR}/${dep_name}"
fi
return 0
}
# Function to fix references in a library
fix_references() {
local lib_path="$1"
local lib_name=$(basename "$lib_path")
echo "Fixing references in: ${lib_name}"
# Get all dependencies
local deps=$(otool -L "$lib_path" | tail -n +2 | awk '{print $1}')
for dep in $deps; do
# Skip system libraries (they're fine as-is)
if [[ "$dep" == /usr/lib/* ]] || [[ "$dep" == /System/* ]] || [[ "$dep" == "@rpath/"* ]] || [[ "$dep" == "@executable_path/"* ]]; then
continue
fi
local dep_name=$(basename "$dep")
# Bundle the dependency if it's from Homebrew or a non-system path
if [[ "$dep" == /opt/homebrew/* ]] || [[ "$dep" == /usr/local/* ]]; then
if bundle_dependency "$dep"; then
# Update the reference to use @rpath
install_name_tool -change "$dep" "@rpath/${dep_name}" "$lib_path"
echo " Fixed reference: ${dep_name}"
fi
fi
done
}
# Fix the TDLib dylib's install name
echo ""
echo "Fixing dylib install name..."
install_name_tool -id "@rpath/${DYLIB_NAME}" "$BUNDLED_DYLIB"
# Bundle OpenSSL and other dependencies from TDLib
echo ""
echo "Bundling TDLib dependencies..."
fix_references "$BUNDLED_DYLIB"
# Fix any cross-references between bundled dependencies
echo ""
echo "Fixing cross-references between dependencies..."
for dylib in "${FRAMEWORKS_DIR}"/*.dylib; do
if [ -f "$dylib" ]; then
fix_references "$dylib"
fi
done
# Add rpath to the binary to look in Frameworks
echo ""
echo "Adding rpath to binary..."
# First, try to delete existing rpath if it exists (ignore errors)
install_name_tool -delete_rpath "@executable_path/../Frameworks" "$BINARY_PATH" 2>/dev/null || true
# Add the correct rpath
install_name_tool -add_rpath "@executable_path/../Frameworks" "$BINARY_PATH"
# Verify the changes
echo ""
echo "=== Verification ==="
echo ""
echo "Bundled libraries:"
ls -la "${FRAMEWORKS_DIR}/"
echo ""
echo "TDLib dylib dependencies (should all be @rpath or system libs):"
otool -L "$BUNDLED_DYLIB"
echo ""
echo "Binary library dependencies:"
otool -L "$BINARY_PATH" | grep -i tdjson || echo "No tdjson reference found"
echo ""
echo "Binary rpaths:"
otool -l "$BINARY_PATH" | grep -A3 "cmd LC_RPATH" | head -8 || true
echo ""
echo "=== TDLib bundling complete ==="
echo "The app bundle at ${APP_BUNDLE} now includes TDLib and its dependencies."