Skip to content

Commit

Permalink
Add native ARM macOS build
Browse files Browse the repository at this point in the history
  • Loading branch information
tech-ticks committed Jan 31, 2024
1 parent 4ae19f2 commit a8382be
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 19 deletions.
91 changes: 88 additions & 3 deletions .github/workflows/build-test-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ jobs:
package-mac:
runs-on: macos-11
name: Build and package for Mac OS
name: Build and package for Mac OS (Intel)
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -269,7 +269,7 @@ jobs:
- name: Upload .app
uses: actions/upload-artifact@v3
with:
name: skytemple-mac-app
name: skytemple-mac-app-x86_64
path: |
installer/skytemple-mac.zip
Expand All @@ -288,7 +288,92 @@ jobs:
- name: Upload .dmg
uses: actions/upload-artifact@v3
with:
name: skytemple-mac-dmg
name: skytemple-mac-dmg-x86_64
path: |
installer/SkyTemple*.dmg
package-mac-arm64:
runs-on: macos-14
name: Build and package for Mac OS (ARM)
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Rewrite version for dev if not tag
if: "!startsWith(github.ref, 'refs/tags/')"
run: |
perl -i -pe "s/version\s*=\s*\"(.*?)(\.rc.*|\.a.*|\.post.*)?\"/version=\"\1.dev0+${GITHUB_SHA::8}\"/" pyproject.toml
echo "IS_DEV_BUILD=1" >> $GITHUB_ENV
- name: Note version
run: |
python3 -m venv .yq-venv
. .yq-venv/bin/activate
pip install yq
echo "PACKAGE_VERSION=$(tomlq '.project.version' pyproject.toml -r)" >> $GITHUB_ENV
- name: Install and package
run: |
# git is already installed.
brew install enchant pygobject3 gtk+3 [email protected] gtksourceview4 adwaita-icon-theme sdl12-compat sdl2 meson cmake
pip3 install -U certifi
export PATH=/usr/local/opt/[email protected]/bin:/usr/local/bin:/opt/homebrew/bin:$PATH
# Install other dependencies and SkyTemple itself
pip3 install py-desmume 'pyinstaller~=5.0'
if [ -n "$IS_DEV_BUILD" ]; then
IS_MACOS=1 installer/install-skytemple-rust.sh x86_64
fi
pip3 install -r requirements-mac-windows.txt
# Generate MO localization files
installer/generate-mo.sh
pip3 install '.[eventserver]'
if [ -n "$IS_DEV_BUILD" ]; then
installer/install-skytemple-components-from-git.sh
fi
cd installer
# Install themes
curl https://skytemple.org/build_deps/Arc.zip -O
unzip Arc.zip > /dev/null
curl https://skytemple.org/build_deps/ZorinBlue.zip -O
unzip ZorinBlue.zip > /dev/null
# Download armips
curl https://skytemple.org/build_deps/mac/armips -O
chmod +x armips
# Package
if [ "$(uname -m)" = "arm64" ]; then
./build-mac-arm.sh $PACKAGE_VERSION
else
./build-mac.sh $PACKAGE_VERSION
fi
# Creating a zip makes the artifact upload much faster since there are so many files
zip -r skytemple-mac.zip dist/SkyTemple.app > /dev/null
- name: Upload .app
uses: actions/upload-artifact@v3
with:
name: skytemple-mac-app-arm64
path: |
installer/skytemple-mac.zip
- name: Create installer
run: |
export PATH=/usr/local/opt/[email protected]/bin:/usr/local/bin:/opt/homebrew/bin:$PATH
# See https://github.com/sindresorhus/create-dmg
# create-dmg automatically generates an installer icon if imagemagick is installed
brew install graphicsmagick imagemagick
npm -g install create-dmg
# This tool returns exit code 2 if the DMG was created but code signing failed for some reason
npx create-dmg --dmg-title=SkyTemple installer/dist/SkyTemple.app installer || true
- name: Upload .dmg
uses: actions/upload-artifact@v3
with:
name: skytemple-mac-dmg-arm64
path: |
installer/SkyTemple*.dmg
Expand Down
41 changes: 41 additions & 0 deletions installer/build-mac-arm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash

# Call with "PACKAGE_VERSION=[version number] ./build-mac.sh"
# The version from the current pip install of SkyTemple is used if no version number is set.
set -e

generate_version_file() {
location=$(pip3 show $1 | grep Location | cut -d":" -f 2 | cut -c2-)
pip3 show $1 | grep Version | cut -d":" -f 2 | cut -c2- > $location/$1/VERSION
}

# The VERSION files for a few dependencies are missing for some reason, so generate them from 'pip show' commands
generate_version_file cssselect2
generate_version_file tinycss2
generate_version_file cairosvg
generate_version_file cairocffi

# Create the icon
# https://www.codingforentrepreneurs.com/blog/create-icns-icons-for-macos-apps
mkdir skytemple.iconset
icons_path=../skytemple/data/icons/hicolor
cp $icons_path/16x16/apps/skytemple.png skytemple.iconset/icon_16x16.png
cp $icons_path/32x32/apps/skytemple.png skytemple.iconset/[email protected]
cp $icons_path/32x32/apps/skytemple.png skytemple.iconset/icon_32x32.png
cp $icons_path/64x64/apps/skytemple.png skytemple.iconset/[email protected]
cp $icons_path/128x128/apps/skytemple.png skytemple.iconset/icon_128x128.png
cp $icons_path/256x256/apps/skytemple.png skytemple.iconset/[email protected]
cp $icons_path/256x256/apps/skytemple.png skytemple.iconset/icon_256x256.png
cp $icons_path/512x512/apps/skytemple.png skytemple.iconset/[email protected]
cp $icons_path/512x512/apps/skytemple.png skytemple.iconset/icon_512x512.png

iconutil -c icns skytemple.iconset
rm -rf skytemple.iconset

# Build the app
pyinstaller skytemple-mac.spec --noconfirm
rm skytemple.icns

# Since the library search path for the app is wrong, execute a shell script that sets is correctly
# and launches the app instead of launching run_skytemple directly
appdir=dist/SkyTemple.app/Contents/MacOS
9 changes: 0 additions & 9 deletions installer/build-mac.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,6 @@ install_name_tool -add_rpath @executable_path/. dist/SkyTemple.app/Contents/MacO
cat > $appdir/pre_run_skytemple << EOF
#!/bin/sh
# Fix paths
export DYLD_LIBRARY_PATH="\$(dirname \$0)"
export PYENCHANT_LIBRARY_PATH="\$(dirname \$0)/libenchant-2.dylib"
export PATH="\$PATH:\$(dirname \$0)/skytemple_files/_resources"
# Disable SDL video. It's not used and would only be required with joystick/gamepad support,
# but alas it doesn't work because Cococa only supports I/O from the main thread.
export SDL_VIDEODRIVER=dummy
# Fix the language 🥲
# The output of "defaults read -g AppleLanguages" looks like this, so we need to extract
# the language code and replace "-" with "_".
Expand Down
7 changes: 6 additions & 1 deletion installer/install-skytemple-rust.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ branch="master"
wheel_name="skytemple_rust-*-cp311-cp311-win_amd64.whl"

if [ -n "$IS_MACOS" ]; then
wheel_name="skytemple_rust-*-cp311-cp311-macosx_10_9_x86_64.whl"
# Check if we're running on Apple Silicon
if [ "$(uname -m)" = "arm64" ]; then
wheel_name="skytemple_rust-*-cp311-cp311-macosx_11_0_arm64.whl"
else
wheel_name="skytemple_rust-*-cp311-cp311-macosx_10_9_x86_64.whl"
fi
fi

url="https://nightly.link/SkyTemple/skytemple-rust/workflows/build-test-publish/$branch/wheels.zip"
Expand Down
17 changes: 11 additions & 6 deletions installer/skytemple-mac.spec
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ from PyInstaller.utils.hooks import collect_entry_point, copy_metadata
pkg_path = os.path.abspath(os.path.join("..", "skytemple"))
site_packages = next(p for p in sys.path if "site-packages" in p)

# The Homebrew lib path is different on ARM and Intel
homebrew_path = os.path.join(os.sep, "usr", "local")
if os.uname().machine == "arm64":
homebrew_path = os.path.join(os.sep, "opt", "homebrew")

additional_datas = [
(os.path.join(pkg_path, "data"), "data"),
(os.path.join(pkg_path, "*.glade"), "."),
Expand Down Expand Up @@ -72,29 +77,29 @@ additional_datas = [
additional_binaries = [
(os.path.join(site_packages, "desmume", "libdesmume.dylib"), "."),
(
os.path.join(os.sep, "usr", "local", "lib", "libSDL-1.2.0.dylib"),
os.path.join(homebrew_path, "lib", "libSDL-1.2.0.dylib"),
".",
), # Must be installed with Homebrew
(
os.path.join(os.sep, "usr", "local", "lib", "libSDL2-2.0.0.dylib"),
os.path.join(homebrew_path, "lib", "libSDL2-2.0.0.dylib"),
".",
), # Must be installed with Homebrew
(
os.path.join(os.sep, "usr", "local", "lib", "libenchant-2.dylib"),
os.path.join(homebrew_path, "lib", "libenchant-2.dylib"),
".",
), # Must be installed with Homebrew
(
os.path.join(os.sep, "usr", "local", "lib", "libaspell.15.dylib"),
os.path.join(homebrew_path, "lib", "libaspell.15.dylib"),
".",
), # Gets installed with Enchant
(
os.path.join(
os.sep, "usr", "local", "lib", "enchant-2", "enchant_applespell.so"
homebrew_path, "lib", "enchant-2", "enchant_applespell.so"
),
".",
), # Gets installed with Enchant
(
os.path.join(os.sep, "usr", "local", "opt", "cairo", "lib", "libcairo.2.dylib"),
os.path.join(homebrew_path, "opt", "cairo", "lib", "libcairo.2.dylib"),
".",
),
(os.path.join(site_packages, "libtilequant.dylib"), "."),
Expand Down
13 changes: 13 additions & 0 deletions skytemple/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,26 @@
import sys
import locale
import gettext
from pathlib import Path
from skytemple.core.ui_utils import data_dir, APP, builder_get_assert
from skytemple.core.settings import SkyTempleSettingsStore
from skytemple_files.common.impl_cfg import (
ENV_SKYTEMPLE_USE_NATIVE,
change_implementation_type,
)

# Workaround for errors on macOS when running from a bundle
if sys.platform.startswith("darwin"):
base_path = Path(__file__).parent.absolute().as_posix()
os.chdir(base_path) # Set working directory to the executable directory
os.environ["DYLD_LIBRARY_PATH"] = base_path
os.environ["PATH"] = f"{base_path}/skytemple_files/_resources:{os.environ['PATH']}"
os.environ["PYENCHANT_LIBRARY_PATH"] = f"{base_path}/libenchant-2.dylib"

# Disable SDL video. It's not used and would only be required with joystick/gamepad support,
# but alas it doesn't work because Cococa only supports I/O from the main thread.
os.environ["SDL_VIDEODRIVER"] = "dummy" # Fixes the debugger not loading

settings = SkyTempleSettingsStore()

# Setup Sentry
Expand Down

0 comments on commit a8382be

Please sign in to comment.