@@ -302,8 +302,8 @@ jobs:
302302 qt_version_major : ' 6'
303303 qt_modules : ' qtserialport qtmultimedia'
304304 cmake_preset : ' RelWithDebInfo'
305- macos_path : ' /opt/homebrew/opt/qt/lib/cmake:/opt/homebrew/opt/qt/bin:/opt/homebrew/bin:/opt/homebrew/sbin:$PATH'
306- cmake_additional_param : ' -DCMAKE_OSX_ARCHITECTURES=arm64 - DPACKAGE_BUILD=true -DUNIX_LINK_TESSERACT:BOOL=true -DCMAKE_PREFIX_PATH=/opt/homebrew/opt/qt '
305+ macos_path : ' /opt/homebrew/opt/qt/lib/cmake:/opt/homebrew/opt/qt/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/opt/homebrew: $PATH'
306+ cmake_additional_param : ' -DPACKAGE_BUILD=true -DUNIX_LINK_TESSERACT:BOOL=true'
307307
308308 x86_64 :
309309 poolName : ' ApplePool'
@@ -315,8 +315,8 @@ jobs:
315315 qt_version_major : ' 6'
316316 qt_modules : ' qtserialport qtmultimedia'
317317 cmake_preset : ' RelWithDebInfo'
318- macos_path : ' /usr/local/opt/qt/lib/cmake:/usr/local/opt/qt/bin:/usr/local/opt:/usr/local/bin:/usr/local/sbin:$PATH'
319- cmake_additional_param : ' -DCMAKE_OSX_ARCHITECTURES=x86_64 - DPACKAGE_BUILD=true -DUNIX_LINK_TESSERACT:BOOL=true -DCMAKE_PREFIX_PATH=/usr/local/opt/qt '
318+ macos_path : ' /usr/local/opt/qt/lib/cmake:/usr/local/opt/qt/bin:/usr/local/opt:/usr/local/bin:/usr/local/sbin:/usr/local: $PATH'
319+ cmake_additional_param : ' -DPACKAGE_BUILD=true -DUNIX_LINK_TESSERACT:BOOL=true'
320320
321321 pool :
322322 name : $(poolName)
@@ -338,14 +338,14 @@ jobs:
338338 - script : |
339339 export PATH=$(macos_path)
340340 cd "$(Pipeline.Workspace)/Arduino-Source/SerialPrograms"
341- arch -$(arch) /Applications/CMake.app/Contents/bin/cmake --preset=$(cmake_preset) $(cmake_additional_param ) --fresh
341+ cmake $(cmake_additional_param) --preset=$(cmake_preset) --fresh
342342 displayName: 'Configure CMake'
343343 condition: succeeded()
344344
345345 - script : |
346346 export PATH=$(macos_path)
347347 cd "$(Pipeline.Workspace)/Arduino-Source/SerialPrograms"
348- arch -$(arch) /Applications/CMake.app/Contents/bin/ cmake --build --preset=$(cmake_preset)
348+ cmake --build --preset=$(cmake_preset)
349349 displayName: 'Build'
350350 condition: succeeded()
351351
@@ -370,118 +370,131 @@ jobs:
370370
371371 echo "=== Running Macdeployqt ==="
372372 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"
373+ otool -l SerialPrograms.app/Contents/MacOS /SerialPrograms | grep -A2 LC_RPATH
374+ "$QT_BIN/macdeployqt" "$APP_DIR" -no-strip -verbose=3
375375 displayName: 'Run macdeployqt'
376376 condition: succeeded()
377377
378378 - bash : |
379379 set -euo pipefail
380380 echo "=== Fixing the app bundle ==="
381381 export PATH=$(macos_path)
382+
382383 APP_DIR="$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/SerialPrograms.app"
383384 MACOS_DIR="$APP_DIR/Contents/MacOS"
384385 FW_DIR="$APP_DIR/Contents/Frameworks"
385386 BIN="$MACOS_DIR/SerialPrograms"
387+ SYSTEM_RE='^(/System/Library|/usr/lib)'
386388
387- if [ "$(architecture)" = "X64" ]; then
389+ echo "=== Determining Homebrew prefix ==="
390+ if [ $(architecture) = "X64" ]; then
388391 BREW_PREFIX=$(/usr/local/bin/brew --prefix)
389392 else
390393 BREW_PREFIX=$(/opt/homebrew/bin/brew --prefix)
391394 fi
395+
392396 echo "Using BREW_PREFIX=$BREW_PREFIX"
393397
394- install_name_tool -add_rpath $BREW_PREFIX/lib $MACOS_DIR/SerialPrograms
395- otool -l SerialPrograms.app/Contents/MacOS/SerialPrograms | grep -A2 LC_RPATH
396398 collect_deps() {
397- otool -L "$1" \
398- | awk 'NR>1 {print $1}' \
399- | grep -vE '^(@rpath|@executable_path|@loader_path)' || true
399+ otool -L "$1" | awk 'NR>1 {print $1}' | grep -vE "$SYSTEM_RE" | grep -vE '^@' || true
400400 }
401401
402- copy_dylib() {
403- local src="$1"
404- local base
405- base=$(basename "$src")
402+ is_framework() {
403+ [[ "$1" == *.framework/* ]]
404+ }
406405
407- if [ -f "$FW_DIR/$base" ]; then
408- return
409- fi
406+ copy_dep() {
407+ local dep="$1"
410408
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"
409+ if is_framework "$dep"; then
410+ local fw_root
411+ fw_root=$(echo "$dep" | sed 's|\(.*/[^/]*\.framework\)/.*|\1|')
412+ local fw_name
413+ fw_name=$(basename "$fw_root")
414+ local dst="$FW_DIR/$fw_name"
415+
416+ if [ ! -d "$dst" ]; then
417+ echo "Copying framework $fw_name"
418+ rsync -a "$fw_root" "$dst"
419+ copied=1
420+ fi
421+ else
422+ local base
423+ base=$(basename "$dep")
424+ if [ ! -f "$FW_DIR/$base" ]; then
425+ echo "Copying dylib $base"
426+ cp "$dep" "$FW_DIR/$base"
427+ chmod 755 "$FW_DIR/$base"
428+ copied=1
429+ fi
430+ fi
415431 }
416432
417- echo "=== Collecting and copying dependent dylibs (recursive) ==="
433+ echo "=== Collecting and copying dependent dylibs and frameworks ==="
418434 copied=1
419435 while [ $copied -eq 1 ]; do
420436 copied=0
421437
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
438+ for dep in $(collect_deps "$BIN"); do
439+ copy_dep "$dep"
440+ done
441+
442+ for obj in "$FW_DIR"/*.dylib "$FW_DIR"/*.framework/Versions/A/*; do
443+ [ -f "$obj" ] || continue
444+ for dep in $(collect_deps "$obj"); do
445+ copy_dep "$dep"
432446 done
433447 done
434448 done
435449
450+ echo "=== Fixing install IDs ==="
451+ for dylib in "$FW_DIR"/*.dylib; do
452+ [ -f "$dylib" ] || continue
453+ base=$(basename "$dylib")
454+ install_name_tool -id "@executable_path/../Frameworks/$base" "$dylib"
455+ done
456+
457+ for fw in "$FW_DIR"/*.framework; do
458+ fw_bin="$fw/Versions/A/$(basename "$fw" .framework)"
459+ if [ -f "$fw_bin" ]; then
460+ install_name_tool -id \
461+ "@executable_path/../Frameworks/$(basename "$fw")/Versions/A/$(basename "$fw_bin")" \
462+ "$fw_bin"
463+ fi
464+ done
465+
436466 rewrite_refs() {
437467 local target="$1"
438- otool -L "$target" | awk 'NR>1 {print $1}' | while read -r dep ; do
468+ for dep in $( otool -L "$target" | awk 'NR>1 {print $1}') ; do
439469 base=$(basename "$dep")
440470 if [ -f "$FW_DIR/$base" ]; then
441471 install_name_tool -change "$dep" \
442472 "@executable_path/../Frameworks/$base" \
443473 "$target"
474+ elif [[ "$dep" == *.framework/* ]]; then
475+ fw=$(basename "$(echo "$dep" | sed 's|\(.*/[^/]*\.framework\)/.*|\1|')")
476+ install_name_tool -change "$dep" \
477+ "@executable_path/../Frameworks/$fw/Versions/A/${fw%.framework}" \
478+ "$target"
444479 fi
445480 done
446481 }
447482
448- echo "=== Rewriting dylib references ==="
483+ echo "=== Rewriting dylib and framework references ==="
449484 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- }
462485
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
486+ for obj in "$FW_DIR"/*.dylib "$FW_DIR"/*.framework/Versions/A/*; do
487+ [ -f "$obj" ] && rewrite_refs "$obj"
468488 done
469489
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
490+ echo "=== Ensuring rpath ==="
491+ install_name_tool -add_rpath "@executable_path/../Frameworks" "$BIN" 2>/dev/null || true
479492
480493 echo "=== Codesigning ==="
481494 codesign --force --deep --sign - "$APP_DIR"
482495
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/"
496+ echo "=== Copying app bundle to output directory ==="
497+ rsync -a --delete "$APP_DIR " "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/"
485498 echo "https://github.com/$(Build.Repository.Name)/commit/$(Build.SourceVersion)" > "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/version.txt"
486499 echo "Deployment complete for $(architecture)"
487500 displayName: "Fix MacOS app bundle"
0 commit comments