Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 51 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,11 @@ jobs:
buildtype: release,
args: -Db_pch=false
}
- name: macOS x86_64 Debug
os: macos-15-intel
buildtype: debugoptimized
args: &macos_debug_args >-
-Dmacos_deployment_target=15.0
-Dbuild_osx_bundle=false
-Dfftw3=enabled
-Dlibpulse=disabled
-Dopenal=enabled
- name: macOS x86_64 Release
os: macos-15-intel
os: macos-15
cross_args: --cross-file tools/macos-release.ini --cross-file tools/macos-x86_64.ini
buildtype: release
args: &macos_release_args >-
args: &macos_source_args >-
-Ddefault_library=static
-Dbuild_osx_bundle=true
-Dfftw3=disabled
Expand Down Expand Up @@ -102,11 +94,17 @@ jobs:
- name: macOS arm64 Debug
os: macos-15
buildtype: debugoptimized
args: *macos_debug_args
args: >-
-Dmacos_deployment_target=15.0
-Dbuild_osx_bundle=false
-Dfftw3=enabled
-Dlibpulse=disabled
-Dopenal=enabled
- name: macOS arm64 Release
os: macos-15
native_args: --native-file tools/macos-release.ini
buildtype: release
args: *macos_release_args
args: *macos_source_args

steps:
- uses: actions/checkout@v6
Expand Down Expand Up @@ -159,17 +157,34 @@ jobs:

echo "PKG_CONFIG_PATH=$(brew --prefix icu4c)/lib/pkgconfig:$(brew --prefix zlib)/lib/pkgconfig" >> "${GITHUB_ENV}"

- name: Install dependencies (macOS Release)
- name: Install build tools (macOS source dependencies)
if: startsWith(matrix.config.os, 'macos-') && matrix.config.buildtype == 'release'
run: |
brew install ninja nasm

- name: Check Rosetta (macOS cross builds)
if: matrix.config.cross_args
run: |
if ! /usr/bin/arch -x86_64 /usr/bin/true; then
sudo softwareupdate --install-rosetta --agree-to-license
fi
/usr/bin/arch -x86_64 /usr/bin/true

- name: Install test dependencies (macOS)
if: startsWith(matrix.config.os, 'macos-')
env:
CROSS_ARGS: ${{ matrix.config.cross_args }}
run: |
# LuaJIT is Lua 5.1 to luarocks.
brew install luajit luarocks
luarocks --lua-dir="$(brew --prefix luajit)" --lua-version=5.1 install busted
if test -n "${CROSS_ARGS}"; then
# Busted's native modules are loaded by the Intel test executable.
luarocks --lua-dir="$(brew --prefix luajit)" --lua-version=5.1 install busted \
CC='/usr/bin/clang -arch x86_64' \
LD='/usr/bin/clang -arch x86_64'
else
luarocks --lua-dir="$(brew --prefix luajit)" --lua-version=5.1 install busted
fi

- name: Install dependencies (Linux)
if: startsWith(matrix.config.os, 'ubuntu-')
Expand All @@ -184,7 +199,7 @@ jobs:
- name: Configure
run: |
${{ matrix.config.devenv }}
meson setup build ${{ matrix.config.args }} -Dbuildtype=${{ matrix.config.buildtype }} ${{ github.ref_type == 'tag' && '-Dofficial_release=true' || '' }}
meson setup build ${{ matrix.config.native_args }} ${{ matrix.config.cross_args }} ${{ matrix.config.args }} -Dbuildtype=${{ matrix.config.buildtype }} ${{ github.ref_type == 'tag' && '-Dofficial_release=true' || '' }}

- name: Build FFTW (MacOS)
if: startsWith(matrix.config.os, 'macos-') && matrix.config.buildtype == 'release'
Expand All @@ -199,6 +214,14 @@ jobs:
${{ matrix.config.devenv }}
meson compile -C build

- name: Verify Intel cross-build architecture
if: matrix.config.cross_args
run: |
test "$(lipo -archs build/aegisub)" = x86_64
test "$(lipo -archs build/tests/gtest-main)" = x86_64
test "$(lipo -archs build/tests/luajit-52)" = x86_64
test "$(lipo -archs build/automation/tests/aegisub-lua)" = x86_64

# The automation suite is registered at configure time only if the
# busted probe succeeds, so make sure it can't silently drop out of CI
- name: Check automation tests are registered
Expand All @@ -211,6 +234,18 @@ jobs:
${{ matrix.config.devenv }}
meson test -C build --verbose --suite Aegisub

- name: Check cross-built tests executed
if: matrix.config.cross_args
run: |
python3 - <<'PY'
import json
from pathlib import Path

results = [json.loads(line) for line in Path('build/meson-logs/testlog.json').read_text().splitlines()]
if not results or any(result['result'] != 'OK' for result in results):
raise SystemExit('Cross-built tests must pass under Rosetta, not be skipped')
PY

# Windows artifacts
- name: Generate Windows installer
if: matrix.config.os == 'windows-latest'
Expand Down
26 changes: 26 additions & 0 deletions docs/developer_docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,32 @@ the notary service and stapled. This follows Apple's nested-container guidance;
the app and every nested Mach-O file are still Developer ID-signed before the
DMG is created.

## Intel macOS cross builds

The Intel Release CI lane uses an Apple Silicon runner with
`--cross-file tools/macos-release.ini --cross-file tools/macos-x86_64.ini`.
Compilation uses native Apple Silicon tools targeting x86_64; Rosetta runs
the resulting Intel test executables.
This checks the Intel code path, but does not replace testing a release on
real Intel hardware.

The Intel lane builds its target dependencies from source using the shared
macOS release dependency options in `.github/workflows/ci.yml`. Both Release
lanes use `tools/macos-release.ini` to restrict pkg-config and CMake dependency
discovery away from Homebrew; arm64 loads it with `--native-file`. Homebrew is
still used for build tools. The native arm64 Debug lane still uses
Homebrew libraries and is tested but not packaged. Intel coverage comes from
the Release lane, including tests under Rosetta.

For a local cross build, use the same dependency options and cross files as CI.
After Meson setup, run `tools/macos-build-fftw.sh BUILD_DIR`, then reconfigure
with `-Dpkg_config_path="$PWD/BUILD_DIR/fftw-prefix/lib/pkgconfig"`
and `-Dfftw3=enabled`. The bootstrap reads the target architecture from Meson
and only passes Autoconf's `--host` option when it differs from the build CPU.
Automation tests also need Intel builds of Busted's native Lua modules; the
workflow shows the LuaRocks compiler overrides. Use a separate LuaRocks tree
if native arm64 tests need to run on the same machine.

## Running Doxygen

You can run Doxygen with the following command:
Expand Down
30 changes: 25 additions & 5 deletions tools/macos-build-fftw.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,17 @@ FFTW_SHA256="5630c24cdeb33b131612f7eb4b1a9934234754f9f388ff8617458d0be6f239a1"
FFTW_URL="https://fftw.org/fftw-${FFTW_VERSION}.tar.gz"
FFTW_PREFIX="${BUILD_DIR}/fftw-prefix"
FFTW_STAMP="${FFTW_PREFIX}/.aegisub-build"
ARCH="$(uname -m)"
EXPECTED_STAMP="fftw=${FFTW_VERSION} arch=${ARCH} macos=${DEPLOYMENT_TARGET}"
ARCH="$(meson introspect --machines "${BUILD_DIR}" | python3 -c '
import json
import sys

machine = json.load(sys.stdin)["host"]
if machine["system"] != "darwin":
raise SystemExit("FFTW macOS bootstrap requires a Darwin host")
print({"aarch64": "arm64", "x86_64": "x86_64"}.get(machine["cpu_family"], machine["cpu_family"]))
')"
BUILD_ARCH="$(uname -m)"
EXPECTED_STAMP="fftw=${FFTW_VERSION} arch=${ARCH} build=${BUILD_ARCH} macos=${DEPLOYMENT_TARGET}"

if test -f "${FFTW_STAMP}" && test "$(cat "${FFTW_STAMP}")" = "${EXPECTED_STAMP}"; then
echo "Using existing FFTW build: ${EXPECTED_STAMP}"
Expand Down Expand Up @@ -62,12 +71,19 @@ rm -rf "${FFTW_PREFIX}"
mkdir -p "${FFTW_PREFIX}"

cd "${WORK_DIR}/fftw-${FFTW_VERSION}"
export CFLAGS="-O3 -mmacosx-version-min=${DEPLOYMENT_TARGET}"
export LDFLAGS="-mmacosx-version-min=${DEPLOYMENT_TARGET}"
export CC=/usr/bin/clang
export CFLAGS="-O3 -arch ${ARCH} -mmacosx-version-min=${DEPLOYMENT_TARGET}"
export LDFLAGS="-arch ${ARCH} -mmacosx-version-min=${DEPLOYMENT_TARGET}"

# Keep runtime probes enabled for native builds.
set -- "--build=$(./config.guess)"
if test "${ARCH}" != "${BUILD_ARCH}"; then
set -- "$@" "--host=${ARCH}-apple-darwin"
fi

# Aegisub only uses FFTW's single-threaded, double-precision API.
# shellcheck disable=SC2086
./configure \
./configure "$@" \
--prefix="${FFTW_PREFIX}" \
--disable-shared \
--enable-static \
Expand All @@ -80,6 +96,10 @@ export LDFLAGS="-mmacosx-version-min=${DEPLOYMENT_TARGET}"

make -s -j"$(sysctl -n hw.logicalcpu)"
make -s install
if test "$(lipo -archs "${FFTW_PREFIX}/lib/libfftw3.a")" != "${ARCH}"; then
echo "FFTW library architecture does not match Meson's host: ${ARCH}" >&2
exit 1
fi
printf '%s\n' "${EXPECTED_STAMP}" > "${FFTW_STAMP}"

echo "Built FFTW ${FFTW_VERSION} for macOS ${DEPLOYMENT_TARGET} (${ARCH})"
Expand Down
9 changes: 9 additions & 0 deletions tools/macos-release.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Use Homebrew build tools, but exclude its target libraries from discovery.
[properties]
pkg_config_libdir = ['/usr/lib/pkgconfig']

[built-in options]
pkg_config_path = []

[cmake]
CMAKE_IGNORE_PREFIX_PATH = ['/opt/homebrew', '/usr/local']
24 changes: 24 additions & 0 deletions tools/macos-x86_64.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Build Intel binaries with native Apple Silicon tools; run tests via Rosetta.
# Combine with macos-release.ini for target dependency search paths.
[binaries]
c = ['/usr/bin/clang', '-arch', 'x86_64']
cpp = ['/usr/bin/clang++', '-arch', 'x86_64']
objc = ['/usr/bin/clang', '-arch', 'x86_64']
objcpp = ['/usr/bin/clang++', '-arch', 'x86_64']
ar = '/usr/bin/ar'
strip = '/usr/bin/strip'
pkg-config = 'pkg-config'
cmake = 'cmake'
exe_wrapper = ['/usr/bin/arch', '-x86_64']

[host_machine]
system = 'darwin'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

[properties]
needs_exe_wrapper = true

[cmake]
CMAKE_OSX_ARCHITECTURES = 'x86_64'