Merge pull request #571 from gnattu/apple-silicon-build

feat: add Apple silicon build
This commit is contained in:
Izzie Walton 2024-05-13 17:58:52 -04:00 committed by GitHub
commit 9b9bb09318
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 90 additions and 16 deletions

View File

@ -8,28 +8,25 @@ on:
- test
jobs:
build-mac:
runs-on: macos-11
runs-on: macos-12
steps:
- uses: actions/checkout@v4
- name: Install Qt 5.15.2
uses: jurplel/install-qt-action@v4
with:
version: "5.15.2"
modules: "qtwebengine"
setup-python: 'false'
- name: Install dependencies
run: |
brew update
brew install ninja mpv || true
brew install ninja mpv qt@5 || true
- name: Release build
run: |
./download_webclient.sh
sed -i '' 's/<body>/<body style="overscroll-behavior: none;">/' ./build/dist/index.html
cd build
cmake -GNinja -DQTROOT=$Qt5_DIR -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=output ..
cmake -GNinja -DQTROOT=/usr/local/opt/qt@5 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=output ..
ninja install
- name: Fix library paths and create dmg
run: |
python3 ./scripts/fix-install-names.py ./build/output/Jellyfin\ Media\ Player.app
python3 ./scripts/fix-webengine.py ./build/output/Jellyfin\ Media\ Player.app
codesign --force --deep -s - ./build/output/Jellyfin\ Media\ Player.app/
brew install create-dmg
create-dmg --volname "Jellyfin Media Player" --no-internet-enable "JellyfinMediaPlayer.dmg" "./build/output/Jellyfin Media Player.app"
- name: Archive production artifacts
@ -38,12 +35,40 @@ jobs:
name: macos
path: ${{ github.workspace }}/JellyfinMediaPlayer.dmg
build-macarm64:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
brew update
brew install ninja mpv qt@5 || true
- name: Release build
run: |
./download_webclient.sh
sed -i '' 's/<body>/<body style="overscroll-behavior: none;">/' ./build/dist/index.html
cd build
cmake -GNinja -DQTROOT=/opt/homebrew/opt/qt@5 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=output ..
ninja install
- name: Fix library paths and create dmg
run: |
python3 ./scripts/fix-install-names.py ./build/output/Jellyfin\ Media\ Player.app
python3 ./scripts/fix-webengine.py ./build/output/Jellyfin\ Media\ Player.app
codesign --force --deep -s - ./build/output/Jellyfin\ Media\ Player.app/
brew install create-dmg
create-dmg --volname "Jellyfin Media Player" --no-internet-enable "JellyfinMediaPlayer.dmg" "./build/output/Jellyfin Media Player.app"
- name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
name: macos-arm64
path: ${{ github.workspace }}/JellyfinMediaPlayer.dmg
build-win64:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Install Qt 5.15.2
uses: jurplel/install-qt-action@v4
uses: jurplel/install-qt-action@v3
with:
version: "5.15.2"
arch: "win64_msvc2019_64"
@ -89,7 +114,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install Qt 5.15.2
uses: jurplel/install-qt-action@v4
uses: jurplel/install-qt-action@v3
with:
version: "5.15.2"
arch: "win32_msvc2019"

View File

@ -4,6 +4,7 @@ import argparse
from collections import deque
import subprocess
import shutil
import platform
def main(argv=tuple(sys.argv[1:])):
@ -13,6 +14,9 @@ def main(argv=tuple(sys.argv[1:])):
bundle_path = Path(arguments.bundle[0])
framework_path = bundle_path / 'Contents' / 'Frameworks'
rpath_str = '/usr/local/lib'
if platform.machine() == 'arm64':
rpath_str = '/opt/homebrew/lib'
framework_libs = set(file.name for file in framework_path.glob('*.dylib')).union(set(file.name for file in framework_path.glob('*.so')))
libs_to_fix = deque()
libs_to_fix.extend(file for file in bundle_path.glob('**/*.dylib'))
@ -23,13 +27,23 @@ def main(argv=tuple(sys.argv[1:])):
result = subprocess.check_output(['otool', '-L', str(lib.resolve())], stderr=subprocess.STDOUT).decode('utf-8')
for dependency in result.splitlines():
dependency = dependency.strip().lstrip()
if dependency.startswith('/usr/local'):
if dependency.startswith('/usr/local') or dependency.startswith('/opt/homebrew') or dependency.startswith('@rpath') or dependency.startswith('@loader_path'):
# cut off trailing compatibility string
dependency = Path(dependency.split(' (compatibility')[0])
dependency_str = dependency.split(' (compatibility')[0].strip()
if dependency.startswith('@rpath'):
dependency = dependency_str.replace("@rpath", rpath_str)
dependency = Path(dependency)
elif dependency.startswith('@loader_path'):
dependency = dependency_str.replace("@loader_path", rpath_str)
dependency = Path(dependency)
dependency_name = dependency.name
dependency = (Path(rpath_str) / dependency_name).resolve()
else:
dependency = Path(dependency_str)
# if somehow macdeployqt didn't copy the lib for us, we do a manual copy
if dependency.name not in framework_libs:
shutil.copy(str(dependency.resolve()), str(framework_path.resolve()))
shutil.copy(str(dependency.resolve()), str((framework_path / dependency.name).resolve()))
framework_libs.add(dependency.name)
# add the newly added library in to the to fix queue
libs_to_fix.append(framework_path / dependency.name)
@ -38,9 +52,9 @@ def main(argv=tuple(sys.argv[1:])):
# now we fix the path using install_name_tool
target = f'@executable_path/../Frameworks/{dependency.name}'
print(f'Fixing dependency {dependency} of {lib} to {target}')
print(f'Fixing dependency {dependency_str} of {lib} to {target}')
subprocess.run(['install_name_tool', '-id', target, lib])
subprocess.run(['install_name_tool', '-change', str(dependency), target, lib])
subprocess.run(['install_name_tool', '-change', dependency_str, target, lib])
if __name__ == '__main__':

35
scripts/fix-webengine.py Normal file
View File

@ -0,0 +1,35 @@
from pathlib import Path
import sys
import os
import argparse
from collections import deque
import subprocess
import shutil
def main(argv=tuple(sys.argv[1:])):
arg_parser = argparse.ArgumentParser(description='Fix third party library paths in .app bundles.')
arg_parser.add_argument('bundle', metavar='BUNDLE', type=str, nargs=1)
arguments = arg_parser.parse_args(argv)
bundle_path = Path(arguments.bundle[0])
print(bundle_path)
webengine_path = bundle_path / 'Contents' / 'Frameworks' / 'QtWebEngineCore.framework' / 'Helpers' / 'QtWebEngineProcess.app'
link_path = webengine_path / 'Contents' / 'Frameworks'
bin_to_fix = webengine_path / 'Contents' / 'MacOS' / 'QtWebEngineProcess'
os.symlink('../../../../../../../Frameworks', link_path)
result = subprocess.check_output(['otool', '-L', str(bin_to_fix.resolve())],stderr=subprocess.STDOUT).decode('utf-8')
for dependency in result.splitlines():
dependency = dependency.strip().lstrip()
if dependency.startswith('/opt/homebrew'):
# cut off trailing compatibility string
dependency_str = dependency.split(' (compatibility')[0].strip()
dependency_framework_str = dependency_str.split('/lib')[1].strip()
dependency_framework = Path(dependency_framework_str)
target = f'@executable_path/../Frameworks{dependency_framework_str}'
subprocess.run(['install_name_tool', '-id', target, bin_to_fix])
subprocess.run(['install_name_tool', '-change', dependency_str, target, bin_to_fix])
if __name__ == '__main__':
main()