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
128 changes: 94 additions & 34 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ jobs:
build:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}
env:
# Pull request checkouts use a detached merge commit. Preserve the source
# branch in generated non-release version and artifact names.
AEGISUB_BUILD_BRANCH: ${{ github.head_ref || github.ref_name }}

strategy:
fail-fast: false
Expand Down Expand Up @@ -55,30 +59,55 @@ jobs:
buildtype: release,
args: -Db_pch=false
}
- {
name: macOS x86_64 Debug,
os: macos-15-intel,
buildtype: debugoptimized,
args: -Ddefault_library=static -Dbuild_osx_bundle=true -Dlocal_boost=true --force-fallback-for=ffms2
}
- {
name: macOS x86_64 Release,
os: macos-15-intel,
buildtype: release,
args: -Ddefault_library=static -Dbuild_osx_bundle=true -Dlocal_boost=true --force-fallback-for=ffms2
}
- {
name: macOS arm64 Debug,
os: macos-15,
buildtype: debugoptimized,
args: -Ddefault_library=static -Dbuild_osx_bundle=true -Dlocal_boost=true --force-fallback-for=ffms2
}
- {
name: macOS arm64 Release,
os: macos-15,
buildtype: release,
args: -Ddefault_library=static -Dbuild_osx_bundle=true -Dlocal_boost=true --force-fallback-for=ffms2
}
- 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
buildtype: release
args: &macos_release_args >-
-Ddefault_library=static
-Dbuild_osx_bundle=true
-Dfftw3=disabled
-Dlibpulse=disabled
-Dopenal=enabled
-Dlibass:fontconfig=disabled
-Dlibass:libunibreak=disabled
-Dlibass:test=disabled
-Dfreetype2:bzip2=disabled
-Dfreetype2:brotli=disabled
-Dfreetype2:hvf=disabled
-Dfribidi:bin=false
-Dfribidi:docs=false
-Dfribidi:tests=false
-Dharfbuzz:gpu=disabled
-Dharfbuzz:raster=disabled
-Dharfbuzz:subset=disabled
-Dharfbuzz:tests=disabled
-Dharfbuzz:utilities=disabled
-Dharfbuzz:vector=disabled
-Dffmpeg:bzlib=disabled
-Dffmpeg:lzma=disabled
-Dffmpeg:programs=disabled
-Dffmpeg:tests=disabled
-Ddav1d:enable_tests=false
-Ddav1d:enable_tools=false
-Dzlib:tests=disabled
--force-fallback-for=boost,wxWidgets,libass,zlib,freetype2,fribidi,harfbuzz,libpng,ffms2,libavformat,libavcodec,libswscale,libavutil,libswresample,dav1d,hunspell,uchardet,icu-uc,icu-i18n,libcurl
- name: macOS arm64 Debug
os: macos-15
buildtype: debugoptimized
args: *macos_debug_args
- name: macOS arm64 Release
os: macos-15
buildtype: release
args: *macos_release_args

steps:
- uses: actions/checkout@v6
Expand Down Expand Up @@ -124,13 +153,17 @@ jobs:
Get-Location | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
popd

- name: Install dependencies (MacOS)
if: startsWith(matrix.config.os, 'macos-')
- name: Install dependencies (macOS Debug)
if: startsWith(matrix.config.os, 'macos-') && matrix.config.buildtype == 'debugoptimized'
run: |
brew install ninja pkg-config libass boost zlib libpng ffms2 fftw hunspell uchardet icu4c wxwidgets

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

- name: Install dependencies (macOS Release)
if: startsWith(matrix.config.os, 'macos-') && matrix.config.buildtype == 'release'
run: |
brew update
brew install ninja
brew install libass zlib ffms2 fftw hunspell
brew install pulseaudio # NO OpenAL in github CI
brew install ninja nasm

- name: Install dependencies (Linux)
if: startsWith(matrix.config.os, 'ubuntu-')
Expand All @@ -143,6 +176,14 @@ jobs:
${{ matrix.config.devenv }}
meson setup build ${{ 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'
run: |
tools/macos-build-fftw.sh build
meson setup --reconfigure --clearcache build \
-Dpkg_config_path="$PWD/build/fftw-prefix/lib/pkgconfig" \
-Dfftw3=enabled

- name: Build
run: |
${{ matrix.config.devenv }}
Expand Down Expand Up @@ -181,11 +222,16 @@ jobs:
if: matrix.config.os == 'windows-latest'
with:
name: ${{ matrix.config.name }} - portable
path: build/aegisub-portable-64.zip
path: build/Aegisub-*-portable.zip
if-no-files-found: error

# macOS artifacts
- name: Generate macOS installer
if: startsWith(matrix.config.os, 'macos-')
if: startsWith(matrix.config.os, 'macos-') && matrix.config.buildtype == 'release'
env:
# CI artifacts are intentionally ad-hoc signed. Release managers must
# explicitly replace this with a Developer ID signature before release.
AEGISUB_BUNDLE_SIGNATURE: '-'
run: |
meson compile osx-bundle -C build

Expand All @@ -201,11 +247,25 @@ jobs:
i=$((i+1))
done

- name: Archive macOS app for local signing
if: startsWith(matrix.config.os, 'macos-') && matrix.config.buildtype == 'release' && (github.ref_type == 'tag' || github.event_name == 'workflow_dispatch')
run: |
package_name="$(tools/osx-package-name.sh build/Aegisub.app)"
ditto -c -k --sequesterRsrc --keepParent build/Aegisub.app "build/${package_name}-signing-input.zip"

- name: Upload macOS local-signing input
uses: actions/upload-artifact@v6
if: startsWith(matrix.config.os, 'macos-') && matrix.config.buildtype == 'release' && (github.ref_type == 'tag' || github.event_name == 'workflow_dispatch')
with:
name: ${{ matrix.config.name }} - local signing input
path: build/Aegisub-*-signing-input.zip
if-no-files-found: error

- name: Upload artifacts - macOS dmg
uses: actions/upload-artifact@v6
if: startsWith(matrix.config.os, 'macos-')
if: startsWith(matrix.config.os, 'macos-') && matrix.config.buildtype == 'release'
with:
name: ${{ matrix.config.name }} - installer
name: ${{ matrix.config.name }} - ad-hoc installer
path: build/Aegisub-*.dmg
if-no-files-found: error

Expand Down
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,27 @@ When compiling on Apple Silicon, replace `/usr/local` with `/opt/homebrew`.

Once the dependencies are installed, build Aegisub with `meson build && meson compile -C build`.

#### Build dmg
#### Build a local DMG

Homebrew bottles target the macOS release they were built for, which may be
newer than Aegisub's default deployment target. For a local package, target
the current macOS major release and explicitly request an ad-hoc signature.
The resulting DMG is for development and personal use on that macOS release;
release packages use CI's source-built dependencies and the
[macOS release-signing process](docs/developer_docs.md#macos-release-signing).

```bash
meson build_static -Ddefault_library=static -Dbuildtype=debugoptimized -Dbuild_osx_bundle=true -Dlocal_boost=true
deployment_target="$(sw_vers -productVersion)"
meson setup build_static \
-Ddefault_library=static \
-Dbuildtype=debugoptimized \
-Dbuild_osx_bundle=true \
-Dmacos_deployment_target="${deployment_target}" \
--force-fallback-for=boost
meson compile -C build_static
meson test -C build_static --verbose
meson compile osx-bundle -C build_static
meson compile osx-build-dmg -C build_static
AEGISUB_BUNDLE_SIGNATURE=- meson compile osx-build-dmg -C build_static
```

### Linux or other
Expand Down
92 changes: 91 additions & 1 deletion docs/developer_docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,97 @@ Follow the following steps to release a new Aegisub version:
- Add the release to the update checking server
- If needed, create a support branch for backports, keeping the master branch free for larger changes

### macOS release signing

Tagged and manually dispatched builds upload an ad-hoc-signed
`-signing-input.zip`. This is an input to the release process, not a
distributable release artifact. Publish only the Developer ID-signed and
notarized DMG produced below.

Create a `notarytool` profile once. Add `--keychain PATH` if the profile
should be stored in a keychain other than the login keychain:

```bash
export AEGISUB_NOTARY_PROFILE=aegisub-release
xcrun notarytool store-credentials "${AEGISUB_NOTARY_PROFILE}"
```

Check out the exact commit which produced the CI artifact. Downloads from the
GitHub web UI are wrapper ZIPs containing the uploaded `-signing-input.zip`.
Extract that wrapper first:

```bash
mkdir -p signing-artifact
ditto -x -k /path/to/github-artifact-download.zip signing-artifact
```

Alternatively, GitHub CLI performs that outer extraction while downloading:

```bash
gh run download RUN_ID \
--name 'macOS arm64 Release - local signing input' \
--dir signing-artifact
```

Then extract the signing input into the staging directory. The resulting path
must be `build/Aegisub.app`:

```bash
mkdir -p build
ditto -x -k signing-artifact/Aegisub-*-signing-input.zip build
```

This release-manager step does not rebuild or resolve Aegisub's dependencies.
It requires the matching source checkout, Xcode command-line tools, the
Developer ID certificate, the stored notary profile, and the extracted app;
Meson, CMake, Ninja, Homebrew, and network access to the wrap sources are not
required. Export the release identity and notary profile, then run the three
scripts in order from the repository root:

```bash
export AEGISUB_BUNDLE_SIGNATURE='Developer ID Application: Example (TEAMID)'
export AEGISUB_NOTARY_PROFILE=aegisub-release

# Optional when using non-default keychains:
export AEGISUB_SIGNING_KEYCHAIN=/path/to/signing.keychain-db
export AEGISUB_NOTARY_KEYCHAIN=/path/to/notary.keychain-db

tools/osx-sign.sh "$PWD" "$PWD/build/Aegisub.app"
tools/osx-dmg.sh "$PWD" "$PWD/build"
tools/osx-notarize.sh "$PWD" "$PWD/build"
```

The final notarization submission requires internet access to Apple's notary
service.

The complete script interfaces are:

```text
tools/osx-sign.sh SOURCE_DIR AEGISUB_APP
tools/osx-dmg.sh SOURCE_DIR BUILD_DIR [VERSION_OVERRIDE]
tools/osx-notarize.sh SOURCE_DIR BUILD_DIR [VERSION_OVERRIDE]
```

An existing, fully configured Meson build offers equivalent `osx-sign`,
`osx-build-dmg`, and `osx-notarize` targets, but setting up a fresh build only
to obtain these wrappers unnecessarily resolves the full dependency tree.

`AEGISUB_BUNDLE_SIGNATURE` is mandatory. Set it to `-` only for an explicitly
ad-hoc CI or development build; such an image cannot be notarized.
`AEGISUB_BUNDLE_ENTITLEMENTS` optionally replaces the default entitlements
file, and `AEGISUB_NOTARY_TIMEOUT` optionally replaces the default `30m`
submission timeout.

Hardened-runtime library validation deliberately remains enabled. Bundled and
third-party native Automation modules must therefore be Apple-signed or signed
with the same Team ID as Aegisub. Rebuild and sign controlled modules rather
than disabling library validation for the whole application.

The DMG is the outermost distributed container, so it is the item submitted to
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.

## Running Doxygen

You can run Doxygen with the following command:
Expand All @@ -38,4 +129,3 @@ Open the newly created `bin/moonscript.lua`, and within it make the following ch
3. Within the function at `package.preload['moonscript']`, remove the line `_with_0.insert_loader()`.

The file is now ready for use, to be placed in `automation/include` within the Aegisub repo.

Loading
Loading