TRX/.github/workflows/job_build_tr1_macos.yml
Marcin Kurczewski a64870750e build: change uthash packaging
Resolves #1856.
2024-11-19 22:51:10 +01:00

292 lines
12 KiB
YAML

name: Build TR1X and the installer (macOS)
on:
workflow_call:
inputs:
target:
type: string
description: "Target to build for"
required: true
let_mac_fail:
type: boolean
description: "Do not require Mac builds to pass"
required: false
default: false
env:
FFMPEG_INSTALL_FINAL: /opt/local
FFMPEG_INSTALL_TMP_UNIVERSAL: /tmp/install_universal
FFMPEG_INSTALL_TMP_ARM64: /tmp/install_arm64
FFMPEG_INSTALL_TMP_X86_64: /tmp/install_x86_64
CACHE_TMP_DIR: /tmp/opt_local/
CACHE_DST_DIR: /opt/local/
C_INCLUDE_PATH: /opt/local/include/uthash/:/opt/local/include/
jobs:
build:
name: Build release assets (mac)
runs-on: macos-14
continue-on-error: ${{ inputs.let_mac_fail == true || inputs.let_mac_fail == 'true' }}
steps:
- name: Set up signing certificate
env:
MACOS_KEYCHAIN_PWD: ${{ secrets.MACOS_KEYCHAIN_PWD }}
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
run: |
echo ${{ secrets.MACOS_KEYCHAIN_PWD }}
echo ${{ secrets.MACOS_CERTIFICATE }}
echo ${{ secrets.MACOS_CERTIFICATE_PWD }}
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
echo -n "$MACOS_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH
security create-keychain -p "$MACOS_KEYCHAIN_PWD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$MACOS_KEYCHAIN_PWD" $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P "$MACOS_KEYCHAIN_PWD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH -T /usr/bin/codesign
security list-keychain -d user -s $KEYCHAIN_PATH
security set-key-partition-list -S "apple-tool:,apple:,codesign:" -s -k $MACOS_KEYCHAIN_PWD $KEYCHAIN_PATH
- name: Checkout
uses: actions/checkout@v4
with:
submodules: 'true'
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Extend PATH for MacPorts
run: |
echo -e "/opt/local/bin" >> $GITHUB_PATH
echo -e "/opt/local/sbin" >> $GITHUB_PATH
- name: "Restore dependencies from cache"
id: restore-cache
uses: actions/cache/restore@v4
with:
key: ${{ runner.os }}-tooling-${{ hashFiles('.github/workflows/job_build_tr1_macos.yml') }}
path: |
${{ env.CACHE_TMP_DIR }}
${{ env.FFMPEG_INSTALL_TMP_ARM64 }}
${{ env.FFMPEG_INSTALL_TMP_X86_64 }}
${{ env.FFMPEG_INSTALL_TMP_UNIVERSAL }}
- name: "Prepare cached dependencies for use"
if: steps.restore-cache.outputs.cache-hit == 'true'
run: |
sudo rsync -arvq ${{ env.CACHE_TMP_DIR }} ${{ env.CACHE_DST_DIR }}
- name: Select latest stable Xcode
if: steps.restore-cache.outputs.cache-hit != 'true'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Install and update MacPorts
if: steps.restore-cache.outputs.cache-hit != 'true'
run: |
wget -O ${{ github.workspace }}/macports.pkg https://github.com/macports/macports-base/releases/download/v2.9.2/MacPorts-2.9.2-14-Sonoma.pkg
sudo installer -pkg ${{ github.workspace }}/macports.pkg -target /
- name: Install build and deployment tools
if: steps.restore-cache.outputs.cache-hit != 'true'
run: |
# Install Python first to avoid multiple Python in the dep tree later on.
sudo port -N install python312 py312-pip
sudo port select --set python python312
sudo port select --set python3 python312
sudo port select --set pip pip312
sudo port select --set pip3 pip312
# Install the rest.
sudo port -N install create-dmg meson ninja pkgconfig
sudo pip3 install pyjson5
- name: "Build dependencies: Compression libraries (universal)"
if: steps.restore-cache.outputs.cache-hit != 'true'
run: |
sudo port -N install zlib +universal
sudo port -N install bzip2 +universal
sudo port -N install xz +universal
- name: "Build dependency: pcre2 (universal)"
if: steps.restore-cache.outputs.cache-hit != 'true'
run: sudo port -N install pcre2 +universal
- name: "Build dependency: libsdl2 (universal)"
if: steps.restore-cache.outputs.cache-hit != 'true'
run: sudo port -N install libsdl2 +universal
- name: "Build dependency: uthash (universal)"
if: steps.restore-cache.outputs.cache-hit != 'true'
run: sudo port -N install uthash +universal
- name: "Build dependency: ffmpeg (universal)"
if: steps.restore-cache.outputs.cache-hit != 'true'
run: |
# Install to separate staging paths for all architectures in
# preparation for fusing universal libraries in a follow-up step.
cd "$RUNNER_TEMP"
git clone --depth 1 --branch "n4.4.1" https://github.com/FFmpeg/FFmpeg
cd FFmpeg
# Common FFmpeg configure options
FFMPEG_CONFIG_OPTIONS=" \
--enable-shared \
--disable-static \
$(cat $GITHUB_WORKSPACE/tools/ffmpeg_flags.txt)"
# Configure for arm64.
./configure \
--arch=arm64 \
--prefix=$FFMPEG_INSTALL_TMP_ARM64 \
--cc='clang' \
$FFMPEG_CONFIG_OPTIONS
# Build and install.
make -j$(sysctl -n hw.ncpu)
sudo make install
# Reset build directory.
make clean
# Configure for x86-64.
./configure \
--arch=x86_64 \
--enable-cross-compile \
--prefix=$FFMPEG_INSTALL_TMP_X86_64 \
--cc='clang -arch x86_64' \
$FFMPEG_CONFIG_OPTIONS
# Build and install.
make -j$(sysctl -n hw.ncpu)
sudo make install
- name: "Build dependency: ffmpeg (fuse universal libraries)"
if: steps.restore-cache.outputs.cache-hit != 'true'
run: |
# Libs
FFMPEG_LIBS=(
"libavcodec"
"libavdevice"
"libavfilter"
"libavformat"
"libavutil"
"libpostproc"
"libswresample"
"libswscale"
)
# Recreate library symlinks in MacPorts install prefix.
sudo find $FFMPEG_INSTALL_TMP_ARM64/lib -type l -exec cp -P '{}' $FFMPEG_INSTALL_FINAL/LIB ';'
# `lipo` cannot overwrite binaries in place, so we stage the
# fused binaries in a temporary directory.
mkdir -p $FFMPEG_INSTALL_TMP_UNIVERSAL
for LIB in ${FFMPEG_LIBS[@]}; do
RESOLVED_LIB=$(ls -l $FFMPEG_INSTALL_TMP_ARM64/lib/${LIB}* \
| grep -v '^l' \
| awk -F'/' '{print $NF}')
lipo -create \
$FFMPEG_INSTALL_TMP_ARM64/lib/$RESOLVED_LIB \
$FFMPEG_INSTALL_TMP_X86_64/lib/$RESOLVED_LIB \
-output $FFMPEG_INSTALL_TMP_UNIVERSAL/$RESOLVED_LIB
# Replace the arch-specific libraries with links to the universal
# binary, so `bundle_dylibs` will always gather a universal build.
sudo ln -s -f $FFMPEG_INSTALL_TMP_UNIVERSAL/$RESOLVED_LIB $FFMPEG_INSTALL_TMP_ARM64/lib/$RESOLVED_LIB
sudo ln -s -f $FFMPEG_INSTALL_TMP_UNIVERSAL/$RESOLVED_LIB $FFMPEG_INSTALL_TMP_X86_64/lib/$RESOLVED_LIB
done
# Copy the fused binaries to the MacPorts install prefix.
sudo cp $FFMPEG_INSTALL_TMP_UNIVERSAL/*.dylib $FFMPEG_INSTALL_FINAL/lib/
# Update and install pkgconfig files.
for file in "$FFMPEG_INSTALL_TMP_ARM64/lib/pkgconfig"/*.pc; do
sudo sed -i '' "s|^prefix=.*|prefix=$FFMPEG_INSTALL_FINAL|" "$file"
sudo sed -i '' "s|^libdir=.*|libdir=$FFMPEG_INSTALL_FINAL/lib|" "$file"
done
sudo mv $FFMPEG_INSTALL_TMP_ARM64/lib/pkgconfig/* $FFMPEG_INSTALL_FINAL/lib/pkgconfig/
- name: "Prepare dependencies for caching"
if: steps.restore-cache.outputs.cache-hit != 'true'
run: |
# Remove MacPorts leftover build and download files
sudo rm -rf /opt/local/var/macports/build/*
sudo rm -rf /opt/local/var/macports/distfiles/*
sudo rm -rf /opt/local/var/macports/packages/*
sudo rsync -arvq ${{ env.CACHE_DST_DIR }} ${{ env.CACHE_TMP_DIR }}
- name: "Save dependencies to cache"
if: steps.restore-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
path: |
${{ env.CACHE_TMP_DIR }}
${{ env.FFMPEG_INSTALL_TMP_ARM64 }}
${{ env.FFMPEG_INSTALL_TMP_X86_64 }}
${{ env.FFMPEG_INSTALL_TMP_UNIVERSAL }}
- name: Setup CA
run: |
sudo port -N install apple-pki-bundle curl-ca-bundle
- name: Build arm64 and create app bundle
run: |
BUILD_DIR=build-arm64
BUILD_OPTIONS="src/tr1 --prefix=/tmp/TR1X.app --bindir=Contents/MacOS --buildtype ${{ inputs.target }}"
meson setup $BUILD_DIR $BUILD_OPTIONS
meson install -C $BUILD_DIR
- name: Build x86-64
run: |
BUILD_DIR=build-x86-64
BUILD_OPTIONS="src/tr1 --prefix=/tmp/TR1X.app --bindir=Contents/MacOS --cross-file tools/tr1/mac/x86-64_cross_file.txt --buildtype ${{ inputs.target }}"
meson setup $BUILD_DIR $BUILD_OPTIONS
meson compile -C $BUILD_DIR
- name: Fuse universal executable
run: |
BUNDLE_EXEC_DIR=/tmp/TR1X.app/Contents/MacOS
# Fuse executable and move it into the app bundle.
lipo -create build-x86-64/TR1X $BUNDLE_EXEC_DIR/TR1X -output $BUNDLE_EXEC_DIR/TR1X_universal
mv $BUNDLE_EXEC_DIR/TR1X_universal $BUNDLE_EXEC_DIR/TR1X
# Update dynamic library links in the fused executable.
./tools/tr1/mac/bundle_dylibs --links-only
- name: Sign app bundle
run: |
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
IDENTITY=$(security find-identity -v -p codesigning $KEYCHAIN_PATH | awk -F'"' '{print $2}')
xattr -cr /tmp/TR1X.app
/usr/bin/codesign --force --deep --options runtime -s "${IDENTITY}" --keychain $KEYCHAIN_PATH -v /tmp/TR1X.app
- name: Create, sign and notarize disk image
env:
MACOS_APPLEID: ${{ secrets.MACOS_APPLEID }}
MACOS_APP_PWD: ${{ secrets.MACOS_APP_PWD }}
MACOS_TEAMID: ${{ secrets.MACOS_TEAMID }}
run: |
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
IDENTITY=$(security find-identity -v -p codesigning $KEYCHAIN_PATH | awk -F'"' '{print $2}')
tools/tr1/mac/create_installer
xattr -cr TR1X-Installer.dmg
/usr/bin/codesign --force --options runtime -s "${IDENTITY}" --keychain $KEYCHAIN_PATH -v TR1X-Installer.dmg
xcrun notarytool submit --wait --apple-id "$MACOS_APPLEID" --password "$MACOS_APP_PWD" --team-id "$MACOS_TEAMID" TR1X-Installer.dmg
xcrun stapler staple -v TR1X-Installer.dmg
mv TR1X-Installer.dmg "TR1X-$(tools/get_version 1)-Installer.dmg"
- id: vars
name: Prepare variables
run: echo "version=$(tools/get_version 1)" >> $GITHUB_OUTPUT
- name: Upload signed+notarized installer image
uses: actions/upload-artifact@v4
with:
name: ${{ github.event.repository.name }}-${{ steps.vars.outputs.version }}-mac
path: |
*.dmg
compression-level: 0 # .dmg is already compressed.