@@ -369,119 +369,130 @@ jobs:
369369 fi
370370
371371 echo "=== Running Macdeployqt ==="
372- install_name_tool -add_rpath $BREW_PREFIX/lib $MACOS_DIR/SerialPrograms
373- otool -l $MACOS_DIR/SerialPrograms | grep -A2 LC_RPATH
374- "$QT_BIN/macdeployqt" "$APP_DIR" -no-strip -verbose=2 -executable="$MACOS_DIR/SerialPrograms" -libpath="$BREW_PREFIX/opt/qt/lib"
372+ "$QT_BIN/macdeployqt" "$APP_DIR" -no-strip -verbose=3
375373 displayName: 'Run macdeployqt'
376374 condition: succeeded()
377375
378376 - bash : |
379377 set -euo pipefail
380378 echo "=== Fixing the app bundle ==="
381379 export PATH=$(macos_path)
380+
382381 APP_DIR="$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/SerialPrograms.app"
383382 MACOS_DIR="$APP_DIR/Contents/MacOS"
384383 FW_DIR="$APP_DIR/Contents/Frameworks"
385384 BIN="$MACOS_DIR/SerialPrograms"
385+ SYSTEM_RE='^(/System/Library|/usr/lib)'
386386
387- if [ "$(architecture)" = "X64" ]; then
387+ echo "=== Determining Homebrew prefix ==="
388+ if [ $(architecture) = "X64" ]; then
388389 BREW_PREFIX=$(/usr/local/bin/brew --prefix)
389390 else
390391 BREW_PREFIX=$(/opt/homebrew/bin/brew --prefix)
391392 fi
393+
392394 echo "Using BREW_PREFIX=$BREW_PREFIX"
393395
394- install_name_tool -add_rpath $BREW_PREFIX/lib $MACOS_DIR/SerialPrograms
395- otool -l SerialPrograms.app/Contents/MacOS/SerialPrograms | grep -A2 LC_RPATH
396396 collect_deps() {
397- otool -L "$1" \
398- | awk 'NR>1 {print $1}' \
399- | grep -vE '^(@rpath|@executable_path|@loader_path)' || true
397+ otool -L "$1" | awk 'NR>1 {print $1}' | grep -vE "$SYSTEM_RE" | grep -vE '^@' || true
400398 }
401399
402- copy_dylib() {
403- local src="$1"
404- local base
405- base=$(basename "$src")
400+ is_framework() {
401+ [[ "$1" == *.framework/* ]]
402+ }
406403
407- if [ -f "$FW_DIR/$base" ]; then
408- return
409- fi
404+ copy_dep() {
405+ local dep="$1"
406+
407+ if is_framework "$dep"; then
408+ local fw_root
409+ fw_root=$(echo "$dep" | sed 's|\(.*/[^/]*\.framework\)/.*|\1|')
410+ local fw_name
411+ fw_name=$(basename "$fw_root")
412+ local dst="$FW_DIR/$fw_name"
410413
411- echo "Copying $base"
412- cp "$src" "$FW_DIR/$base"
413- chmod 755 "$FW_DIR/$base"
414- install_name_tool -id "@executable_path/../Frameworks/$base" "$FW_DIR/$base"
414+ if [ ! -d "$dst" ]; then
415+ echo "Copying framework $fw_name"
416+ rsync -a "$fw_root" "$dst"
417+ copied=1
418+ fi
419+ else
420+ local base
421+ base=$(basename "$dep")
422+ if [ ! -f "$FW_DIR/$base" ]; then
423+ echo "Copying dylib $base"
424+ cp "$dep" "$FW_DIR/$base"
425+ chmod 755 "$FW_DIR/$base"
426+ copied=1
427+ fi
428+ fi
415429 }
416430
417- echo "=== Collecting and copying dependent dylibs (recursive) ==="
431+ echo "=== Collecting and copying dependent dylibs and frameworks ==="
418432 copied=1
419433 while [ $copied -eq 1 ]; do
420434 copied=0
421435
422- for target in "$BIN" "$FW_DIR"/*.dylib; do
423- [ -f "$target" ] || continue
424- for dep in $(collect_deps "$target"); do
425- if [ -f "$dep" ]; then
426- base=$(basename "$dep")
427- if [ ! -f "$FW_DIR/$base" ]; then
428- copy_dylib "$dep"
429- copied=1
430- fi
431- fi
436+ for dep in $(collect_deps "$BIN"); do
437+ copy_dep "$dep"
438+ done
439+
440+ for obj in "$FW_DIR"/*.dylib "$FW_DIR"/*.framework/Versions/A/*; do
441+ [ -f "$obj" ] || continue
442+ for dep in $(collect_deps "$obj"); do
443+ copy_dep "$dep"
432444 done
433445 done
434446 done
435447
448+ echo "=== Fixing install IDs ==="
449+ for dylib in "$FW_DIR"/*.dylib; do
450+ [ -f "$dylib" ] || continue
451+ base=$(basename "$dylib")
452+ install_name_tool -id "@executable_path/../Frameworks/$base" "$dylib"
453+ done
454+
455+ for fw in "$FW_DIR"/*.framework; do
456+ fw_bin="$fw/Versions/A/$(basename "$fw" .framework)"
457+ if [ -f "$fw_bin" ]; then
458+ install_name_tool -id \
459+ "@executable_path/../Frameworks/$(basename "$fw")/Versions/A/$(basename "$fw_bin")" \
460+ "$fw_bin"
461+ fi
462+ done
463+
436464 rewrite_refs() {
437465 local target="$1"
438- otool -L "$target" | awk 'NR>1 {print $1}' | while read -r dep ; do
466+ for dep in $( otool -L "$target" | awk 'NR>1 {print $1}') ; do
439467 base=$(basename "$dep")
440468 if [ -f "$FW_DIR/$base" ]; then
441469 install_name_tool -change "$dep" \
442470 "@executable_path/../Frameworks/$base" \
443471 "$target"
472+ elif [[ "$dep" == *.framework/* ]]; then
473+ fw=$(basename "$(echo "$dep" | sed 's|\(.*/[^/]*\.framework\)/.*|\1|')")
474+ install_name_tool -change "$dep" \
475+ "@executable_path/../Frameworks/$fw/Versions/A/${fw%.framework}" \
476+ "$target"
444477 fi
445478 done
446479 }
447480
448- echo "=== Rewriting dylib references ==="
481+ echo "=== Rewriting dylib and framework references ==="
449482 rewrite_refs "$BIN"
450- for dylib in "$FW_DIR"/*.dylib; do
451- rewrite_refs "$dylib"
452- done
453-
454- echo "=== Cleaning rpaths ==="
455- get_rpaths() {
456- otool -l "$1" \
457- | awk '
458- $1=="cmd" && $2=="LC_RPATH" {f=1}
459- f && $1=="path" {print $2; f=0}
460- '
461- }
462483
463- for rpath in $(get_rpaths "$BIN"); do
464- if [ "$rpath" != "@executable_path/../Frameworks" ]; then
465- echo "Removing rpath: $rpath"
466- install_name_tool -delete_rpath "$rpath" "$BIN" || true
467- fi
484+ for obj in "$FW_DIR"/*.dylib "$FW_DIR"/*.framework/Versions/A/*; do
485+ [ -f "$obj" ] && rewrite_refs "$obj"
468486 done
469487
470- if ! get_rpaths "$BIN" | grep -q "^@executable_path/../Frameworks$"; then
471- install_name_tool -add_rpath "@executable_path/../Frameworks" "$BIN"
472- fi
473-
474- echo "=== Verifying no external dylib references remain ==="
475- if otool -L "$BIN" | grep -E "/usr/local|/opt/homebrew|Cellar"; then
476- echo "ERROR: External Homebrew dylib references remain"
477- exit 1
478- fi
488+ echo "=== Ensuring rpath ==="
489+ install_name_tool -add_rpath "@executable_path/../Frameworks" "$BIN" 2>/dev/null || true
479490
480491 echo "=== Codesigning ==="
481492 codesign --force --deep --sign - "$APP_DIR"
482493
483- echo "=== Copying app bundle to output ==="
484- rsync -a --delete "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/SerialPrograms.app " "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/"
494+ echo "=== Copying app bundle to output directory ==="
495+ rsync -a --delete "$APP_DIR " "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/"
485496 echo "https://github.com/$(Build.Repository.Name)/commit/$(Build.SourceVersion)" > "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/version.txt"
486497 echo "Deployment complete for $(architecture)"
487498 displayName: "Fix MacOS app bundle"
0 commit comments