Skip to content

Commit a052e4f

Browse files
committed
Modernize template app
* CMake * Apple-framework * Apple sign & notarize
1 parent edf3d52 commit a052e4f

35 files changed

+2463
-812
lines changed

.appveyor.yml

Lines changed: 0 additions & 29 deletions
This file was deleted.

.github/workflows/build.yml

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# =============================================================================
2+
# LSL Application Build Workflow
3+
# =============================================================================
4+
# This workflow builds, tests, and packages the LSL application for all
5+
# supported platforms. It serves as a reference for other LSL applications.
6+
#
7+
# Features:
8+
# - Multi-platform builds (Linux, macOS, Windows)
9+
# - Qt6 integration
10+
# - Automatic liblsl fetch via FetchContent
11+
# - CPack packaging
12+
# - macOS code signing and notarization (on release)
13+
# =============================================================================
14+
15+
name: Build
16+
17+
on:
18+
push:
19+
branches: [main, master, dev]
20+
tags: ['v*']
21+
pull_request:
22+
branches: [main, master]
23+
release:
24+
types: [published]
25+
workflow_dispatch:
26+
27+
env:
28+
BUILD_TYPE: Release
29+
30+
jobs:
31+
# ===========================================================================
32+
# Build Job - Multi-platform builds
33+
# ===========================================================================
34+
build:
35+
name: ${{ matrix.config.name }}
36+
runs-on: ${{ matrix.config.os }}
37+
strategy:
38+
fail-fast: false
39+
matrix:
40+
config:
41+
- { name: "Ubuntu 22.04", os: ubuntu-22.04 }
42+
# - { name: "Ubuntu 24.04", os: ubuntu-24.04 }
43+
- { name: "macOS", os: macos-14, cmake_extra: '-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"' }
44+
# - { name: "Windows", os: windows-latest }
45+
46+
steps:
47+
- name: Checkout
48+
uses: actions/checkout@v4
49+
50+
# -----------------------------------------------------------------------
51+
# Install CMake 3.28+ (Ubuntu 22.04 ships with 3.22)
52+
# -----------------------------------------------------------------------
53+
- name: Install CMake
54+
if: runner.os == 'Linux'
55+
uses: lukka/get-cmake@latest
56+
57+
# -----------------------------------------------------------------------
58+
# Install Qt6 (6.8 LTS across all platforms)
59+
# -----------------------------------------------------------------------
60+
- name: Install Linux dependencies
61+
if: runner.os == 'Linux'
62+
run: |
63+
sudo apt-get update
64+
sudo apt-get install -y libgl1-mesa-dev libxkbcommon-dev libxcb-cursor0
65+
66+
- name: Install Qt
67+
uses: jurplel/install-qt-action@v4
68+
with:
69+
version: '6.8.*'
70+
cache: true
71+
72+
# -----------------------------------------------------------------------
73+
# Configure
74+
# -----------------------------------------------------------------------
75+
- name: Configure CMake
76+
run: >
77+
cmake -S . -B build
78+
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}
79+
-DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install
80+
-DLSL_FETCH_IF_MISSING=ON
81+
${{ matrix.config.cmake_extra }}
82+
83+
# -----------------------------------------------------------------------
84+
# Build
85+
# -----------------------------------------------------------------------
86+
- name: Build
87+
run: cmake --build build --config ${{ env.BUILD_TYPE }} --parallel
88+
89+
# -----------------------------------------------------------------------
90+
# Install
91+
# -----------------------------------------------------------------------
92+
- name: Install
93+
run: cmake --install build --config ${{ env.BUILD_TYPE }}
94+
95+
# -----------------------------------------------------------------------
96+
# Test CLI
97+
# -----------------------------------------------------------------------
98+
- name: Test CLI (Linux)
99+
if: runner.os == 'Linux'
100+
run: ./install/bin/LSLTemplateCLI --help
101+
102+
- name: Test CLI (macOS)
103+
if: runner.os == 'macOS'
104+
run: ./install/LSLTemplateCLI --help
105+
106+
- name: Test CLI (Windows)
107+
if: runner.os == 'Windows'
108+
run: ./install/LSLTemplateCLI.exe --help
109+
110+
# -----------------------------------------------------------------------
111+
# Package
112+
# -----------------------------------------------------------------------
113+
- name: Package
114+
run: cpack -C ${{ env.BUILD_TYPE }}
115+
working-directory: build
116+
117+
# -----------------------------------------------------------------------
118+
# Upload Artifacts
119+
# -----------------------------------------------------------------------
120+
- name: Upload Artifacts
121+
uses: actions/upload-artifact@v4
122+
with:
123+
name: package-${{ matrix.config.os }}
124+
path: |
125+
build/*.zip
126+
build/*.tar.gz
127+
build/*.deb
128+
if-no-files-found: ignore
129+
130+
# ===========================================================================
131+
# macOS Signing and Notarization (Release only)
132+
# ===========================================================================
133+
sign-macos:
134+
name: Sign & Notarize (macOS)
135+
needs: build
136+
# if: github.event_name == 'release'
137+
runs-on: macos-14
138+
139+
steps:
140+
- name: Checkout
141+
uses: actions/checkout@v4
142+
143+
- name: Download macOS Artifact
144+
uses: actions/download-artifact@v4
145+
with:
146+
name: package-macos-14
147+
path: packages
148+
149+
- name: Extract Package
150+
run: |
151+
cd packages
152+
tar -xzf *.tar.gz
153+
# Move contents out of versioned subdirectory to packages/
154+
SUBDIR=$(ls -d LSLTemplate-*/ | head -1)
155+
mv "$SUBDIR"/* .
156+
rmdir "$SUBDIR"
157+
ls -la
158+
159+
# -----------------------------------------------------------------------
160+
# Install Apple Certificates
161+
# -----------------------------------------------------------------------
162+
- name: Install Apple Certificates
163+
env:
164+
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
165+
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
166+
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
167+
run: |
168+
# Create temporary keychain
169+
KEYCHAIN_PATH=$RUNNER_TEMP/build.keychain
170+
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
171+
security default-keychain -s $KEYCHAIN_PATH
172+
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
173+
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
174+
175+
# Import certificate
176+
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
177+
echo -n "$MACOS_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH
178+
security import $CERTIFICATE_PATH -P "$MACOS_CERTIFICATE_PWD" -k $KEYCHAIN_PATH -A -t cert -f pkcs12
179+
rm $CERTIFICATE_PATH
180+
181+
# Allow codesign to access keychain
182+
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
183+
security list-keychain -d user -s $KEYCHAIN_PATH
184+
185+
# Extract identity name and export to environment
186+
IDENTITY=$(security find-identity -v -p codesigning $KEYCHAIN_PATH | grep "Developer ID Application" | head -1 | awk -F'"' '{print $2}')
187+
echo "APPLE_CODE_SIGN_IDENTITY_APP=$IDENTITY" >> $GITHUB_ENV
188+
189+
# -----------------------------------------------------------------------
190+
# Setup Notarization Credentials
191+
# -----------------------------------------------------------------------
192+
- name: Setup Notarization
193+
env:
194+
NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
195+
NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
196+
NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
197+
run: |
198+
xcrun notarytool store-credentials "notarize-profile" \
199+
--apple-id "$NOTARIZATION_APPLE_ID" \
200+
--password "$NOTARIZATION_PWD" \
201+
--team-id "$NOTARIZATION_TEAM_ID"
202+
echo "APPLE_NOTARIZE_KEYCHAIN_PROFILE=notarize-profile" >> $GITHUB_ENV
203+
204+
# -----------------------------------------------------------------------
205+
# Sign and Notarize
206+
# -----------------------------------------------------------------------
207+
- name: Sign and Notarize
208+
env:
209+
ENTITLEMENTS_FILE: ${{ github.workspace }}/app.entitlements
210+
run: |
211+
# Sign GUI app bundle (--deep handles all nested code including lsl.framework)
212+
APP_PATH=$(find packages -name "*.app" -type d | head -1)
213+
if [[ -n "$APP_PATH" ]]; then
214+
./scripts/sign_and_notarize.sh "$APP_PATH" --notarize
215+
fi
216+
217+
# Sign CLI and its bundled lsl.framework
218+
CLI_PATH=$(find packages -name "LSLTemplateCLI" -type f | head -1)
219+
if [[ -n "$CLI_PATH" ]]; then
220+
CLI_DIR=$(dirname "$CLI_PATH")
221+
# Sign framework first (dependency must be signed before dependent)
222+
if [[ -d "$CLI_DIR/Frameworks/lsl.framework" ]]; then
223+
codesign --force --sign "$APPLE_CODE_SIGN_IDENTITY_APP" --options runtime \
224+
"$CLI_DIR/Frameworks/lsl.framework"
225+
fi
226+
./scripts/sign_and_notarize.sh "$CLI_PATH" --notarize
227+
fi
228+
229+
# -----------------------------------------------------------------------
230+
# Repackage
231+
# -----------------------------------------------------------------------
232+
- name: Repackage
233+
run: |
234+
cd packages
235+
236+
# Debug: show what we have
237+
echo "Contents of packages directory:"
238+
ls -la
239+
240+
# Remove original unsigned package
241+
rm -f *.tar.gz
242+
243+
# Get project version from CMakeLists.txt
244+
VERSION=$(grep -A1 'project(LSLTemplate' ../CMakeLists.txt | grep VERSION | sed 's/.*VERSION \([0-9.]*\).*/\1/')
245+
echo "Detected version: $VERSION"
246+
247+
# Create signed package with CLI and its Frameworks (universal binary)
248+
tar -cvzf "LSLTemplate-${VERSION}-macOS_universal-signed.tar.gz" \
249+
LSLTemplate.app LSLTemplateCLI Frameworks
250+
251+
echo "Created package:"
252+
ls -la *.tar.gz
253+
254+
- name: Upload Signed Package
255+
uses: actions/upload-artifact@v4
256+
with:
257+
name: package-macos-signed
258+
path: packages/*-signed.tar.gz
259+
260+
- name: Upload to Release
261+
if: github.event_name == 'release'
262+
uses: softprops/action-gh-release@v2
263+
with:
264+
files: packages/*-signed.tar.gz
265+
266+
# ===========================================================================
267+
# Upload unsigned packages to release
268+
# ===========================================================================
269+
release:
270+
name: Upload to Release
271+
needs: build
272+
if: github.event_name == 'release'
273+
runs-on: ubuntu-latest
274+
275+
steps:
276+
- name: Download All Artifacts
277+
uses: actions/download-artifact@v4
278+
with:
279+
path: artifacts
280+
281+
- name: Upload to Release
282+
uses: softprops/action-gh-release@v2
283+
with:
284+
files: |
285+
artifacts/**/*.zip
286+
artifacts/**/*.tar.gz
287+
artifacts/**/*.deb

0 commit comments

Comments
 (0)