Skip to content

Commit

Permalink
build: Optimize macOS build & add build script for universal binary
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeWang000000 committed Feb 5, 2025
1 parent d7b01b3 commit 7491ea2
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 111 deletions.
43 changes: 36 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,44 +59,73 @@ jobs:

Build-macOS-Intel:
name: Build Spek-X (macOS, Intel)
runs-on: macos-13
runs-on: macos-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install dependencies
run: |
eval "$(brew shellenv)"
brew unlink perl
cd '${{ github.workspace }}' && ./dist/osx/install_deps.sh
cd '${{ github.workspace }}' && ARCH=x86_64 ./dist/osx/install_deps.sh
- name: Compile and bundle application
run: |
eval "$(brew shellenv)"
cd '${{ github.workspace }}' && ./dist/osx/bundle.sh
cd '${{ github.workspace }}' && ARCH=x86_64 ./dist/osx/bundle.sh
- name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
name: Spek-X (macOS, Intel)
path: ${{ github.workspace }}/dist/osx/Spek.tgz
path: ${{ github.workspace }}/dist/osx/Spek.x86_64.tgz

Build-macOS-AppleSilicon:
name: Build Spek-X (macOS, Apple Silicon)
runs-on: macos-13
runs-on: macos-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install dependencies
run: |
eval "$(brew shellenv)"
brew unlink perl
cd '${{ github.workspace }}' && ./dist/osx/cross/install_deps.sh i_am_ci
cd '${{ github.workspace }}' && ARCH=arm64 ./dist/osx/install_deps.sh
- name: Compile and bundle application
run: |
eval "$(brew shellenv)"
cd '${{ github.workspace }}' && ./dist/osx/cross/bundle.sh i_am_ci
cd '${{ github.workspace }}' && ARCH=arm64 ./dist/osx/bundle.sh
- name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
name: Spek-X (macOS, Apple Silicon)
path: ${{ github.workspace }}/dist/osx/Spek.arm64.tgz

Build-macOS-Universal:
name: Build Spek-X (macOS, Universal)
runs-on: macos-latest
needs:
- Build-macOS-Intel
- Build-macOS-AppleSilicon
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Download Spek-X (macOS, Intel)
uses: actions/download-artifact@v4
with:
name: Spek-X (macOS, Intel)
path: ${{ github.workspace }}/dist/osx/
- name: Download Spek-X (macOS, Apple Silicon)
uses: actions/download-artifact@v4
with:
name: Spek-X (macOS, Apple Silicon)
path: ${{ github.workspace }}/dist/osx/
- name: Bundle application
run: |
eval "$(brew shellenv)"
cd '${{ github.workspace }}' && ./dist/osx/bundle_universal.sh merge_only
- name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
name: Spek-X (macOS, Universal)
path: ${{ github.workspace }}/dist/osx/Spek.tgz

Unit-Test:
Expand Down
21 changes: 18 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,24 @@ AM_COND_IF([USE_VALGRIND], [use_valgrind=yes], [use_valgrind=no])

AC_CHECK_LIB(m, log10)

PKG_CHECK_MODULES(AVFORMAT, [libavformat >= 59.27.100])
PKG_CHECK_MODULES(AVCODEC, [libavcodec >= 59.37.100])
PKG_CHECK_MODULES(AVUTIL, [libavutil >= 57.28.100])
PKG_CHECK_MODULES(AVFORMAT, [libavformat >= 59.27.100], [
AC_SUBST([AVFORMAT_CFLAGS])
AC_SUBST([AVFORMAT_LIBS])
])
PKG_CHECK_MODULES(AVCODEC, [libavcodec >= 59.37.100], [
AC_SUBST([AVCODEC_CFLAGS])
AC_SUBST([AVCODEC_LIBS])
])
PKG_CHECK_MODULES(AVUTIL, [libavutil >= 57.28.100], [
AC_SUBST([AVUTIL_CFLAGS])
AC_SUBST([AVUTIL_LIBS])
])

CXXFLAGS="$CXXFLAGS $AVFORMAT_CFLAGS $AVCODEC_CFLAGS $AVUTIL_CFLAGS"
LDFLAGS="$LDFLAGS $AVFORMAT_LIBS $AVCODEC_LIBS $AVUTIL_LIBS"
if test "$os" = OSX; then
LDFLAGS="$LDFLAGS -framework Cocoa"
fi

AM_OPTIONS_WXCONFIG
reqwx=3.0.0
Expand Down
8 changes: 4 additions & 4 deletions dist/osx/Info.plist.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<key>CFBundleExecutable</key>
<string>Spek</string>
<key>CFBundleGetInfoString</key>
<string>Spek @VERSION@</string>
<string>Spek-X @VERSION@</string>
<key>CFBundleIconFile</key>
<string>Spek.icns</string>
<key>CFBundleIdentifier</key>
<string>org.spek-project</string>
<string>org.spek-x-project</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
Expand All @@ -25,9 +25,9 @@
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) 2010-2013 Alexander Kojevnikov and contributors</string>
<string>Copyright (c) 2010-2025 Alexander Kojevnikov and contributors</string>
<key>LSMinimumSystemVersion</key>
<string>10.5</string>
<string>10.10</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
Expand Down
97 changes: 51 additions & 46 deletions dist/osx/bundle.sh
Original file line number Diff line number Diff line change
@@ -1,68 +1,73 @@
#!/bin/sh
#!/bin/bash
set -xeu

LANGUAGES="bs ca cs da de el eo es fi fr gl he hu id it ja ko lv nb nl pl pt_BR ru sk sr@latin sv th tr uk vi zh_CN zh_TW"
LOCALEDIR="/usr/local/share/locale/"
[ ! -d "$LOCALEDIR" ] && [ -d "$HOMEBREW_PREFIX/share/locale/" ] && LOCALEDIR="$HOMEBREW_PREFIX/share/locale/"
PROJDIR=$(realpath "$(dirname $0)/../..")

cd $(dirname $0)/../..
[ -z "${ARCH-}" ] && ARCH=$(uname -m)
if [ "$ARCH" = "x86_64" ]; then
echo "Target architecture: $ARCH"
MACOSX_DEPLOYMENT_TARGET=10.10
elif [ "$ARCH" = "arm64" ]; then
echo "Target architecture: $ARCH"
MACOSX_DEPLOYMENT_TARGET=12.0
else
echo "Unsupported architecture: $ARCH" >&2
exit 1
fi

rm -f src/spek
DEPSDIR="$(realpath "$(dirname $0)")/deps.$ARCH"
if [ ! -e "$DEPSDIR" ]; then
echo "Dependency not found. Running ./install_deps.sh ..."
env ARCH="$ARCH" ./install_deps.sh
fi

export MACOSX_DEPLOYMENT_TARGET
export PATH="$DEPSDIR/bin:$PATH"
export ACLOCAL="aclocal -I $DEPSDIR/share/aclocal"
export PKG_CONFIG_PATH="$DEPSDIR/lib/pkgconfig"
export CXX="/usr/bin/clang++ -arch $ARCH"

cd "$PROJDIR"

cp "$HOMEBREW_PREFIX"/share/wx/*/aclocal/wxwin.m4 .
echo "m4_include([wxwin.m4])" > acinclude.m4
rm -f src/spek

./autogen.sh && make -j2 || exit 1
mkdir -p builddir
cd builddir
BUILDDIR=$(pwd)
../autogen.sh --host="$ARCH-apple-darwin" && make clean && make -j$(nproc) || exit 1

cd dist/osx
rm -fr Spek.app
cd "$PROJDIR/dist/osx"
rm -fr Spek.app "Spek-$ARCH.app"
mkdir -p Spek.app/Contents/MacOS
mkdir -p Spek.app/Contents/Frameworks
mkdir -p Spek.app/Contents/Resources
mv ../../src/spek Spek.app/Contents/MacOS/Spek
cp Info.plist Spek.app/Contents/
cp Spek.icns Spek.app/Contents/Resources/
cp *.png Spek.app/Contents/Resources/
cp ../../LICENCE.md Spek.app/Contents/Resources/
cp ../../README.md Spek.app/Contents/Resources/
mv "$BUILDDIR"/src/spek Spek.app/Contents/MacOS/Spek
cp "$BUILDDIR"/dist/osx/Info.plist Spek.app/Contents/
cp "$PROJDIR"/dist/osx/Spek.icns Spek.app/Contents/Resources/
cp "$PROJDIR"/dist/osx/*.png Spek.app/Contents/Resources/
cp "$PROJDIR"/LICENCE.md Spek.app/Contents/Resources/
cp "$PROJDIR"/README.md Spek.app/Contents/Resources/
mkdir Spek.app/Contents/Resources/lic
cp ../../lic/* Spek.app/Contents/Resources/lic/
cp "$PROJDIR"/lic/* Spek.app/Contents/Resources/lic/

for lang in $LANGUAGES; do
mkdir -p Spek.app/Contents/Resources/"$lang".lproj
cp -v ../../po/"$lang".gmo Spek.app/Contents/Resources/"$lang".lproj/spek.mo
cp -v "$LOCALEDIR""$lang"/LC_MESSAGES/wxstd*.mo Spek.app/Contents/Resources/"$lang".lproj/wxstd.mo
cp "$BUILDDIR"/po/"$lang".gmo Spek.app/Contents/Resources/"$lang".lproj/spek.mo
mo=("$DEPSDIR"/share/locale/"$lang"/LC_MESSAGES/wxstd*.mo)
test -f "$mo" && cp "$mo" Spek.app/Contents/Resources/"$lang".lproj/wxstd.mo
done
unset lang mo
mkdir -p Spek.app/Contents/Resources/en.lproj

BINS="Spek.app/Contents/MacOS/Spek"
while [ ! -z "$BINS" ]; do
NEWBINS=""
for bin in $BINS; do
echo "Updating dependendies for $bin."
LIBS=$(otool -L $bin | grep -e /usr/local/ -e /opt/ | tr -d '\t' | awk '{print $1}')
for lib in $LIBS; do
reallib=$(realpath $lib)
libname=$(basename $reallib)
install_name_tool -change $lib @executable_path/../Frameworks/$libname $bin
if [ ! -f Spek.app/Contents/Frameworks/$libname ]; then
echo "\tBundling $reallib."
cp $reallib Spek.app/Contents/Frameworks/
chmod +w Spek.app/Contents/Frameworks/$libname
install_name_tool -id @executable_path/../Frameworks/$libname Spek.app/Contents/Frameworks/$libname
NEWBINS="$NEWBINS Spek.app/Contents/Frameworks/$libname"
fi
done
done
BINS="$NEWBINS"
done
bin="Spek.app/Contents/MacOS/Spek"
echo "Updating dependendies for $bin."
cp -a "$DEPSDIR"/lib/*.dylib Spek.app/Contents/Frameworks/
install_name_tool -add_rpath "@executable_path/../Frameworks" "$bin"

# Sign the app
codesign -fs - ./Spek.app --deep

# Create a gzip tar archive
rm -f Spek.tgz
tar cvzf Spek.tgz ./Spek.app

# Clean up
cd ../..
rm wxwin.m4 acinclude.m4
rm -f "Spek.$ARCH.tgz"
tar cvzf "Spek.$ARCH.tgz" Spek.app
51 changes: 51 additions & 0 deletions dist/osx/bundle_universal.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash
set -xeu

cd "$(dirname $0)"

if [ "${1-}" != "merge_only" ]; then
ARCH=x86_64 ./bundle.sh
ARCH=arm64 ./bundle.sh
fi

SPEK_X86_64="$(realpath .)/Spek.x86_64.app"
SPEK_ARM64="$(realpath .)/Spek.arm64.app"
SPEK_UNIVERSAL="$(realpath .)/Spek.app"

rm -rf "Spek.app"
tar xf Spek.x86_64.tgz
mv "Spek.app" "$SPEK_X86_64"
tar xf Spek.arm64.tgz
mv "Spek.app" "$SPEK_ARM64"

cp -a "$SPEK_X86_64" "$SPEK_UNIVERSAL"

# Merge x86_64, arm64 excutables
cd "$SPEK_UNIVERSAL/Contents/MacOS"
for bin in *; do
test -L "$bin" && continue
rm $bin
lipo -create \
"$SPEK_X86_64/Contents/MacOS/$bin" \
"$SPEK_ARM64/Contents/MacOS/$bin" \
-o "$SPEK_UNIVERSAL/Contents/MacOS/$bin"
done

# Merge x86_64, arm64 libraries
cd "$SPEK_UNIVERSAL/Contents/Frameworks"
for bin in *; do
test -L "$bin" && continue
rm $bin
lipo -create \
"$SPEK_X86_64/Contents/Frameworks/$bin" \
"$SPEK_ARM64/Contents/Frameworks/$bin" \
-o "$SPEK_UNIVERSAL/Contents/Frameworks/$bin"
done

# Sign the app
codesign -fs - "$SPEK_UNIVERSAL" --deep

# Create a gzip tar archive
cd "$SPEK_UNIVERSAL/.."
rm -f Spek.tgz
tar cvzf Spek.tgz Spek.app
Loading

0 comments on commit 7491ea2

Please sign in to comment.