This is the reference template for building Lab Streaming Layer (LSL) applications in C++ with Qt6. Use this as a starting point for creating new LSL-compatible applications.
- Modern CMake (3.28+) with clean, documented structure
- 4-tier liblsl discovery: source, install_root, system, FetchContent
- CLI and GUI separation with shared core library
- Qt6 for the GUI (with Qt5 intentionally dropped for simplicity)
- Cross-platform: Linux, macOS, Windows
- macOS code signing with entitlements for network capabilities
- Automated CI/CD via GitHub Actions
LSLTemplate/
├── CMakeLists.txt # Root build configuration
├── app.entitlements # macOS network capabilities
├── LSLTemplate.cfg # Default configuration file
├── src/
│ ├── core/ # Qt-independent core library
│ │ ├── include/lsltemplate/
│ │ │ ├── Device.hpp # Device interface
│ │ │ ├── LSLOutlet.hpp # LSL outlet wrapper
│ │ │ ├── Config.hpp # Configuration management
│ │ │ └── StreamThread.hpp # Background streaming
│ │ └── src/
│ ├── cli/ # Command-line application
│ │ └── main.cpp
│ └── gui/ # Qt6 GUI application
│ ├── MainWindow.hpp/cpp
│ ├── MainWindow.ui
│ └── main.cpp
├── scripts/
│ └── sign_and_notarize.sh # macOS signing script
└── .github/workflows/
└── build.yml # CI/CD workflow
- CMake 3.28 or later
- C++20 compatible compiler
- Qt6.8 (for GUI build)
- liblsl (optional - will be fetched automatically if not found)
Ubuntu's default repositories don't include Qt 6.8. Use aqtinstall to install it:
# Install aqtinstall
pip install aqtinstall
# Install Qt 6.8 (adjust version as needed)
aqt install-qt linux desktop 6.8.3 gcc_64 -O ~/Qt
# Set environment for CMake to find Qt
export CMAKE_PREFIX_PATH=~/Qt/6.8.3/gcc_64
# Install system dependencies
sudo apt-get install libgl1-mesa-dev libxkbcommon-dev libxcb-cursor0To run the GUI application, ensure Qt libraries are in your library path:
export LD_LIBRARY_PATH=~/Qt/6.8.3/gcc_64/lib:$LD_LIBRARY_PATHAlternatively, build CLI-only with -DLSLTEMPLATE_BUILD_GUI=OFF to avoid the Qt dependency.
# Clone and build
git clone https://github.com/labstreaminglayer/AppTemplate_cpp_qt.git
cd AppTemplate_cpp_qt
# Configure (liblsl will be fetched automatically)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
# Build
cmake --build build --parallel
# Install
cmake --install build --prefix build/install
# Package
cd build && cpack| Option | Default | Description |
|---|---|---|
LSLTEMPLATE_BUILD_GUI |
ON | Build the GUI application |
LSLTEMPLATE_BUILD_CLI |
ON | Build the CLI application |
LSL_FETCH_IF_MISSING |
ON | Auto-fetch liblsl from GitHub |
LSL_FETCH_REF |
(see CMakeLists.txt) | liblsl git ref to fetch (tag, branch, or commit) |
LSL_SOURCE_DIR |
- | Path to liblsl source (for development) |
LSL_INSTALL_ROOT |
- | Path to installed liblsl |
The build system searches for liblsl in this order:
- LSL_SOURCE_DIR - Build from local source (for parallel liblsl development)
- LSL_INSTALL_ROOT - Explicit installation path
- System - Standard CMake search paths
- FetchContent - Automatic download from GitHub
For headless systems or servers:
cmake -S . -B build -DLSLTEMPLATE_BUILD_GUI=OFF
cmake --build buildFor parallel development with liblsl:
cmake -S . -B build -DLSL_SOURCE_DIR=/path/to/liblsl./LSLTemplate # Use default config
./LSLTemplate myconfig.cfg # Use custom config./LSLTemplateCLI --help
./LSLTemplateCLI --name MyStream --rate 256 --channels 8
./LSLTemplateCLI --config myconfig.cfg- Fork/copy this template
- Rename the project in
CMakeLists.txt - Implement your device class by deriving from
IDeviceinsrc/core/include/lsltemplate/Device.hpp - Update the GUI for device-specific settings in
src/gui/MainWindow.ui - Update configuration fields in
src/core/include/lsltemplate/Config.hpp
For local development, the build automatically applies ad-hoc signing with network entitlements. This allows the app to use LSL's multicast discovery.
For distribution, use the signing script:
# Sign only
./scripts/sign_and_notarize.sh build/install/LSLTemplate.app
# Sign and notarize
export APPLE_CODE_SIGN_IDENTITY_APP="Developer ID Application: Your Name"
export APPLE_NOTARIZE_KEYCHAIN_PROFILE="your-profile"
./scripts/sign_and_notarize.sh build/install/LSLTemplate.app --notarizeFor automated signing and notarization, the workflow expects these secrets from the labstreaminglayer organization:
| Secret | Description |
|---|---|
PROD_MACOS_CERTIFICATE |
Base64-encoded Developer ID Application certificate (.p12) |
PROD_MACOS_CERTIFICATE_PWD |
Certificate password |
PROD_MACOS_CI_KEYCHAIN_PWD |
Password for temporary CI keychain |
PROD_MACOS_NOTARIZATION_APPLE_ID |
Apple ID email for notarization |
PROD_MACOS_NOTARIZATION_PWD |
App-specific password for Apple ID |
PROD_MACOS_NOTARIZATION_TEAM_ID |
Apple Developer Team ID |
Important: These organization secrets must be shared with your repository. In GitHub:
- Go to Organization Settings → Secrets and variables → Actions
- For each secret, click to edit and under "Repository access" select the repositories that need access
MIT License - see LICENSE