Skip to content

Commit cdfc0d1

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

35 files changed

Lines changed: 2461 additions & 812 deletions

.appveyor.yml

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

.github/workflows/build.yml

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

0 commit comments

Comments
 (0)