@@ -20,28 +20,26 @@ parameters:
2020 displayName : Build Type
2121 type : string
2222 default : commit
23- values :
24- - release
25- - beta
26- - commit
23+ values : [commit, beta, release]
2724
2825 - name : targetOS
2926 displayName : Target OS
3027 type : string
3128 default : all
32- values :
33- - windows
34- - linux
35- - macos
36- - all
29+ values : [all, windows, linux, macos]
30+
31+ - name : versionTag
32+ displayName : Version Tag
33+ type : string
34+ default : ' v0.0.0'
3735
3836# ##########################################
3937# WINDOWS BUILD JOB #
4038# ##########################################
4139
4240jobs :
4341- job : Windows
44- timeoutInMinutes : 120
42+ timeoutInMinutes : 30
4543 cancelTimeoutInMinutes : 1
4644 condition : |
4745 or(
@@ -84,18 +82,19 @@ jobs:
8482 arguments : ' -arch=x64'
8583 modifyEnvironment : true
8684 displayName : ' Initialize VS Environment'
85+ condition : succeeded()
8786
8887 - script : |
8988 cd /d "$(Pipeline.Workspace)/Arduino-Source/SerialPrograms"
9089 cmake --preset=$(cmake_preset) $(cmake_additional_param)
9190 displayName: 'Configure CMake'
92- condition: and( succeeded(), eq(variables['Agent.OS'], 'Windows_NT') )
91+ condition: succeeded()
9392
9493 - script : |
9594 cd /d "$(Pipeline.Workspace)/Arduino-Source/SerialPrograms"
9695 cmake --build --preset=$(cmake_preset) --parallel 8
9796 displayName: 'Build'
98- condition: and( succeeded(), eq(variables['Agent.OS'], 'Windows_NT') )
97+ condition: succeeded()
9998
10099 - powershell : |
101100 Write-Host "=== Running windeployqt ==="
@@ -106,7 +105,7 @@ jobs:
106105 & "C:/Qt/6.8.3/msvc2022_64/bin/windeployqt.exe" --dir "$OUTPUT_DIR" --release "$APP_EXE"
107106 Write-Host "=== windeployqt complete ==="
108107 displayName: 'Deploy app'
109- condition: and( succeeded(), eq(variables['Agent.OS'], 'Windows_NT') )
108+ condition: succeeded()
110109
111110 - powershell : |
112111 echo "=== Copying resources==="
@@ -119,7 +118,7 @@ jobs:
119118 Write-Host "Robocopy exited with exit code:" $LASTEXITCODE
120119 if ($LASTEXITCODE -eq 1) { exit 0 } else { exit 1 }
121120 displayName: 'Copy resources'
122- condition: and( succeeded(), eq(variables['Agent.OS'], 'Windows_NT') )
121+ condition: succeeded()
123122
124123 - powershell : |
125124 $root = "$(Pipeline.Workspace)\Arduino-Source\build\$(cmake_preset)"
@@ -130,7 +129,7 @@ jobs:
130129 Compress-Archive -Path $temp -DestinationPath "$root\$name.zip"
131130 Remove-Item $temp -Recurse -Force
132131 displayName: 'Archive Windows Output folder'
133- condition: and( succeeded(), eq(variables['Agent.OS'], 'Windows_NT') )
132+ condition: succeeded()
134133
135134 - task : PublishBuildArtifacts@1
136135 displayName : ' Publish SerialPrograms'
@@ -144,7 +143,7 @@ jobs:
144143# ##########################################
145144
146145- job : Linux
147- timeoutInMinutes : 120
146+ timeoutInMinutes : 30
148147 cancelTimeoutInMinutes : 1
149148 condition : |
150149 or(
@@ -188,14 +187,14 @@ jobs:
188187 cd "$(Pipeline.Workspace)/Arduino-Source/SerialPrograms"
189188 cmake --preset=$(cmake_preset) $(cmake_additional_param)
190189 displayName: 'Configure CMake'
191- condition: and( succeeded(), eq(variables['Agent.OS'], 'Linux') )
190+ condition: succeeded()
192191
193192 - script : |
194193 export PATH="/opt/Qt/6.10.0/gcc_64/lib/cmake:$PATH"
195194 cd "$(Pipeline.Workspace)/Arduino-Source/SerialPrograms"
196195 cmake --build --preset=$(cmake_preset) --parallel 6
197196 displayName: 'Build'
198- condition: and( succeeded(), eq(variables['Agent.OS'], 'Linux') )
197+ condition: succeeded()
199198
200199 - script : |
201200 set -e
@@ -262,13 +261,13 @@ jobs:
262261 echo "https://github.com/$(Build.Repository.Name)/commit/$(Build.SourceVersion)" > $(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/version.txt
263262 echo "=== AppImage build complete ==="
264263 displayName: 'Deploy AppImage'
265- condition: and( succeeded(), eq(variables['Agent.OS'], 'Linux') )
264+ condition: succeeded()
266265
267266 - script : |
268267 cd "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output"
269268 tar -zcvf ../SerialPrograms-Linux-$(compiler)-$(architecture).tar.gz *
270269 displayName: 'Archive Linux Output folder'
271- condition: and( succeeded(), eq(variables['Agent.OS'], 'Linux') )
270+ condition: succeeded()
272271
273272 - task : PublishBuildArtifacts@1
274273 displayName : ' Publish SerialPrograms'
@@ -282,7 +281,7 @@ jobs:
282281# ##########################################
283282
284283- job : MacOS
285- timeoutInMinutes : 120
284+ timeoutInMinutes : 30
286285 cancelTimeoutInMinutes : 1
287286 condition : |
288287 or(
@@ -339,18 +338,18 @@ jobs:
339338 cd "$(Pipeline.Workspace)/Arduino-Source/SerialPrograms"
340339 cmake --preset=$(cmake_preset) $(cmake_additional_param)
341340 displayName: 'Configure CMake'
342- condition: and( succeeded(), eq(variables['Agent.OS'], 'Darwin') )
341+ condition: succeeded()
343342
344343 - script : |
345344 export PATH=$(macos_path)
346345 cd "$(Pipeline.Workspace)/Arduino-Source/SerialPrograms"
347346 cmake --build --preset=$(cmake_preset)
348347 displayName: 'Build'
349- condition: and( succeeded(), eq(variables['Agent.OS'], 'Darwin') )
348+ condition: succeeded()
350349
351350 - script : |
352351 set -e
353- echo "=== Deploying MacOS $(architecture) bundle ==="
352+ echo "=== Running macdeployqt for MacOS $(architecture) ==="
354353 export PATH=$(macos_path)
355354 APP_DIR="$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/SerialPrograms.app"
356355 MACOS_DIR="$APP_DIR/Contents/MacOS"
@@ -367,69 +366,131 @@ jobs:
367366 QT_BIN="$BREW_PREFIX/opt/qt/bin"
368367 fi
369368
370- echo "BREW_PREFIX=$BREW_PREFIX"
371- echo "QT_BIN=$QT_BIN"
372-
373- echo "=== Running macdeployqt ==="
369+ echo "=== Running Macdeployqt ==="
374370 install_name_tool -add_rpath $BREW_PREFIX/lib $MACOS_DIR/SerialPrograms
375371 otool -l $MACOS_DIR/SerialPrograms | grep -A2 LC_RPATH
376372 "$QT_BIN/macdeployqt" "$APP_DIR" -no-strip -verbose=2
373+ displayName: 'Run macdeployqt'
374+ condition: succeeded()
377375
378- echo "=== Copying additional dependencies ==="
379- cp "$BREW_PREFIX/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib" "$FW_DIR" || true
380- cp "$BREW_PREFIX/opt/protobuf/lib/libutf8_validity.dylib" "$FW_DIR" || true
381- cp "$BREW_PREFIX/opt/webp/lib/libsharpyuv.0.dylib" "$FW_DIR" || true
382- cp "$BREW_PREFIX/opt/jpeg-xl/lib/libjxl_cms.0.11.dylib" "$FW_DIR" || true
383-
384- cp $BREW_PREFIX/opt/vtk/lib/libvtkCommonComputationalGeometry-*.dylib "$FW_DIR" 2>/dev/null || true
385- cp $BREW_PREFIX/opt/vtk/lib/libvtkFiltersVerdict-*.dylib "$FW_DIR" 2>/dev/null || true
386- cp $BREW_PREFIX/opt/vtk/lib/libvtkfmt-*.dylib "$FW_DIR" 2>/dev/null || true
387- cp $BREW_PREFIX/opt/vtk/lib/libvtkFiltersGeometry-*.dylib "$FW_DIR" 2>/dev/null || true
388- cp $BREW_PREFIX/opt/vtk/lib/libvtkFiltersCore-*.dylib "$FW_DIR" 2>/dev/null || true
389- cp $BREW_PREFIX/opt/vtk/lib/libvtkCommonCore-*.dylib "$FW_DIR" 2>/dev/null || true
390- cp $BREW_PREFIX/opt/vtk/lib/libvtkCommonSystem-*.dylib "$FW_DIR" 2>/dev/null || true
391-
392- echo "=== Fixing install IDs in copied libs ==="
393- for dylib in "$FW_DIR"/*.dylib; do
394- [ -f "$dylib" ] || continue
395- base=$(basename "$dylib")
396- install_name_tool -id "@executable_path/../Frameworks/$base" "$dylib"
376+ - bash : |
377+ set -euo pipefail
378+ echo "=== Fixing the app bundle ==="
379+ export PATH=$(macos_path)
380+ APP_DIR="$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/SerialPrograms.app"
381+ MACOS_DIR="$APP_DIR/Contents/MacOS"
382+ FW_DIR="$APP_DIR/Contents/Frameworks"
383+ BIN="$MACOS_DIR/SerialPrograms"
384+
385+ if [ "$(architecture)" = "X64" ]; then
386+ BREW_PREFIX=$(/usr/local/bin/brew --prefix)
387+ else
388+ BREW_PREFIX=$(/opt/homebrew/bin/brew --prefix)
389+ fi
390+ echo "Using BREW_PREFIX=$BREW_PREFIX"
391+
392+ SYSTEM_RE='^(/System/Library|/usr/lib)'
393+
394+ collect_deps() {
395+ otool -L "$1" \
396+ | awk 'NR>1 {print $1}' \
397+ | grep -vE "$SYSTEM_RE" \
398+ | grep -vE '^(@rpath|@executable_path|@loader_path)' || true
399+ }
400+
401+ copy_dylib() {
402+ local src="$1"
403+ local base
404+ base=$(basename "$src")
405+
406+ if [ -f "$FW_DIR/$base" ]; then
407+ return
408+ fi
409+
410+ echo "Copying $base"
411+ cp "$src" "$FW_DIR/$base"
412+ chmod 755 "$FW_DIR/$base"
413+ install_name_tool -id "@executable_path/../Frameworks/$base" "$FW_DIR/$base"
414+ }
415+
416+ echo "=== Collecting and copying dependent dylibs (recursive) ==="
417+ copied=1
418+ while [ $copied -eq 1 ]; do
419+ copied=0
420+
421+ for target in "$BIN" "$FW_DIR"/*.dylib; do
422+ [ -f "$target" ] || continue
423+ for dep in $(collect_deps "$target"); do
424+ if [ -f "$dep" ]; then
425+ base=$(basename "$dep")
426+ if [ ! -f "$FW_DIR/$base" ]; then
427+ copy_dylib "$dep"
428+ copied=1
429+ fi
430+ fi
431+ done
432+ done
397433 done
398434
399- echo "=== Rewriting internal dylib references ==="
400- for dylib in "$FW_DIR"/*.dylib; do
401- [ -f "$dylib" ] || continue
402- for linked in $(otool -L "$dylib" | awk 'NR>1 {print $1}' | grep "$BREW_PREFIX" || true); do
403- base=$(basename "$linked")
435+ rewrite_refs() {
436+ local target="$1"
437+ otool -L "$target" | awk 'NR>1 {print $1}' | while read -r dep; do
438+ base=$(basename "$dep")
404439 if [ -f "$FW_DIR/$base" ]; then
405- install_name_tool -change "$linked" "@executable_path/../Frameworks/$base" "$dylib"
440+ install_name_tool -change "$dep" \
441+ "@executable_path/../Frameworks/$base" \
442+ "$target"
406443 fi
407444 done
445+ }
446+
447+ echo "=== Rewriting dylib references ==="
448+ rewrite_refs "$BIN"
449+ for dylib in "$FW_DIR"/*.dylib; do
450+ rewrite_refs "$dylib"
408451 done
409452
410- echo "=== Rewriting main executable references ==="
411- for linked in $(otool -L "$MACOS_DIR/SerialPrograms" | awk 'NR>1 {print $1}' | grep "$BREW_PREFIX" || true); do
412- base=$(basename "$linked")
413- if [ -f "$FW_DIR/$base" ]; then
414- install_name_tool -change "$linked" "@executable_path/../Frameworks/$base" "$MACOS_DIR/SerialPrograms"
453+ echo "=== Cleaning rpaths ==="
454+ get_rpaths() {
455+ otool -l "$1" \
456+ | awk '
457+ $1=="cmd" && $2=="LC_RPATH" {f=1}
458+ f && $1=="path" {print $2; f=0}
459+ '
460+ }
461+
462+ for rpath in $(get_rpaths "$BIN"); do
463+ if [ "$rpath" != "@executable_path/../Frameworks" ]; then
464+ echo "Removing rpath: $rpath"
465+ install_name_tool -delete_rpath "$rpath" "$BIN" || true
415466 fi
416467 done
417468
469+ if ! get_rpaths "$BIN" | grep -q "^@executable_path/../Frameworks$"; then
470+ install_name_tool -add_rpath "@executable_path/../Frameworks" "$BIN"
471+ fi
472+
473+ echo "=== Verifying no external dylib references remain ==="
474+ if otool -L "$BIN" | grep -E "/usr/local|/opt/homebrew|Cellar"; then
475+ echo "ERROR: External Homebrew dylib references remain"
476+ exit 1
477+ fi
478+
418479 echo "=== Codesigning ==="
419480 codesign --force --deep --sign - "$APP_DIR"
420- echo "Deployment complete for $(architecture)"
421481
422- echo "=== Copying app bundle to the output directory ==="
482+ echo "=== Copying app bundle to output ==="
423483 rsync -a --delete "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/SerialPrograms.app" "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/"
424- echo "https://github.com/$(Build.Repository.Name)/commit/$(Build.SourceVersion)" > $(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/version.txt
425- displayName: 'Deploy app'
426- condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
484+ echo "https://github.com/$(Build.Repository.Name)/commit/$(Build.SourceVersion)" > "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output/version.txt"
485+ echo "Deployment complete for $(architecture)"
486+ displayName: "Fix MacOS app bundle"
487+ condition: succeeded()
427488
428489 - script : |
429490 cd "$(Pipeline.Workspace)/Arduino-Source/build/$(cmake_preset)/Output"
430491 tar -zcvf ../SerialPrograms-MacOS-$(compiler)-$(architecture).tar.gz *
431492 displayName: 'Archive MacOS Output folder'
432- condition: and( succeeded(), eq(variables['Agent.OS'], 'Darwin') )
493+ condition: succeeded()
433494
434495 - task : PublishBuildArtifacts@1
435496 displayName : ' Publish SerialPrograms'
0 commit comments