From e3e67110fc149856322f7431f217037f32d712d6 Mon Sep 17 00:00:00 2001 From: cheezwiz7899 Date: Sat, 2 May 2026 15:51:14 +1200 Subject: [PATCH] ci: update macos workflow to match the CI repo --- .github/workflows/build-macos.yml | 101 ++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 5be04ad..5a7415a 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -226,25 +226,114 @@ jobs: run: | set -e; mkdir -p dist APP_BUNDLE_PATH=$(find citron/build -name "citron.app" | head -n 1) + if [ -z "$APP_BUNDLE_PATH" ]; then + echo "::error::Could not find citron.app bundle after build!" + exit 1 + fi + echo "Found .app bundle at: $APP_BUNDLE_PATH" + QT_MACOS_ROOT=$(find citron/build/externals/qt -maxdepth 3 -type d -path "*/macos" | sort -V | tail -n 1) + if [ -z "$QT_MACOS_ROOT" ]; then + echo "::error::Could not find Qt macOS root under citron/build/externals/qt" + exit 1 + fi + echo "Using Qt root: $QT_MACOS_ROOT" + MACDEPLOYQT_PATH="$QT_MACOS_ROOT/bin/macdeployqt" - if [ ! -f "$MACDEPLOYQT_PATH" ]; then MACDEPLOYQT_PATH="$QT_MACOS_ROOT/bin/macdeployqt6"; fi - "$MACDEPLOYQT_PATH" "$APP_BUNDLE_PATH" -libpath="$QT_MACOS_ROOT/lib" -verbose=1 -always-overwrite - + if [ ! -f "$MACDEPLOYQT_PATH" ]; then + MACDEPLOYQT_PATH="$QT_MACOS_ROOT/bin/macdeployqt6" + fi + QT_LIB_PATH="$QT_MACOS_ROOT/lib" + + if [ ! -f "$MACDEPLOYQT_PATH" ]; then + echo "::error::Could not find macdeployqt or macdeployqt6 in $QT_MACOS_ROOT/bin" + exit 1 + fi + + "$MACDEPLOYQT_PATH" "$APP_BUNDLE_PATH" -libpath="$QT_LIB_PATH" -verbose=2 -always-overwrite + FRAMEWORKS_PATH="$APP_BUNDLE_PATH/Contents/Frameworks" + + # Create Vulkan ICD json to ensure bundled MoltenVK is used + echo "Setting up Vulkan ICD for bundled MoltenVK..." + VULKAN_ICD_DIR="$APP_BUNDLE_PATH/Contents/Resources/vulkan/icd.d" + mkdir -p "$VULKAN_ICD_DIR" + cat > "$VULKAN_ICD_DIR/MoltenVK_icd.json" << 'ICDEOF' + { + "file_format_version": "1.0.0", + "ICD": { + "library_path": "../../../Frameworks/libMoltenVK.dylib", + "api_version": "1.4.0", + "is_portability_driver": true + } + } + ICDEOF + + echo "Checking for missing transitive dependencies..." copy_missing_deps() { find "$FRAMEWORKS_PATH" -name "*.dylib" -type f | while read -r dylib; do + # Handle @rpath/ references + otool -L "$dylib" 2>/dev/null | grep -E "^\s+@rpath/" | awk '{print $1}' | sed 's|@rpath/||' | while read -r dep; do + if [ ! -f "$FRAMEWORKS_PATH/$dep" ]; then + HOMEBREW_LIB=$(find /opt/homebrew/lib /opt/homebrew/Cellar /usr/local/lib -name "$dep" 2>/dev/null | head -1) + if [ -n "$HOMEBREW_LIB" ] && [ -f "$HOMEBREW_LIB" ]; then + cp "$HOMEBREW_LIB" "$FRAMEWORKS_PATH/" + chmod u+w "$FRAMEWORKS_PATH/$dep" + install_name_tool -id "@rpath/$dep" "$FRAMEWORKS_PATH/$dep" 2>/dev/null || true + fi + fi + done + # Handle absolute homebrew path references otool -L "$dylib" 2>/dev/null | grep -E "^\s+(/opt/homebrew|/usr/local)" | awk '{print $1}' | while read -r abs_dep; do dep_name=$(basename "$abs_dep") if [ ! -f "$FRAMEWORKS_PATH/$dep_name" ] && [ -f "$abs_dep" ]; then - cp "$abs_dep" "$FRAMEWORKS_PATH/"; chmod u+w "$FRAMEWORKS_PATH/$dep_name" + cp "$abs_dep" "$FRAMEWORKS_PATH/" + chmod u+w "$FRAMEWORKS_PATH/$dep_name" install_name_tool -id "@rpath/$dep_name" "$FRAMEWORKS_PATH/$dep_name" 2>/dev/null || true fi done done } - for i in {1..3}; do copy_missing_deps; done - + for i in {1..5}; do copy_missing_deps; done + + EXECUTABLE_PATH="$APP_BUNDLE_PATH/Contents/MacOS/citron" + install_name_tool -add_rpath "@executable_path/../Frameworks" "$EXECUTABLE_PATH" 2>/dev/null || true + + # Remove absolute rpaths from executable + otool -l "$EXECUTABLE_PATH" | grep -A2 LC_RPATH | grep "path " | awk '{print $2}' | while read -r rpath; do + case "$rpath" in + @executable_path*|@loader_path*|@rpath*) ;; + *) install_name_tool -delete_rpath "$rpath" "$EXECUTABLE_PATH" 2>/dev/null || true ;; + esac + done + + find "$FRAMEWORKS_PATH" -name "*.dylib" -type f | while read -r dylib; do + dylib_name=$(basename "$dylib") + install_name_tool -id "@rpath/$dylib_name" "$dylib" 2>/dev/null || true + otool -L "$dylib" 2>/dev/null | grep -E "^\s+/" | awk '{print $1}' | while read -r dep; do + dep_name=$(basename "$dep") + if [ -f "$FRAMEWORKS_PATH/$dep_name" ]; then + install_name_tool -change "$dep" "@rpath/$dep_name" "$dylib" 2>/dev/null || true + fi + done + install_name_tool -add_rpath "@loader_path" "$dylib" 2>/dev/null || true + done + + otool -L "$EXECUTABLE_PATH" 2>/dev/null | grep -E "^\s+/" | awk '{print $1}' | while read -r dep; do + dep_name=$(basename "$dep") + if [ -f "$FRAMEWORKS_PATH/$dep_name" ]; then + install_name_tool -change "$dep" "@rpath/$dep_name" "$EXECUTABLE_PATH" 2>/dev/null || true + fi + done + + find "$FRAMEWORKS_PATH" -name "*.framework" -type d | while read -r framework_dir; do + framework_name=$(basename "$framework_dir" .framework) + framework_binary="$framework_dir/Versions/A/$framework_name" + [ ! -f "$framework_binary" ] && framework_binary="$framework_dir/$framework_name" + [ -f "$framework_binary" ] && install_name_tool -id "@rpath/$framework_name.framework/Versions/A/$framework_name" "$framework_binary" 2>/dev/null || true + done + + chmod -R u+w "$APP_BUNDLE_PATH" codesign --force --deep -s - "$APP_BUNDLE_PATH" hdiutil create -fs HFS+ -srcfolder "$APP_BUNDLE_PATH" -volname "Citron PR Build" "./Citron-macOS.dmg" mv *.dmg ./dist/