Package macOS releases as a universal binary.

* Minimum macOS version is raised to 10.11.
* App bundles ship 3 versions of the runtime and engine binaries,
  and a fat launcher that selects the appropriate runtime/apphost.
* Mono is used for macOS 10.11 - 10.14, or if OPENRA_PREFER_MONO
  environment variable has been set.
This commit is contained in:
Paul Chote
2022-12-18 11:24:50 +13:00
committed by Gustas
parent 363a0e1d1e
commit e2e541a251
7 changed files with 420 additions and 565 deletions

View File

@@ -21,8 +21,10 @@ if [[ "${OSTYPE}" != "darwin"* ]]; then
exit 1
fi
if [ $# -ne "4" ]; then
echo "Usage: $(basename "$0") tag outputdir platform dmg"
command -v clang >/dev/null 2>&1 || { echo >&2 "macOS packaging requires clang."; exit 1; }
if [ $# -ne "2" ]; then
echo "Usage: $(basename "$0") tag outputdir"
exit 1
fi
@@ -45,6 +47,7 @@ fi
TAG="${1}"
OUTPUTDIR="${2}"
SRCDIR="$(pwd)/../.."
BUILTDIR="$(pwd)/build"
ARTWORK_DIR="$(pwd)/../artwork/"
@@ -55,15 +58,13 @@ modify_plist() {
# Copies the game files and sets metadata
build_app() {
PLATFORM="${1}"
TEMPLATE_DIR="${2}"
LAUNCHER_DIR="${3}"
MOD_ID="${4}"
MOD_NAME="${5}"
DISCORD_APPID="${6}"
TEMPLATE_DIR="${1}"
LAUNCHER_DIR="${2}"
MOD_ID="${3}"
MOD_NAME="${4}"
DISCORD_APPID="${5}"
LAUNCHER_CONTENTS_DIR="${LAUNCHER_DIR}/Contents"
LAUNCHER_ASSEMBLY_DIR="${LAUNCHER_CONTENTS_DIR}/MacOS"
LAUNCHER_RESOURCES_DIR="${LAUNCHER_CONTENTS_DIR}/Resources"
cp -r "${TEMPLATE_DIR}" "${LAUNCHER_DIR}"
@@ -74,12 +75,10 @@ build_app() {
fi
# Install engine and mod files
RUNTIME="net6"
if [ "${PLATFORM}" = "mono" ]; then
RUNTIME="mono"
fi
install_assemblies "${SRCDIR}" "${LAUNCHER_CONTENTS_DIR}/MacOS/x86_64" "osx-x64" "net6" "True" "True" "${IS_D2K}"
install_assemblies "${SRCDIR}" "${LAUNCHER_CONTENTS_DIR}/MacOS/arm64" "osx-arm64" "net6" "True" "True" "${IS_D2K}"
install_assemblies "${SRCDIR}" "${LAUNCHER_CONTENTS_DIR}/MacOS/mono" "osx-x64" "mono" "True" "True" "${IS_D2K}"
install_assemblies "${SRCDIR}" "${LAUNCHER_ASSEMBLY_DIR}" "osx-x64" "${RUNTIME}" "True" "True" "${IS_D2K}"
install_data "${SRCDIR}" "${LAUNCHER_RESOURCES_DIR}" "${MOD_ID}"
set_engine_version "${TAG}" "${LAUNCHER_RESOURCES_DIR}"
set_mod_version "${TAG}" "${LAUNCHER_RESOURCES_DIR}/mods/${MOD_ID}/mod.yaml" "${LAUNCHER_RESOURCES_DIR}/mods/modcontent/mod.yaml"
@@ -110,82 +109,101 @@ build_app() {
fi
}
build_platform() {
PLATFORM="${1}"
DMG_PATH="${2}"
echo "Building launchers (${PLATFORM})"
echo "Building launchers"
# Prepare generic template for the mods to duplicate and customize
TEMPLATE_DIR="${BUILTDIR}/template.app"
mkdir -p "${TEMPLATE_DIR}/Contents/Resources"
mkdir -p "${TEMPLATE_DIR}/Contents/MacOS"
echo "APPL????" > "${TEMPLATE_DIR}/Contents/PkgInfo"
cp Info.plist.in "${TEMPLATE_DIR}/Contents/Info.plist"
modify_plist "{DEV_VERSION}" "${TAG}" "${TEMPLATE_DIR}/Contents/Info.plist"
modify_plist "{FAQ_URL}" "http://wiki.openra.net/FAQ" "${TEMPLATE_DIR}/Contents/Info.plist"
# Prepare generic template for the mods to duplicate and customize
TEMPLATE_DIR="${BUILTDIR}/template.app"
mkdir -p "${TEMPLATE_DIR}/Contents/Resources"
mkdir -p "${TEMPLATE_DIR}/Contents/MacOS/mono"
mkdir -p "${TEMPLATE_DIR}/Contents/MacOS/x86_64"
mkdir -p "${TEMPLATE_DIR}/Contents/MacOS/arm64"
if [ "${PLATFORM}" = "mono" ]; then
modify_plist "{MINIMUM_SYSTEM_VERSION}" "10.9" "${TEMPLATE_DIR}/Contents/Info.plist"
clang -m64 launcher-mono.m -o "${TEMPLATE_DIR}/Contents/MacOS/Launcher" -framework AppKit -mmacosx-version-min=10.9
else
modify_plist "{MINIMUM_SYSTEM_VERSION}" "10.14" "${TEMPLATE_DIR}/Contents/Info.plist"
clang -m64 launcher.m -o "${TEMPLATE_DIR}/Contents/MacOS/Launcher" -framework AppKit -mmacosx-version-min=10.14
fi
echo "APPL????" > "${TEMPLATE_DIR}/Contents/PkgInfo"
cp Info.plist.in "${TEMPLATE_DIR}/Contents/Info.plist"
modify_plist "{DEV_VERSION}" "${TAG}" "${TEMPLATE_DIR}/Contents/Info.plist"
modify_plist "{FAQ_URL}" "http://wiki.openra.net/FAQ" "${TEMPLATE_DIR}/Contents/Info.plist"
modify_plist "{MINIMUM_SYSTEM_VERSION}" "10.11" "${TEMPLATE_DIR}/Contents/Info.plist"
build_app "${PLATFORM}" "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Red Alert.app" "ra" "Red Alert" "699222659766026240"
build_app "${PLATFORM}" "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Tiberian Dawn.app" "cnc" "Tiberian Dawn" "699223250181292033"
build_app "${PLATFORM}" "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Dune 2000.app" "d2k" "Dune 2000" "712711732770111550"
# Compile universal (x86_64 + arm64) Launcher and arch-specific apphosts
clang apphost.c -o "${TEMPLATE_DIR}/Contents/MacOS/apphost-x86_64" -framework AppKit -target x86_64-apple-macos10.15
clang apphost.c -o "${TEMPLATE_DIR}/Contents/MacOS/apphost-arm64" -framework AppKit -target arm64-apple-macos10.15
clang apphost-mono.c -o "${TEMPLATE_DIR}/Contents/MacOS/apphost-mono" -framework AppKit -target x86_64-apple-macos10.11
clang checkmono.c -o "${TEMPLATE_DIR}/Contents/MacOS/checkmono" -framework AppKit -target x86_64-apple-macos10.11
clang launcher.m -o "${TEMPLATE_DIR}/Contents/MacOS/Launcher-x86_64" -framework AppKit -target x86_64-apple-macos10.11
clang launcher.m -o "${TEMPLATE_DIR}/Contents/MacOS/Launcher-arm64" -framework AppKit -target arm64-apple-macos10.15
lipo -create -output "${TEMPLATE_DIR}/Contents/MacOS/Launcher" "${TEMPLATE_DIR}/Contents/MacOS/Launcher-x86_64" "${TEMPLATE_DIR}/Contents/MacOS/Launcher-arm64"
rm "${TEMPLATE_DIR}/Contents/MacOS/Launcher-x86_64" "${TEMPLATE_DIR}/Contents/MacOS/Launcher-arm64"
rm -rf "${TEMPLATE_DIR}"
build_app "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Red Alert.app" "ra" "Red Alert" "699222659766026240"
build_app "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Tiberian Dawn.app" "cnc" "Tiberian Dawn" "699223250181292033"
build_app "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Dune 2000.app" "d2k" "Dune 2000" "712711732770111550"
echo "Packaging disk image"
hdiutil create "${DMG_PATH}" -format UDRW -volname "OpenRA" -fs HFS+ -srcfolder build
DMG_DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "${DMG_PATH}" | egrep '^/dev/' | sed 1q | awk '{print $1}')
sleep 2
rm -rf "${TEMPLATE_DIR}"
# Background image is created from source svg in artsrc repository
mkdir "/Volumes/OpenRA/.background/"
tiffutil -cathidpicheck "${ARTWORK_DIR}/macos-background.png" "${ARTWORK_DIR}/macos-background-2x.png" -out "/Volumes/OpenRA/.background/background.tiff"
echo "Packaging disk image"
hdiutil create "build.dmg" -format UDRW -volname "OpenRA" -fs HFS+ -srcfolder build
DMG_DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "build.dmg" | egrep '^/dev/' | sed 1q | awk '{print $1}')
sleep 2
cp "${BUILTDIR}/OpenRA - Red Alert.app/Contents/Resources/ra.icns" "/Volumes/OpenRA/.VolumeIcon.icns"
# Background image is created from source svg in artsrc repository
mkdir "/Volumes/OpenRA/.background/"
tiffutil -cathidpicheck "${ARTWORK_DIR}/macos-background.png" "${ARTWORK_DIR}/macos-background-2x.png" -out "/Volumes/OpenRA/.background/background.tiff"
echo '
tell application "Finder"
tell disk "'OpenRA'"
open
set current view of container window to icon view
set toolbar visible of container window to false
set statusbar visible of container window to false
set the bounds of container window to {400, 100, 1040, 580}
set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 72
set background picture of theViewOptions to file ".background:background.tiff"
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
set position of item "'OpenRA - Tiberian Dawn.app'" of container window to {160, 106}
set position of item "'OpenRA - Red Alert.app'" of container window to {320, 106}
set position of item "'OpenRA - Dune 2000.app'" of container window to {480, 106}
set position of item "Applications" of container window to {320, 298}
set position of item ".background" of container window to {160, 298}
set position of item ".fseventsd" of container window to {160, 298}
set position of item ".VolumeIcon.icns" of container window to {160, 298}
update without registering applications
delay 5
close
end tell
end tell
' | osascript
cp "${BUILTDIR}/OpenRA - Red Alert.app/Contents/Resources/ra.icns" "/Volumes/OpenRA/.VolumeIcon.icns"
# HACK: Copy the volume icon again - something in the previous step seems to delete it...?
cp "${BUILTDIR}/OpenRA - Red Alert.app/Contents/Resources/ra.icns" "/Volumes/OpenRA/.VolumeIcon.icns"
SetFile -c icnC "/Volumes/OpenRA/.VolumeIcon.icns"
SetFile -a C "/Volumes/OpenRA"
echo '
tell application "Finder"
tell disk "'OpenRA'"
open
set current view of container window to icon view
set toolbar visible of container window to false
set statusbar visible of container window to false
set the bounds of container window to {400, 100, 1040, 580}
set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 72
set background picture of theViewOptions to file ".background:background.tiff"
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
set position of item "'OpenRA - Tiberian Dawn.app'" of container window to {160, 106}
set position of item "'OpenRA - Red Alert.app'" of container window to {320, 106}
set position of item "'OpenRA - Dune 2000.app'" of container window to {480, 106}
set position of item "Applications" of container window to {320, 298}
set position of item ".background" of container window to {160, 298}
set position of item ".fseventsd" of container window to {160, 298}
set position of item ".VolumeIcon.icns" of container window to {160, 298}
update without registering applications
delay 5
close
end tell
end tell
' | osascript
# Replace duplicate .NET runtime files with hard links to improve compression
if [ "${PLATFORM}" != "mono" ]; then
for MOD in "Red Alert" "Tiberian Dawn"; do
for f in "/Volumes/OpenRA/OpenRA - ${MOD}.app/Contents/MacOS"/*; do
g="/Volumes/OpenRA/OpenRA - Dune 2000.app/Contents/MacOS/"$(basename "${f}")
# HACK: Copy the volume icon again - something in the previous step seems to delete it...?
cp "${BUILTDIR}/OpenRA - Red Alert.app/Contents/Resources/ra.icns" "/Volumes/OpenRA/.VolumeIcon.icns"
SetFile -c icnC "/Volumes/OpenRA/.VolumeIcon.icns"
SetFile -a C "/Volumes/OpenRA"
# Replace duplicate .NET runtime files with hard links to improve compression
for MOD in "Red Alert" "Tiberian Dawn"; do
for p in "x86_64" "arm64" "mono"; do
for f in "/Volumes/OpenRA/OpenRA - ${MOD}.app/Contents/MacOS/${p}"/*; do
g="/Volumes/OpenRA/OpenRA - Dune 2000.app/Contents/MacOS/${p}/"$(basename "${f}")
hashf=$(shasum "${f}" | awk '{ print $1 }') || :
hashg=$(shasum "${g}" | awk '{ print $1 }') || :
if [ -n "${hashf}" ] && [ "${hashf}" = "${hashg}" ]; then
echo "Deduplicating ${f}"
rm "${f}"
ln "${g}" "${f}"
fi
done
done
done
for MOD in "Red Alert" "Tiberian Dawn" "Dune 2000"; do
for p in "arm64" "mono"; do
for f in "/Volumes/OpenRA/OpenRA - ${MOD}.app/Contents/MacOS/x86_64"/*; do
g="/Volumes/OpenRA/OpenRA - ${MOD}.app/Contents/MacOS/${p}/"$(basename "${f}")
if [ -e "${g}" ]; then
hashf=$(shasum "${f}" | awk '{ print $1 }') || :
hashg=$(shasum "${g}" | awk '{ print $1 }') || :
if [ -n "${hashf}" ] && [ "${hashf}" = "${hashg}" ]; then
@@ -193,35 +211,37 @@ build_platform() {
rm "${f}"
ln "${g}" "${f}"
fi
done
fi
done
fi
done
done
chmod -Rf go-w /Volumes/OpenRA
sync
sync
chmod -Rf go-w /Volumes/OpenRA
sync
sync
hdiutil detach "${DMG_DEVICE}"
rm -rf "${BUILTDIR}"
}
hdiutil detach "${DMG_DEVICE}"
rm -rf "${BUILTDIR}"
notarize_package() {
DMG_PATH="${1}"
NOTARIZE_DMG_PATH="${DMG_PATH%.*}"-notarization.dmg
echo "Submitting ${DMG_PATH} for notarization"
if [ -n "${MACOS_DEVELOPER_CERTIFICATE_BASE64}" ] && [ -n "${MACOS_DEVELOPER_CERTIFICATE_PASSWORD}" ] && [ -n "${MACOS_DEVELOPER_IDENTITY}" ]; then
security delete-keychain build.keychain
fi
if [ -n "${MACOS_DEVELOPER_USERNAME}" ] && [ -n "${MACOS_DEVELOPER_PASSWORD}" ] && [ -n "${MACOS_DEVELOPER_IDENTITY}" ]; then
echo "Submitting build for notarization"
# Reset xcode search path to fix xcrun not finding altool
sudo xcode-select -r
# Create a temporary read-only dmg for submission (notarization service rejects read/write images)
hdiutil convert "${DMG_PATH}" -format ULFO -ov -o "${NOTARIZE_DMG_PATH}"
hdiutil convert "build.dmg" -format ULFO -ov -o "build-notarization.dmg"
xcrun notarytool submit "${NOTARIZE_DMG_PATH}" --wait --apple-id "${MACOS_DEVELOPER_USERNAME}" --password "${MACOS_DEVELOPER_PASSWORD}" --team-id "${MACOS_DEVELOPER_IDENTITY}"
xcrun notarytool submit "build-notarization.dmg" --wait --apple-id "${MACOS_DEVELOPER_USERNAME}" --password "${MACOS_DEVELOPER_PASSWORD}" --team-id "${MACOS_DEVELOPER_IDENTITY}"
rm "${NOTARIZE_DMG_PATH}"
rm "build-notarization.dmg"
echo "${DMG_PATH}: Stapling tickets"
DMG_DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "${DMG_PATH}" | egrep '^/dev/' | sed 1q | awk '{print $1}')
echo "Stapling tickets"
DMG_DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "build.dmg" | egrep '^/dev/' | sed 1q | awk '{print $1}')
sleep 2
xcrun stapler staple "/Volumes/OpenRA/OpenRA - Red Alert.app"
@@ -232,35 +252,7 @@ notarize_package() {
sync
hdiutil detach "${DMG_DEVICE}"
break
}
finalize_package() {
PLATFORM="${1}"
INPUT_PATH="${2}"
OUTPUT_PATH="${3}"
if [ "${PLATFORM}" = "mono" ]; then
hdiutil convert "${INPUT_PATH}" -format UDZO -imagekey zlib-level=9 -ov -o "${OUTPUT_PATH}-mono.dmg"
else
# ULFO offers better compression and faster decompression speeds, but is only supported by 10.11+
hdiutil convert "${INPUT_PATH}" -format ULFO -ov -o "${OUTPUT_PATH}.dmg"
fi
rm "${INPUT_PATH}"
}
PLATFORM="$3"
DISK_IMAGE="$4"
build_platform "${PLATFORM}" "${DISK_IMAGE}"
if [ -n "${MACOS_DEVELOPER_CERTIFICATE_BASE64}" ] && [ -n "${MACOS_DEVELOPER_CERTIFICATE_PASSWORD}" ] && [ -n "${MACOS_DEVELOPER_IDENTITY}" ]; then
security delete-keychain build.keychain
fi
if [ -n "${MACOS_DEVELOPER_USERNAME}" ] && [ -n "${MACOS_DEVELOPER_PASSWORD}" ] && [ -n "${MACOS_DEVELOPER_IDENTITY}" ]; then
notarize_package "${DISK_IMAGE}"
fi
finalize_package "${PLATFORM}" "${DISK_IMAGE}" "${OUTPUTDIR}/OpenRA-${TAG}"
hdiutil convert "build.dmg" -format ULFO -ov -o "${OUTPUTDIR}/OpenRA-${TAG}.dmg"
rm "build.dmg"