Skip to content

Commit 9bb7e8a

Browse files
committed
Try to replace hard-coded dep copy for app bundle
1 parent 3c1fca9 commit 9bb7e8a

File tree

1 file changed

+125
-64
lines changed

1 file changed

+125
-64
lines changed

SerialPrograms/azure-pipelines.yml

Lines changed: 125 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -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

4240
jobs:
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

Comments
 (0)