mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 20:58:07 +03:00
tr2: add mac builds
This commit is contained in:
parent
dbf75ced05
commit
e88a28c39f
18 changed files with 500 additions and 224 deletions
181
.github/actions/prepare_macos_tooling/action.yml
vendored
Normal file
181
.github/actions/prepare_macos_tooling/action.yml
vendored
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
name: Cache TRX MacOS Dependencies
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
FFMPEG_INSTALL_TMP_ARM64:
|
||||||
|
required: false
|
||||||
|
default: /opt/local/install_arm64
|
||||||
|
FFMPEG_INSTALL_TMP_X86_64:
|
||||||
|
required: false
|
||||||
|
default: /opt/local/install_x86_64
|
||||||
|
CACHE_SRC_DIR:
|
||||||
|
required: false
|
||||||
|
default: /opt/local
|
||||||
|
CACHE_DIR:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- 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'
|
||||||
|
shell: bash
|
||||||
|
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'
|
||||||
|
shell: bash
|
||||||
|
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'
|
||||||
|
shell: bash
|
||||||
|
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'
|
||||||
|
shell: bash
|
||||||
|
run: sudo port -N install pcre2 +universal
|
||||||
|
|
||||||
|
- name: "Build dependency: libsdl2 (universal)"
|
||||||
|
if: steps.restore-cache.outputs.cache-hit != 'true'
|
||||||
|
shell: bash
|
||||||
|
run: sudo port -N install libsdl2 +universal
|
||||||
|
|
||||||
|
- name: "Build dependency: uthash (universal)"
|
||||||
|
if: steps.restore-cache.outputs.cache-hit != 'true'
|
||||||
|
shell: bash
|
||||||
|
run: sudo port -N install uthash +universal
|
||||||
|
|
||||||
|
- name: "Build dependency: ffmpeg (universal)"
|
||||||
|
if: steps.restore-cache.outputs.cache-hit != 'true'
|
||||||
|
shell: bash
|
||||||
|
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=${{ inputs.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=${{ inputs.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'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# Libs
|
||||||
|
FFMPEG_LIBS=(
|
||||||
|
"libavcodec"
|
||||||
|
"libavdevice"
|
||||||
|
"libavfilter"
|
||||||
|
"libavformat"
|
||||||
|
"libavutil"
|
||||||
|
"libpostproc"
|
||||||
|
"libswresample"
|
||||||
|
"libswscale"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Recreate include tree in MacPorts install prefix.
|
||||||
|
sudo rsync -arvL ${{ inputs.FFMPEG_INSTALL_TMP_ARM64 }}/include/ ${{ inputs.CACHE_SRC_DIR }}/include/
|
||||||
|
|
||||||
|
# Recreate library symlinks in MacPorts install prefix.
|
||||||
|
sudo find ${{ inputs.FFMPEG_INSTALL_TMP_ARM64 }}/lib/ -type l -exec cp -P '{}' ${{ inputs.CACHE_SRC_DIR }}/lib/ ';'
|
||||||
|
|
||||||
|
# Fuse platform-specific binaries into a universal binary.
|
||||||
|
for LIB in ${FFMPEG_LIBS[@]}; do
|
||||||
|
RESOLVED_LIB=$(ls -l ${{ inputs.FFMPEG_INSTALL_TMP_ARM64 }}/lib/${LIB}* \
|
||||||
|
| grep -v '^l' \
|
||||||
|
| awk -F'/' '{print $NF}')
|
||||||
|
|
||||||
|
sudo lipo -create \
|
||||||
|
${{ inputs.FFMPEG_INSTALL_TMP_ARM64 }}/lib/$RESOLVED_LIB \
|
||||||
|
${{ inputs.FFMPEG_INSTALL_TMP_X86_64 }}/lib/$RESOLVED_LIB \
|
||||||
|
-output ${{ inputs.CACHE_SRC_DIR }}/lib/$RESOLVED_LIB
|
||||||
|
|
||||||
|
sudo ln -s -f \
|
||||||
|
${{ inputs.CACHE_SRC_DIR }}/lib/$RESOLVED_LIB \
|
||||||
|
${{ inputs.FFMPEG_INSTALL_TMP_ARM64 }}/lib/$RESOLVED_LIB
|
||||||
|
sudo ln -s -f \
|
||||||
|
${{ inputs.CACHE_SRC_DIR }}/lib/$RESOLVED_LIB \
|
||||||
|
${{ inputs.FFMPEG_INSTALL_TMP_X86_64 }}/lib/$RESOLVED_LIB
|
||||||
|
done
|
||||||
|
|
||||||
|
# Update and install pkgconfig files.
|
||||||
|
for file in "${{ inputs.FFMPEG_INSTALL_TMP_ARM64 }}/lib/pkgconfig"/*.pc; do
|
||||||
|
sudo sed -i '' "s:${{ inputs.FFMPEG_INSTALL_TMP_ARM64 }}:${{ inputs.CACHE_SRC_DIR }}:g" "$file"
|
||||||
|
done
|
||||||
|
sudo mv ${{ inputs.FFMPEG_INSTALL_TMP_ARM64 }}/lib/pkgconfig/* ${{ inputs.CACHE_SRC_DIR }}/lib/pkgconfig/
|
||||||
|
|
||||||
|
- name: "Prepare dependencies for caching"
|
||||||
|
if: steps.restore-cache.outputs.cache-hit != 'true'
|
||||||
|
shell: bash
|
||||||
|
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/*
|
||||||
|
|
||||||
|
# Delete broken symlinks
|
||||||
|
sudo find ${{ inputs.CACHE_SRC_DIR }} -type l ! -exec test -e {} \; -exec rm {} \;
|
||||||
|
|
||||||
|
# Trying to cache the source directory directly leads to permission errors,
|
||||||
|
# so copy it to an intermediate temporary directory. Also, expands all the symlinks to hard copies.
|
||||||
|
sudo rsync -arvqL ${{ inputs.CACHE_SRC_DIR }}/ ${{ inputs.CACHE_DIR }}
|
||||||
|
|
||||||
|
- name: "Save dependencies to cache"
|
||||||
|
if: steps.restore-cache.outputs.cache-hit != 'true'
|
||||||
|
uses: actions/cache/save@v4
|
||||||
|
with:
|
||||||
|
key: ${{ runner.os }}-tooling-${{ hashFiles('.github/actions/prepare_macos_tooling/action.yml') }}
|
||||||
|
path: |
|
||||||
|
${{ inputs.CACHE_DIR }}
|
177
.github/workflows/job_build_tr1_macos.yml
vendored
177
.github/workflows/job_build_tr1_macos.yml
vendored
|
@ -59,174 +59,23 @@ jobs:
|
||||||
echo -e "/opt/local/bin" >> $GITHUB_PATH
|
echo -e "/opt/local/bin" >> $GITHUB_PATH
|
||||||
echo -e "/opt/local/sbin" >> $GITHUB_PATH
|
echo -e "/opt/local/sbin" >> $GITHUB_PATH
|
||||||
|
|
||||||
- name: "Restore dependencies from cache"
|
- name: "Try restore dependencies from cache"
|
||||||
id: restore-cache
|
id: restore-cache
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
key: ${{ runner.os }}-tooling-${{ hashFiles('.github/workflows/job_build_tr1_macos.yml') }}
|
key: ${{ runner.os }}-tooling-${{ hashFiles('.github/actions/prepare_macos_tooling/action.yml') }}
|
||||||
path: |
|
path: |
|
||||||
${{ env.CACHE_TMP_DIR }}
|
/tmp/opt_local/
|
||||||
${{ env.FFMPEG_INSTALL_TMP_ARM64 }}
|
- name: "Build MacOS dependencies"
|
||||||
${{ env.FFMPEG_INSTALL_TMP_X86_64 }}
|
if: steps.restore-cache.outputs.cache-hit != 'true'
|
||||||
${{ env.FFMPEG_INSTALL_TMP_UNIVERSAL }}
|
uses: ./.github/actions/prepare_macos_tooling
|
||||||
|
with:
|
||||||
|
CACHE_DIR: /tmp/opt_local/
|
||||||
- name: "Prepare cached dependencies for use"
|
- name: "Prepare cached dependencies for use"
|
||||||
if: steps.restore-cache.outputs.cache-hit == 'true'
|
if: steps.restore-cache.outputs.cache-hit == 'true'
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo rsync -arvq ${{ env.CACHE_TMP_DIR }} ${{ env.CACHE_DST_DIR }}
|
sudo rsync -arvq /tmp/opt_local/ /opt/local/
|
||||||
|
|
||||||
- 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
|
- name: Setup CA
|
||||||
run: |
|
run: |
|
||||||
|
@ -242,7 +91,7 @@ jobs:
|
||||||
- name: Build x86-64
|
- name: Build x86-64
|
||||||
run: |
|
run: |
|
||||||
BUILD_DIR=build-x86-64
|
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 }}"
|
BUILD_OPTIONS="src/tr1 --prefix=/tmp/TR1X.app --bindir=Contents/MacOS --cross-file tools/shared/mac/x86-64_cross_file.txt --buildtype ${{ inputs.target }}"
|
||||||
meson setup $BUILD_DIR $BUILD_OPTIONS
|
meson setup $BUILD_DIR $BUILD_OPTIONS
|
||||||
meson compile -C $BUILD_DIR
|
meson compile -C $BUILD_DIR
|
||||||
|
|
||||||
|
@ -255,7 +104,7 @@ jobs:
|
||||||
mv $BUNDLE_EXEC_DIR/TR1X_universal $BUNDLE_EXEC_DIR/TR1X
|
mv $BUNDLE_EXEC_DIR/TR1X_universal $BUNDLE_EXEC_DIR/TR1X
|
||||||
|
|
||||||
# Update dynamic library links in the fused executable.
|
# Update dynamic library links in the fused executable.
|
||||||
./tools/tr1/mac/bundle_dylibs --links-only
|
./tools/shared/mac/bundle_dylibs -a TR1X --links-only
|
||||||
|
|
||||||
- name: Sign app bundle
|
- name: Sign app bundle
|
||||||
run: |
|
run: |
|
||||||
|
@ -272,7 +121,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||||
IDENTITY=$(security find-identity -v -p codesigning $KEYCHAIN_PATH | awk -F'"' '{print $2}')
|
IDENTITY=$(security find-identity -v -p codesigning $KEYCHAIN_PATH | awk -F'"' '{print $2}')
|
||||||
tools/tr1/mac/create_installer
|
tools/shared/mac/create_installer -a TR1X -i data/tr1/mac/icon.icns
|
||||||
xattr -cr TR1X-Installer.dmg
|
xattr -cr TR1X-Installer.dmg
|
||||||
/usr/bin/codesign --force --options runtime -s "${IDENTITY}" --keychain $KEYCHAIN_PATH -v 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 notarytool submit --wait --apple-id "$MACOS_APPLEID" --password "$MACOS_APP_PWD" --team-id "$MACOS_TEAMID" TR1X-Installer.dmg
|
||||||
|
|
132
.github/workflows/job_build_tr2_macos.yml
vendored
Normal file
132
.github/workflows/job_build_tr2_macos.yml
vendored
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
name: Build TR2X 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:
|
||||||
|
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: |
|
||||||
|
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: "Try restore dependencies from cache"
|
||||||
|
id: restore-cache
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
with:
|
||||||
|
key: ${{ runner.os }}-tooling-${{ hashFiles('.github/actions/prepare_macos_tooling/action.yml') }}
|
||||||
|
path: |
|
||||||
|
/tmp/opt_local/
|
||||||
|
- name: "Build MacOS dependencies"
|
||||||
|
if: steps.restore-cache.outputs.cache-hit != 'true'
|
||||||
|
uses: ./.github/actions/prepare_macos_tooling
|
||||||
|
with:
|
||||||
|
CACHE_DIR: /tmp/opt_local/
|
||||||
|
- name: "Prepare cached dependencies for use"
|
||||||
|
if: steps.restore-cache.outputs.cache-hit == 'true'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo rsync -arvq /tmp/opt_local/ /opt/local/
|
||||||
|
|
||||||
|
- 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/tr2 --prefix=/tmp/TR2X.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/tr2 --prefix=/tmp/TR2X.app --bindir=Contents/MacOS --cross-file tools/shared/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/TR2X.app/Contents/MacOS
|
||||||
|
|
||||||
|
# Fuse executable and move it into the app bundle.
|
||||||
|
lipo -create build-x86-64/TR2X $BUNDLE_EXEC_DIR/TR2X -output $BUNDLE_EXEC_DIR/TR2X_universal
|
||||||
|
mv $BUNDLE_EXEC_DIR/TR2X_universal $BUNDLE_EXEC_DIR/TR2X
|
||||||
|
|
||||||
|
# Update dynamic library links in the fused executable.
|
||||||
|
./tools/shared/mac/bundle_dylibs -a TR2X --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/TR2X.app
|
||||||
|
/usr/bin/codesign --force --deep --options runtime -s "${IDENTITY}" --keychain $KEYCHAIN_PATH -v /tmp/TR2X.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/shared/mac/create_installer -a TR2X -i data/tr2/mac/icon.icns
|
||||||
|
xattr -cr TR2X-Installer.dmg
|
||||||
|
/usr/bin/codesign --force --options runtime -s "${IDENTITY}" --keychain $KEYCHAIN_PATH -v TR2X-Installer.dmg
|
||||||
|
xcrun notarytool submit --wait --apple-id "$MACOS_APPLEID" --password "$MACOS_APP_PWD" --team-id "$MACOS_TEAMID" TR2X-Installer.dmg
|
||||||
|
xcrun stapler staple -v TR2X-Installer.dmg
|
||||||
|
mv TR2X-Installer.dmg "TR2X-$(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: TR2X-${{ steps.vars.outputs.version }}-mac
|
||||||
|
path: |
|
||||||
|
*.dmg
|
||||||
|
compression-level: 0 # .dmg is already compressed.
|
9
.github/workflows/pr_builds.yml
vendored
9
.github/workflows/pr_builds.yml
vendored
|
@ -33,3 +33,12 @@ jobs:
|
||||||
with:
|
with:
|
||||||
target: 'debug'
|
target: 'debug'
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
package_tr2_mac:
|
||||||
|
name: Build TR2
|
||||||
|
if: vars.MACOS_ENABLE == 'true'
|
||||||
|
uses: ./.github/workflows/job_build_tr2_macos.yml
|
||||||
|
with:
|
||||||
|
target: 'debug'
|
||||||
|
let_mac_fail: true
|
||||||
|
secrets: inherit
|
||||||
|
|
12
.github/workflows/prerelease.yml
vendored
12
.github/workflows/prerelease.yml
vendored
|
@ -36,6 +36,17 @@ jobs:
|
||||||
target: 'debug'
|
target: 'debug'
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
package_tr2_mac:
|
||||||
|
name: Build TR2
|
||||||
|
if: |
|
||||||
|
vars.PRERELEASE_ENABLE == 'true' &&
|
||||||
|
vars.MACOS_ENABLE == 'true'
|
||||||
|
uses: ./.github/workflows/job_build_tr2_macos.yml
|
||||||
|
with:
|
||||||
|
target: 'debug'
|
||||||
|
let_mac_fail: true
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
publish_prerelease:
|
publish_prerelease:
|
||||||
if: vars.PRERELEASE_ENABLE == 'true'
|
if: vars.PRERELEASE_ENABLE == 'true'
|
||||||
name: Create a prerelease
|
name: Create a prerelease
|
||||||
|
@ -43,6 +54,7 @@ jobs:
|
||||||
- package_tr1_multiplatform
|
- package_tr1_multiplatform
|
||||||
- package_tr1_mac
|
- package_tr1_mac
|
||||||
- package_tr2_multiplatform
|
- package_tr2_multiplatform
|
||||||
|
- package_tr2_mac
|
||||||
with:
|
with:
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|
12
data/tr2/mac/Info.plist
Normal file
12
data/tr2/mac/Info.plist
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.lostartifacts.tr1x</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>TR2X</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>icon</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
BIN
data/tr2/mac/icon.icns
Normal file
BIN
data/tr2/mac/icon.icns
Normal file
Binary file not shown.
|
@ -50,6 +50,28 @@ Subsequent builds:
|
||||||
|
|
||||||
Run WSL and continue with the instructions from the `Compiling on Ubuntu` section.
|
Run WSL and continue with the instructions from the `Compiling on Ubuntu` section.
|
||||||
|
|
||||||
|
### Compiling on MacOS
|
||||||
|
|
||||||
|
MacPorts:
|
||||||
|
https://github.com/macports/macports-base/releases
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- **With Docker**:
|
||||||
|
|
||||||
|
Make sure to install Docker and [just](https://github.com/casey/just).
|
||||||
|
To see the list of all possible build targets, run `just -l`. To build the
|
||||||
|
images, use the `just *-build-*` commands relevant to the game and platform
|
||||||
|
you want to build for. The binaries should appear in the `build/`
|
||||||
|
directory.
|
||||||
|
|
||||||
|
- **Without Docker**:
|
||||||
|
|
||||||
|
This scenario is not officially supported, but you can see how it's done by
|
||||||
|
examining the files in the `tools/*/docker/` directory for the external
|
||||||
|
dependencies and `meson.build` for the local files, then tailoring your
|
||||||
|
system to match the process.
|
||||||
|
|
||||||
|
|
||||||
### Supported compilers
|
### Supported compilers
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ MacOS builds require a paid Apple Developer account.
|
||||||
5. Serialize the key in base-64 without spaces - run:
|
5. Serialize the key in base-64 without spaces - run:
|
||||||
|
|
||||||
> base64 TR1X.pem|tr -d '\n'
|
> base64 TR1X.pem|tr -d '\n'
|
||||||
|
> base64 -i BUILD_CERTIFICATE.p12 | pbcopy (macos)
|
||||||
|
|
||||||
The result is to be put as the value of the `MACOS_CERTIFICATE` secret.
|
The result is to be put as the value of the `MACOS_CERTIFICATE` secret.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/tr2-0.8...develop) - ××××-××-××
|
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/tr2-0.8...develop) - ××××-××-××
|
||||||
- added Linux builds and toolchain (#1598)
|
- added Linux builds and toolchain (#1598)
|
||||||
|
- added macOS builds (for both Apple Silicon and Intel) (#2226)
|
||||||
- added pause dialog (#1638)
|
- added pause dialog (#1638)
|
||||||
- added a photo mode feature (#2277)
|
- added a photo mode feature (#2277)
|
||||||
- added fade-out effect to the demos
|
- added fade-out effect to the demos
|
||||||
|
|
|
@ -131,6 +131,7 @@ game with new enhancements and features.
|
||||||
|
|
||||||
#### Miscellaneous
|
#### Miscellaneous
|
||||||
- added Linux builds
|
- added Linux builds
|
||||||
|
- added macOS builds
|
||||||
- added .jpeg/.png screenshots
|
- added .jpeg/.png screenshots
|
||||||
- added ability to skip FMVs with both the Action key
|
- added ability to skip FMVs with both the Action key
|
||||||
- added ability to skip end credits with the Action and Escape keys
|
- added ability to skip end credits with the Action and Escape keys
|
||||||
|
|
|
@ -301,5 +301,5 @@ if host_machine.system() == 'darwin'
|
||||||
install_subdir('../../data/tr1/ship/shaders', install_dir : 'Contents/Resources')
|
install_subdir('../../data/tr1/ship/shaders', install_dir : 'Contents/Resources')
|
||||||
install_data('../../data/tr1/mac/icon.icns', install_dir : 'Contents/Resources')
|
install_data('../../data/tr1/mac/icon.icns', install_dir : 'Contents/Resources')
|
||||||
install_data('../../data/tr1/mac/Info.plist', install_dir : 'Contents')
|
install_data('../../data/tr1/mac/Info.plist', install_dir : 'Contents')
|
||||||
meson.add_install_script('../../tools/tr1/mac/bundle_dylibs')
|
meson.add_install_script('../../tools/shared/mac/bundle_dylibs', '-a', 'TR1X')
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -824,8 +824,8 @@ int32_t Output_GetObjectBounds(const BOUNDS_16 *const bounds)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int32_t vtx_count = 8;
|
const int32_t vtx_count = 8;
|
||||||
const XYZ_32 vtx[vtx_count] = {
|
const XYZ_32 vtx[] = {
|
||||||
{ .x = bounds->min.x, .y = bounds->min.y, .z = bounds->min.z },
|
{ .x = bounds->min.x, .y = bounds->min.y, .z = bounds->min.z },
|
||||||
{ .x = bounds->max.x, .y = bounds->min.y, .z = bounds->min.z },
|
{ .x = bounds->max.x, .y = bounds->min.y, .z = bounds->min.z },
|
||||||
{ .x = bounds->max.x, .y = bounds->max.y, .z = bounds->min.z },
|
{ .x = bounds->max.x, .y = bounds->max.y, .z = bounds->min.z },
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
#include <libtrx/memory.h>
|
#include <libtrx/memory.h>
|
||||||
#include <libtrx/utils.h>
|
#include <libtrx/utils.h>
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <SDL2/SDL_video.h>
|
||||||
|
|
||||||
static RENDERER m_Renderer_SW = {};
|
static RENDERER m_Renderer_SW = {};
|
||||||
static RENDERER m_Renderer_HW = {};
|
static RENDERER m_Renderer_HW = {};
|
||||||
static RENDERER *m_PreviousRenderer = NULL;
|
static RENDERER *m_PreviousRenderer = NULL;
|
||||||
|
@ -32,6 +35,7 @@ static struct {
|
||||||
static RENDERER *M_GetRenderer(void);
|
static RENDERER *M_GetRenderer(void);
|
||||||
static void M_ReuploadBackground(void);
|
static void M_ReuploadBackground(void);
|
||||||
static void M_ResetPolyList(void);
|
static void M_ResetPolyList(void);
|
||||||
|
static void M_SetGLBackend(GFX_GL_BACKEND backend);
|
||||||
|
|
||||||
static RENDERER *M_GetRenderer(void)
|
static RENDERER *M_GetRenderer(void)
|
||||||
{
|
{
|
||||||
|
@ -69,15 +73,60 @@ static void M_ResetPolyList(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void M_SetGLBackend(const GFX_GL_BACKEND backend)
|
||||||
|
{
|
||||||
|
switch (backend) {
|
||||||
|
case GFX_GL_21:
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GFX_GL_33C:
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(
|
||||||
|
SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GFX_GL_INVALID_BACKEND:
|
||||||
|
ASSERT_FAIL();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Render_Init(void)
|
void Render_Init(void)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("");
|
// TODO Move to libtrx later and combine with S_Shell_CreateWindow.
|
||||||
GFX_Context_Attach(g_SDLWindow, GFX_GL_33C);
|
const GFX_GL_BACKEND backends_to_try[] = {
|
||||||
|
// clang-format off
|
||||||
|
GFX_GL_33C,
|
||||||
|
GFX_GL_21,
|
||||||
|
GFX_GL_INVALID_BACKEND, // guard
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int32_t i = 0; backends_to_try[i] != GFX_GL_INVALID_BACKEND; i++) {
|
||||||
|
const GFX_GL_BACKEND backend = backends_to_try[i];
|
||||||
|
|
||||||
|
M_SetGLBackend(backend);
|
||||||
|
|
||||||
|
int32_t major;
|
||||||
|
int32_t minor;
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
|
||||||
|
LOG_DEBUG("Trying GL backend %d.%d", major, minor);
|
||||||
|
if (GFX_Context_Attach(g_SDLWindow, backend)) {
|
||||||
GFX_Context_SetRenderingMode(GFX_RM_FRAMEBUFFER);
|
GFX_Context_SetRenderingMode(GFX_RM_FRAMEBUFFER);
|
||||||
m_FadeRenderer = GFX_FadeRenderer_Create();
|
m_FadeRenderer = GFX_FadeRenderer_Create();
|
||||||
m_BackgroundRenderer = GFX_2D_Renderer_Create();
|
m_BackgroundRenderer = GFX_2D_Renderer_Create();
|
||||||
Renderer_SW_Prepare(&m_Renderer_SW);
|
Renderer_SW_Prepare(&m_Renderer_SW);
|
||||||
Renderer_HW_Prepare(&m_Renderer_HW);
|
Renderer_HW_Prepare(&m_Renderer_HW);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Shell_ExitSystem("System Error: cannot attach opengl context");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render_Shutdown(void)
|
void Render_Shutdown(void)
|
||||||
|
|
|
@ -36,6 +36,11 @@ build_opts = [
|
||||||
|
|
||||||
add_project_arguments(build_opts, language: 'c')
|
add_project_arguments(build_opts, language: 'c')
|
||||||
|
|
||||||
|
# Always dynamically link on macOS
|
||||||
|
if host_machine.system() == 'darwin'
|
||||||
|
staticdeps = false
|
||||||
|
endif
|
||||||
|
|
||||||
null_dep = dependency('', required: false)
|
null_dep = dependency('', required: false)
|
||||||
dep_trx = trx.get_variable('dep_trx')
|
dep_trx = trx.get_variable('dep_trx')
|
||||||
dep_sdl2 = dependency('SDL2', static: staticdeps)
|
dep_sdl2 = dependency('SDL2', static: staticdeps)
|
||||||
|
@ -301,4 +306,14 @@ executable(
|
||||||
link_args: link_args,
|
link_args: link_args,
|
||||||
dependencies: dependencies,
|
dependencies: dependencies,
|
||||||
win_subsystem: 'windows',
|
win_subsystem: 'windows',
|
||||||
|
install: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if host_machine.system() == 'darwin'
|
||||||
|
install_subdir('../../data/tr2/ship/cfg', install_dir : 'Contents/Resources')
|
||||||
|
install_subdir('../../data/tr2/ship/data', install_dir : 'Contents/Resources')
|
||||||
|
install_subdir('../../data/tr2/ship/shaders', install_dir : 'Contents/Resources')
|
||||||
|
install_data('../../data/tr2/mac/icon.icns', install_dir : 'Contents/Resources')
|
||||||
|
install_data('../../data/tr2/mac/Info.plist', install_dir : 'Contents')
|
||||||
|
meson.add_install_script('../../tools/shared/mac/bundle_dylibs', '-a', 'TR2X')
|
||||||
|
endif
|
||||||
|
|
|
@ -2,28 +2,19 @@
|
||||||
import argparse
|
import argparse
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
from collections.abc import Iterable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from subprocess import check_output, run
|
from subprocess import check_output, run
|
||||||
|
|
||||||
# Configuration
|
|
||||||
APP_NAME = "TR1X"
|
|
||||||
APP_BUNDLE_PATH = Path(f"/tmp/{APP_NAME}.app")
|
|
||||||
APP_BINARY_PATH = APP_BUNDLE_PATH / f"Contents/MacOS/{APP_NAME}"
|
|
||||||
FRAMEWORKS_PATH = APP_BUNDLE_PATH / "Contents/Frameworks"
|
|
||||||
IGNORE_LIB_PREFIXES = ("/usr/lib/", "/System/", "@executable_path")
|
IGNORE_LIB_PREFIXES = ("/usr/lib/", "/System/", "@executable_path")
|
||||||
|
RPATH_PATTERN = re.compile(r"@rpath/(.*)")
|
||||||
|
|
||||||
# Other global state
|
|
||||||
LIBRARY_PATHS: set[Path] = set()
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args() -> argparse.Namespace:
|
def parse_args() -> argparse.Namespace:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description=(
|
description="Copies shared libraries into the macOS app bundle."
|
||||||
f"Copies shared libraries into the macOS app bundle "
|
|
||||||
"for {APP_NAME}."
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
parser.add_argument("-a", "--app-name")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--copy-only",
|
"--copy-only",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
|
@ -41,32 +32,33 @@ def should_ignore_lib(lib_path: str) -> bool:
|
||||||
return any(lib_path.startswith(prefix) for prefix in IGNORE_LIB_PREFIXES)
|
return any(lib_path.startswith(prefix) for prefix in IGNORE_LIB_PREFIXES)
|
||||||
|
|
||||||
|
|
||||||
def gather_libs(binary_path: Path) -> None:
|
def gather_libs(
|
||||||
|
binary_path: Path, visited_paths: set[Path] | None = None
|
||||||
|
) -> Iterable[Path]:
|
||||||
|
if visited_paths is None:
|
||||||
|
visited_paths = set()
|
||||||
|
visited_paths.add(binary_path)
|
||||||
|
|
||||||
parent_path = binary_path.parent
|
parent_path = binary_path.parent
|
||||||
output = check_output(["otool", "-L", str(binary_path)], text=True)
|
output = check_output(["otool", "-L", str(binary_path)], text=True)
|
||||||
libs = [line.split()[0] for line in output.split("\n")[1:] if line]
|
libs = [line.split()[0] for line in output.split("\n")[1:] if line]
|
||||||
|
|
||||||
rpath_pattern = re.compile(r"@rpath/(.*)")
|
|
||||||
|
|
||||||
for lib in libs:
|
for lib in libs:
|
||||||
match = rpath_pattern.match(lib)
|
match = RPATH_PATTERN.match(lib)
|
||||||
lib_path = parent_path / (match.group(1) if match else lib)
|
lib_path = parent_path / (match.group(1) if match else lib)
|
||||||
|
|
||||||
if (
|
if should_ignore_lib(str(lib_path)) or lib_path == binary_path:
|
||||||
should_ignore_lib(str(lib_path))
|
|
||||||
or lib_path in LIBRARY_PATHS
|
|
||||||
or lib_path == binary_path
|
|
||||||
):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
LIBRARY_PATHS.add(lib_path)
|
yield lib_path
|
||||||
gather_libs(lib_path)
|
if lib_path not in visited_paths:
|
||||||
|
yield from gather_libs(lib_path, visited_paths=visited_paths)
|
||||||
|
|
||||||
|
|
||||||
def copy_libs() -> None:
|
def copy_libs(frameworks_path: Path, library_paths: set[Path]) -> None:
|
||||||
FRAMEWORKS_PATH.mkdir(parents=True, exist_ok=True)
|
frameworks_path.mkdir(parents=True, exist_ok=True)
|
||||||
for lib_path in LIBRARY_PATHS:
|
for lib_path in library_paths:
|
||||||
target_path = FRAMEWORKS_PATH / lib_path.name
|
target_path = frameworks_path / lib_path.name
|
||||||
if not target_path.exists():
|
if not target_path.exists():
|
||||||
print(f"Copying {lib_path} to {target_path}")
|
print(f"Copying {lib_path} to {target_path}")
|
||||||
shutil.copy2(lib_path, target_path)
|
shutil.copy2(lib_path, target_path)
|
||||||
|
@ -93,17 +85,21 @@ def update_links(binary_path: Path) -> None:
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
|
||||||
|
app_bundle_path = Path(f"/tmp/{args.app_name}.app")
|
||||||
|
app_binary_path = app_bundle_path / f"Contents/MacOS/{args.app_name}"
|
||||||
|
frameworks_path = app_bundle_path / "Contents/Frameworks"
|
||||||
|
|
||||||
if args.copy_only or not args.links_only:
|
if args.copy_only or not args.links_only:
|
||||||
gather_libs(APP_BINARY_PATH)
|
library_paths = set(gather_libs(app_binary_path))
|
||||||
copy_libs()
|
copy_libs(frameworks_path, library_paths)
|
||||||
|
|
||||||
if args.links_only or not args.copy_only:
|
if args.links_only or not args.copy_only:
|
||||||
for lib_path in FRAMEWORKS_PATH.glob("*"):
|
for lib_path in frameworks_path.glob("*"):
|
||||||
update_links(lib_path)
|
update_links(lib_path)
|
||||||
|
|
||||||
update_links(APP_BINARY_PATH)
|
update_links(app_binary_path)
|
||||||
|
|
||||||
print(f"Libraries for {APP_NAME} copied and updated.")
|
print(f"Libraries for {args.app_name} copied and updated.")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
|
@ -4,27 +4,21 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Configuration
|
|
||||||
APP_NAME = "TR1X"
|
|
||||||
APP_BUNDLE_PATH = Path(f"/tmp/{APP_NAME}.app")
|
|
||||||
DMG_NAME = Path(f"{APP_NAME}-Installer.dmg")
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args() -> argparse.Namespace:
|
def parse_args() -> argparse.Namespace:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(description=f"Create a DMG installer.")
|
||||||
description=f"Create a DMG installer for {APP_NAME}."
|
parser.add_argument("-a", "--app-name")
|
||||||
)
|
parser.add_argument("-i", "--icon-path", type=Path)
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def create_dmg(app_name: str, dmg_name: str, app_bundle_path: Path) -> None:
|
def create_dmg(app_name: str, dmg_name: str, icon_path: Path, app_bundle_path: Path) -> None:
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
(
|
(
|
||||||
"create-dmg",
|
"create-dmg",
|
||||||
"--volname",
|
"--volname",
|
||||||
f"{APP_NAME} Installer",
|
f"{app_name} Installer",
|
||||||
"--volicon",
|
"--volicon",
|
||||||
"data/tr1/mac/icon.icns",
|
str(icon_path),
|
||||||
"--window-pos",
|
"--window-pos",
|
||||||
"200",
|
"200",
|
||||||
"120",
|
"120",
|
||||||
|
@ -34,11 +28,11 @@ def create_dmg(app_name: str, dmg_name: str, app_bundle_path: Path) -> None:
|
||||||
"--icon-size",
|
"--icon-size",
|
||||||
"100",
|
"100",
|
||||||
"--icon",
|
"--icon",
|
||||||
f"{APP_NAME}.app",
|
f"{app_name}.app",
|
||||||
"200",
|
"200",
|
||||||
"190",
|
"190",
|
||||||
"--hide-extension",
|
"--hide-extension",
|
||||||
f"{APP_NAME}.app",
|
f"{app_name}.app",
|
||||||
"--app-drop-link",
|
"--app-drop-link",
|
||||||
"600",
|
"600",
|
||||||
"185",
|
"185",
|
||||||
|
@ -51,10 +45,12 @@ def create_dmg(app_name: str, dmg_name: str, app_bundle_path: Path) -> None:
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
|
||||||
if DMG_NAME.is_file():
|
dmg_name = Path(f"{args.app_name}-Installer.dmg")
|
||||||
DMG_NAME.unlink()
|
if dmg_name.is_file():
|
||||||
|
dmg_name.unlink()
|
||||||
|
|
||||||
create_dmg(APP_NAME, DMG_NAME, APP_BUNDLE_PATH)
|
app_bundle_path = Path(f"/tmp/{args.app_name}.app")
|
||||||
|
create_dmg(args.app_name, dmg_name, args.icon_path, app_bundle_path)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
Loading…
Add table
Add a link
Reference in a new issue