From 056e51d442780b96fdcdb3a9b0e657c2b93c67d2 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Sat, 10 Jan 2026 12:34:26 -0500 Subject: [PATCH 1/3] Modernize build including Apple signing and simpler GHA --- .github/workflows/build.yml | 287 ++++++++++++++++++ .github/workflows/cppcmake.yml | 125 -------- CMakeLists.txt | 522 +++++++++++++++++++++------------ app.entitlements | 17 ++ scripts/sign_and_notarize.sh | 119 ++++++++ xdfwriter/CMakeLists.txt | 12 +- 6 files changed, 770 insertions(+), 312 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/cppcmake.yml create mode 100644 app.entitlements create mode 100755 scripts/sign_and_notarize.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..1818244 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,287 @@ +# ============================================================================= +# LabRecorder Build Workflow +# ============================================================================= +# This workflow builds, tests, and packages LabRecorder for all supported +# platforms. +# +# Features: +# - Multi-platform builds (Linux, macOS, Windows) +# - Qt6 integration +# - Automatic liblsl fetch via FetchContent +# - CPack packaging +# - macOS code signing and notarization (on release) +# ============================================================================= + +name: Build + +on: + push: + branches: [main, master, dev] + tags: ['v*'] + pull_request: + branches: [main, master] + release: + types: [published] + workflow_dispatch: + +env: + BUILD_TYPE: Release + +jobs: + # =========================================================================== + # Build Job - Multi-platform builds + # =========================================================================== + build: + name: ${{ matrix.config.name }} + runs-on: ${{ matrix.config.os }} + strategy: + fail-fast: false + matrix: + config: + - { name: "Ubuntu 22.04", os: ubuntu-22.04 } + - { name: "Ubuntu 24.04", os: ubuntu-24.04 } + - { name: "macOS", os: macos-14, cmake_extra: '-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"' } + - { name: "Windows", os: windows-latest } + + steps: + - name: Checkout + uses: actions/checkout@v4 + + # ----------------------------------------------------------------------- + # Install CMake 3.28+ (Ubuntu 22.04 ships with 3.22) + # ----------------------------------------------------------------------- + - name: Install CMake + if: runner.os == 'Linux' + uses: lukka/get-cmake@latest + + # ----------------------------------------------------------------------- + # Install Qt6 (6.8 LTS across all platforms) + # ----------------------------------------------------------------------- + - name: Install Linux dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y libgl1-mesa-dev libxkbcommon-dev libxcb-cursor0 + + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: '6.8.*' + cache: true + + # ----------------------------------------------------------------------- + # Configure + # ----------------------------------------------------------------------- + - name: Configure CMake + run: > + cmake -S . -B build + -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} + -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install + -DLSL_FETCH_IF_MISSING=ON + ${{ matrix.config.cmake_extra }} + + # ----------------------------------------------------------------------- + # Build + # ----------------------------------------------------------------------- + - name: Build + run: cmake --build build --config ${{ env.BUILD_TYPE }} --parallel + + # ----------------------------------------------------------------------- + # Install + # ----------------------------------------------------------------------- + - name: Install + run: cmake --install build --config ${{ env.BUILD_TYPE }} + + # ----------------------------------------------------------------------- + # Test CLI + # ----------------------------------------------------------------------- + - name: Test CLI (Linux) + if: runner.os == 'Linux' + run: ./install/bin/LabRecorderCLI --help || true + + - name: Test CLI (macOS) + if: runner.os == 'macOS' + run: ./install/LabRecorderCLI --help || true + + - name: Test CLI (Windows) + if: runner.os == 'Windows' + run: ./install/LabRecorderCLI.exe --help || true + + # ----------------------------------------------------------------------- + # Package + # ----------------------------------------------------------------------- + - name: Package + run: cpack -C ${{ env.BUILD_TYPE }} + working-directory: build + + # ----------------------------------------------------------------------- + # Upload Artifacts + # ----------------------------------------------------------------------- + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: package-${{ matrix.config.os }} + path: | + build/*.zip + build/*.tar.gz + build/*.deb + if-no-files-found: ignore + + # =========================================================================== + # macOS Signing and Notarization (Release only) + # =========================================================================== + sign-macos: + name: Sign & Notarize (macOS) + needs: build + if: github.event_name == 'release' + runs-on: macos-14 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download macOS Artifact + uses: actions/download-artifact@v4 + with: + name: package-macos-14 + path: packages + + - name: Extract Package + run: | + cd packages + tar -xzf *.tar.gz + # Move contents out of versioned subdirectory to packages/ + SUBDIR=$(ls -d LabRecorder-*/ | head -1) + mv "$SUBDIR"/* . + rmdir "$SUBDIR" + ls -la + + # ----------------------------------------------------------------------- + # Install Apple Certificates + # ----------------------------------------------------------------------- + - name: Install Apple Certificates + env: + MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }} + MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }} + MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }} + run: | + # Create temporary keychain + KEYCHAIN_PATH=$RUNNER_TEMP/build.keychain + security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH + security default-keychain -s $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH + + # Import certificate + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + echo -n "$MACOS_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH + security import $CERTIFICATE_PATH -P "$MACOS_CERTIFICATE_PWD" -k $KEYCHAIN_PATH -A -t cert -f pkcs12 + rm $CERTIFICATE_PATH + + # Allow codesign to access keychain + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + + # Extract identity name and export to environment + IDENTITY=$(security find-identity -v -p codesigning $KEYCHAIN_PATH | grep "Developer ID Application" | head -1 | awk -F'"' '{print $2}') + echo "APPLE_CODE_SIGN_IDENTITY_APP=$IDENTITY" >> $GITHUB_ENV + + # ----------------------------------------------------------------------- + # Setup Notarization Credentials + # ----------------------------------------------------------------------- + - name: Setup Notarization + env: + NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }} + NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }} + NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }} + run: | + xcrun notarytool store-credentials "notarize-profile" \ + --apple-id "$NOTARIZATION_APPLE_ID" \ + --password "$NOTARIZATION_PWD" \ + --team-id "$NOTARIZATION_TEAM_ID" + echo "APPLE_NOTARIZE_KEYCHAIN_PROFILE=notarize-profile" >> $GITHUB_ENV + + # ----------------------------------------------------------------------- + # Sign and Notarize + # ----------------------------------------------------------------------- + - name: Sign and Notarize + env: + ENTITLEMENTS_FILE: ${{ github.workspace }}/app.entitlements + run: | + # Sign GUI app bundle (--deep handles all nested code including lsl.framework) + APP_PATH=$(find packages -name "*.app" -type d | head -1) + if [[ -n "$APP_PATH" ]]; then + ./scripts/sign_and_notarize.sh "$APP_PATH" --notarize + fi + + # Sign CLI and its bundled lsl.framework + CLI_PATH=$(find packages -name "LabRecorderCLI" -type f | head -1) + if [[ -n "$CLI_PATH" ]]; then + CLI_DIR=$(dirname "$CLI_PATH") + # Sign framework first (dependency must be signed before dependent) + if [[ -d "$CLI_DIR/Frameworks/lsl.framework" ]]; then + codesign --force --sign "$APPLE_CODE_SIGN_IDENTITY_APP" --options runtime \ + "$CLI_DIR/Frameworks/lsl.framework" + fi + ./scripts/sign_and_notarize.sh "$CLI_PATH" --notarize + fi + + # ----------------------------------------------------------------------- + # Repackage + # ----------------------------------------------------------------------- + - name: Repackage + run: | + cd packages + + # Debug: show what we have + echo "Contents of packages directory:" + ls -la + + # Remove original unsigned package + rm -f *.tar.gz + + # Get project version from CMakeLists.txt + VERSION=$(grep -A1 'project(LabRecorder' ../CMakeLists.txt | grep VERSION | sed 's/.*VERSION \([0-9.]*\).*/\1/') + echo "Detected version: $VERSION" + + # Create signed package with CLI and its Frameworks (universal binary) + tar -cvzf "LabRecorder-${VERSION}-macOS_universal-signed.tar.gz" \ + LabRecorder.app LabRecorderCLI Frameworks LabRecorder.cfg LICENSE README.md + + echo "Created package:" + ls -la *.tar.gz + + - name: Upload Signed Package + uses: actions/upload-artifact@v4 + with: + name: package-macos-signed + path: packages/*-signed.tar.gz + + - name: Upload to Release + if: github.event_name == 'release' + uses: softprops/action-gh-release@v2 + with: + files: packages/*-signed.tar.gz + + # =========================================================================== + # Upload unsigned packages to release + # =========================================================================== + release: + name: Upload to Release + needs: build + if: github.event_name == 'release' + runs-on: ubuntu-latest + + steps: + - name: Download All Artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Upload to Release + uses: softprops/action-gh-release@v2 + with: + files: | + artifacts/**/*.zip + artifacts/**/*.tar.gz + artifacts/**/*.deb diff --git a/.github/workflows/cppcmake.yml b/.github/workflows/cppcmake.yml deleted file mode 100644 index 4d20ae5..0000000 --- a/.github/workflows/cppcmake.yml +++ /dev/null @@ -1,125 +0,0 @@ -name: C/C++ CI - -on: - workflow_dispatch: - push: - branches: ['*'] - tags: - - v*.* - pull_request: - branches: - - master - release: - types: ['created'] - -env: - LSL_RELEASE_URL: 'https://github.com/sccn/liblsl/releases/download' - LSL_RELEASE: '1.16.2' - -defaults: - run: - shell: bash - -# Check qt_ver on # https://download.qt.io/online/qtsdkrepository/ -jobs: - build: - name: ${{ matrix.config.name }} - runs-on: ${{ matrix.config.os }} - strategy: - fail-fast: false - matrix: - config: - - name: "ubuntu-24.04" - os: "ubuntu-24.04" - - name: "ubuntu-22.04" - os: "ubuntu-22.04" - - name: "windows-x64" - os: "windows-latest" - cmake_extra: "-T v142,host=x86" - arch: "amd64" - qt_arch: "win64_msvc2019_64" - qt_ver: "6.4.0" - - name: "windows-x86" - os: "windows-latest" - cmake_extra: "-T v142,host=x86 -A Win32" - arch: "i386" - qt_arch: "win32_msvc2019" - qt_ver: "5.15.2" - - name: "macOS-latest" - os: "macOS-latest" - steps: - - uses: actions/checkout@v4 - - - name: Install liblsl (Ubuntu) - if: startsWith(matrix.config.os, 'ubuntu-') - run: | - sudo apt install -y libpugixml-dev - curl -L ${LSL_RELEASE_URL}/v${LSL_RELEASE}/liblsl-${LSL_RELEASE}-$(lsb_release -sc)_amd64.deb -o liblsl.deb - sudo apt install ./liblsl.deb - - - name: Download liblsl (Windows) - if: matrix.config.os == 'windows-latest' - run: | - curl -L ${LSL_RELEASE_URL}/v${LSL_RELEASE}/liblsl-${LSL_RELEASE}-Win_${{ matrix.config.arch}}.zip -o liblsl.zip - 7z x liblsl.zip -oLSL - - - name: Download liblsl (macOS) - if: startsWith(matrix.config.os, 'macos-') - run: brew install labstreaminglayer/tap/lsl - - - name: Install Qt (Window) - if: (matrix.config.os == 'windows-latest') - uses: jurplel/install-qt-action@v4 - with: - version: ${{ matrix.config.qt_ver }} - arch: ${{ matrix.config.qt_arch }} - - - name: Install Qt (Ubuntu) - if: startsWith(matrix.config.os, 'ubuntu-') - run: sudo apt install qt6-base-dev freeglut3-dev - - - name: Install Qt (MacOS) - if: startsWith(matrix.config.os, 'macos-') - run: brew install qt - - - name: Configure CMake - run: | - cmake --version - cmake -S . -B build \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=${PWD}/install \ - -DCPACK_PACKAGE_DIRECTORY=${PWD}/package \ - -DLSL_INSTALL_ROOT=$PWD/LSL/ \ - -DCPACK_DEBIAN_PACKAGE_SHLIBDEPS=ON \ - ${{ matrix.config.cmake_extra }} - if [[ "${{ matrix.config.name }}" = ubuntu-* ]]; then - cmake -DLSL_UNIXFOLDERS=ON build - fi - - - name: make - run: cmake --build build --config Release -j --target install - - - name: package - run: | - export LD_LIBRARY_PATH=$Qt5_DIR/lib:$Qt6_DIR/lib:$LD_LIBRARY_PATH - cmake --build build --config Release -j --target package - cmake -E remove_directory package/_CPack_Packages - - - name: Upload Artifacts - uses: actions/upload-artifact@v4 - with: - name: pkg-${{ matrix.config.name }} - path: package - - - name: upload to release page - if: github.event_name == 'release' - env: - TOKEN: "token ${{ secrets.GITHUB_TOKEN }}" - UPLOAD_URL: ${{ github.event.release.upload_url }} - run: | - UPLOAD_URL=${UPLOAD_URL%\{*} # remove "{name,label}" suffix - for pkg in package/*.*; do - NAME=$(basename $pkg) - MIME=$(file --mime-type $pkg|cut -d ' ' -f2) - curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: $TOKEN" -H "Content-Type: $MIME" --data-binary @$pkg $UPLOAD_URL?name=$NAME - done diff --git a/CMakeLists.txt b/CMakeLists.txt index 71933ce..69eef7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,210 +1,370 @@ -cmake_minimum_required(VERSION 3.12) -#set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum MacOS deployment version") +# ============================================================================= +# LabRecorder - CMakeLists.txt +# ============================================================================= +# Record and write LabStreamingLayer streams to an XDF file. +# ============================================================================= + +cmake_minimum_required(VERSION 3.28) + +# CMP0177: install() DESTINATION paths are normalized (CMake 3.31+) +if(POLICY CMP0177) + cmake_policy(SET CMP0177 NEW) +endif() project(LabRecorder - DESCRIPTION "Record and write LabStreamingLayer streams to an XDF file" - HOMEPAGE_URL "https://github.com/labstreaminglayer/App-LabRecorder/" - LANGUAGES C CXX - VERSION 1.16.4) + VERSION 1.16.5 + DESCRIPTION "Record and write LabStreamingLayer streams to an XDF file" + HOMEPAGE_URL "https://github.com/labstreaminglayer/App-LabRecorder/" + LANGUAGES C CXX +) -# Needed for customized MacOSXBundleInfo.plist.in -SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake" ${CMAKE_MODULE_PATH}) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED On) +# ============================================================================= +# Build Options +# ============================================================================= +option(LABRECORDER_BUILD_GUI "Build the GUI application (requires Qt6)" ON) -option(BUILD_GUI "Build the GUI, set to off for CLI only build" ON) +# ============================================================================= +# LSL Discovery Options +# ============================================================================= +# Priority 1: Build from local source (for parallel liblsl development) +set(LSL_SOURCE_DIR "" CACHE PATH "Path to liblsl source directory") -set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") -set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") +# Priority 2: Use explicit installation path +set(LSL_INSTALL_ROOT "" CACHE PATH "Path to installed liblsl") -# Dependencies +# Priority 3: System installation (searched automatically) -## LSL -if(ANDROID) - set(LIBLSL_SOURCE_PATH "../../LSL/liblsl" CACHE STRING "Path to liblsl sources") +# Priority 4: Fetch from GitHub if not found +option(LSL_FETCH_IF_MISSING "Fetch liblsl from GitHub if not found locally" ON) +# TODO: Change back to version tag (e.g., "v1.16.2") once apple_framework branch is merged +set(LSL_FETCH_REF "cboulay/apple_framework" CACHE STRING "liblsl git ref to fetch (tag, branch, or commit)") - # force include liblsl as target to build with the android toolchain - # as path of the normal build process - add_subdirectory(${LIBLSL_SOURCE_PATH} liblsl_bin) - add_library(LSL::lsl ALIAS lsl) +# ============================================================================= +# Find/Fetch liblsl +# ============================================================================= +if(LSL_SOURCE_DIR) + # Priority 1: Build from local source (parallel development) + if(NOT EXISTS "${LSL_SOURCE_DIR}/CMakeLists.txt") + message(FATAL_ERROR "LSL_SOURCE_DIR set to '${LSL_SOURCE_DIR}' but no CMakeLists.txt found there") + endif() + message(STATUS "Using local liblsl source: ${LSL_SOURCE_DIR}") + add_subdirectory("${LSL_SOURCE_DIR}" liblsl_bin EXCLUDE_FROM_ALL) + if(NOT TARGET LSL::lsl) + add_library(LSL::lsl ALIAS lsl) + endif() + set(LSL_FOUND TRUE) + include("${LSL_SOURCE_DIR}/cmake/LSLCMake.cmake") else() - find_package(LSL REQUIRED - HINTS ${LSL_INSTALL_ROOT} - "${CMAKE_CURRENT_LIST_DIR}/../../LSL/liblsl/build/" - "${CMAKE_CURRENT_LIST_DIR}/../../LSL/liblsl/build/install" - "${CMAKE_CURRENT_LIST_DIR}/../../LSL/liblsl/out/build/x64-Release" - "${CMAKE_CURRENT_LIST_DIR}/../../LSL/liblsl/out/install/x64-Release" - PATH_SUFFIXES share/LSL - ) + # Priority 2 & 3: Try to find installed liblsl + set(_lsl_hints) + if(LSL_INSTALL_ROOT) + list(APPEND _lsl_hints "${LSL_INSTALL_ROOT}") + endif() + # Common development layout hints (including CLion cmake-build-* directories) + string(TOLOWER "${CMAKE_BUILD_TYPE}" _build_type_lower) + if(NOT _build_type_lower) + set(_build_type_lower "release") + endif() + if(MSVC) + set(_clion_build_dir "cmake-build-${_build_type_lower}-visual-studio") + else() + set(_clion_build_dir "cmake-build-${_build_type_lower}") + endif() + foreach(_root IN ITEMS "../liblsl" "../../LSL/liblsl") + foreach(_build IN ITEMS "build" "${_clion_build_dir}") + list(APPEND _lsl_hints "${CMAKE_CURRENT_LIST_DIR}/${_root}/${_build}/install") + endforeach() + endforeach() + + set(_lsl_suffixes + share/LSL + lib/cmake/LSL + cmake + Frameworks/lsl.framework/Resources/CMake # macOS framework layout + ) + + # First try: Search only in hints (prefer local builds over system) + find_package(LSL QUIET + HINTS ${_lsl_hints} + PATH_SUFFIXES ${_lsl_suffixes} + NO_DEFAULT_PATH + ) + + # Second try: Search system paths if not found in hints + if(NOT LSL_FOUND) + find_package(LSL QUIET + PATH_SUFFIXES ${_lsl_suffixes} + ) + endif() + + if(LSL_FOUND) + message(STATUS "Found installed liblsl: ${LSL_DIR}") + include("${LSL_DIR}/LSLCMake.cmake") + elseif(LSL_FETCH_IF_MISSING) + # Priority 4: Fetch from GitHub + message(STATUS "liblsl not found locally, fetching ${LSL_FETCH_REF} from GitHub...") + include(FetchContent) + # Disable liblsl extras we don't need + set(LSL_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + set(LSL_BUILD_TESTING OFF CACHE BOOL "" FORCE) + # EXCLUDE_FROM_ALL prevents liblsl's install rules from running + FetchContent_Declare(liblsl + GIT_REPOSITORY https://github.com/sccn/liblsl.git + GIT_TAG ${LSL_FETCH_REF} + GIT_SHALLOW ON + EXCLUDE_FROM_ALL + ) + FetchContent_MakeAvailable(liblsl) + if(NOT TARGET LSL::lsl) + add_library(LSL::lsl ALIAS lsl) + endif() + set(LSL_FOUND TRUE) + include("${liblsl_SOURCE_DIR}/cmake/LSLCMake.cmake") + message(STATUS "liblsl fetched and configured") + else() + message(FATAL_ERROR + "liblsl not found. Options:\n" + " 1. Set LSL_SOURCE_DIR to liblsl source directory\n" + " 2. Set LSL_INSTALL_ROOT to installed liblsl location\n" + " 3. Install liblsl system-wide\n" + " 4. Enable LSL_FETCH_IF_MISSING=ON to auto-fetch from GitHub" + ) + endif() endif() -if (BUILD_GUI) - ## Qt - set(CMAKE_AUTOMOC ON) # The later version of this in LSLCMake is somehow not enough. - set(CMAKE_AUTORCC ON) - set(CMAKE_AUTOUIC ON) - find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) - find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Widgets Network DBus) -endif(BUILD_GUI) +# ============================================================================= +# Qt6 (for GUI build only) +# ============================================================================= +if(LABRECORDER_BUILD_GUI) + set(CMAKE_AUTOMOC ON) + set(CMAKE_AUTORCC ON) + set(CMAKE_AUTOUIC ON) + + find_package(Qt6 REQUIRED COMPONENTS Core Widgets Network) -## Threads + # macOS: Work around deprecated AGL framework issue in some Qt6 builds + if(APPLE AND TARGET WrapOpenGL::WrapOpenGL) + get_target_property(_wrap_gl_libs WrapOpenGL::WrapOpenGL INTERFACE_LINK_LIBRARIES) + if(_wrap_gl_libs) + list(FILTER _wrap_gl_libs EXCLUDE REGEX ".*AGL.*") + set_target_properties(WrapOpenGL::WrapOpenGL PROPERTIES INTERFACE_LINK_LIBRARIES "${_wrap_gl_libs}") + endif() + endif() +endif() + +# ============================================================================= +# Common Dependencies +# ============================================================================= find_package(Threads REQUIRED) +# ============================================================================= +# RPATH Configuration (must be set before targets are created) +# ============================================================================= +LSL_configure_rpath() + +# ============================================================================= # Targets +# ============================================================================= -## xdfwriter - stand alone library +# xdfwriter library add_subdirectory(xdfwriter) -if (BUILD_GUI) - add_executable(${PROJECT_NAME} MACOSX_BUNDLE) - - target_sources(${PROJECT_NAME} PRIVATE - src/main.cpp - src/mainwindow.cpp - src/mainwindow.h - src/mainwindow.ui - src/recording.h - src/recording.cpp - src/tcpinterface.h - src/tcpinterface.cpp - ) - - target_link_libraries(${PROJECT_NAME} - PRIVATE - xdfwriter - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Widgets - Qt${QT_VERSION_MAJOR}::Network - Qt${QT_VERSION_MAJOR}::DBus - Threads::Threads - LSL::lsl - ) -endif(BUILD_GUI) - - -add_executable(LabRecorderCLI MACOSX_BUNDLE - src/clirecorder.cpp - src/recording.h - src/recording.cpp +# GUI application +if(LABRECORDER_BUILD_GUI) + qt_add_executable(${PROJECT_NAME} MACOSX_BUNDLE WIN32 + src/main.cpp + src/mainwindow.cpp + src/mainwindow.h + src/mainwindow.ui + src/recording.h + src/recording.cpp + src/tcpinterface.h + src/tcpinterface.cpp + ) + + target_link_libraries(${PROJECT_NAME} PRIVATE + xdfwriter + Qt6::Core + Qt6::Widgets + Qt6::Network + Threads::Threads + LSL::lsl + ) + + # macOS bundle configuration + if(APPLE) + set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.labstreaminglayer.${PROJECT_NAME}") + set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}") + set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}") + endif() +endif() + +# CLI application +add_executable(${PROJECT_NAME}CLI + src/clirecorder.cpp + src/recording.h + src/recording.cpp +) +target_link_libraries(${PROJECT_NAME}CLI PRIVATE + xdfwriter + Threads::Threads + LSL::lsl ) -target_link_libraries(LabRecorderCLI - PRIVATE - xdfwriter - Threads::Threads - LSL::lsl +# ============================================================================= +# Copy config file to build directory for testing +# ============================================================================= +if(LABRECORDER_BUILD_GUI) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.cfg" + "$" + ) +endif() +add_custom_command(TARGET ${PROJECT_NAME}CLI POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.cfg" + "$" ) -installLSLApp(xdfwriter) -installLSLApp(testxdfwriter) -installLSLApp(LabRecorderCLI) -if (BUILD_GUI) - installLSLApp(${PROJECT_NAME}) - installLSLAuxFiles(${PROJECT_NAME} - ${PROJECT_NAME}.cfg - LICENSE - README.md - ) +# ============================================================================= +# Installation +# ============================================================================= +include(GNUInstallDirs) + +# Platform-specific install directories +if(WIN32) + set(INSTALL_BINDIR ".") + set(INSTALL_LIBDIR ".") + set(INSTALL_DATADIR ".") +elseif(APPLE) + set(INSTALL_BINDIR ".") + set(INSTALL_LIBDIR ".") + set(INSTALL_DATADIR ".") else() - installLSLAuxFiles(LabRecorderCLI - ${PROJECT_NAME}.cfg - LICENSE - README.md - ) -endif(BUILD_GUI) - - -if (WIN32) - if(BUILD_GUI) - get_target_property(QT_QMAKE_EXECUTABLE Qt::qmake IMPORTED_LOCATION) - get_filename_component(QT_WINDEPLOYQT_EXECUTABLE ${QT_QMAKE_EXECUTABLE} PATH) - set(QT_WINDEPLOYQT_EXECUTABLE "${QT_WINDEPLOYQT_EXECUTABLE}/windeployqt.exe") - - add_custom_command( - TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${QT_WINDEPLOYQT_EXECUTABLE} - --no-translations --no-system-d3d-compiler - --qmldir ${CMAKE_CURRENT_SOURCE_DIR} - $) - - add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $ - $) - else() - add_custom_command(TARGET LabRecorderCLI POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $ - $) - endif(BUILD_GUI) + # Linux: use standard FHS layout + set(INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}") + set(INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}") + set(INSTALL_DATADIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}") endif() -if (BUILD_GUI) - add_custom_command( - TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_SOURCE_DIR}//${PROJECT_NAME}.cfg - $) -else() - add_custom_command( - TARGET LabRecorderCLI POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_SOURCE_DIR}//${PROJECT_NAME}.cfg - $) -endif(BUILD_GUI) - -if(Qt6_FOUND AND BUILD_GUI) - set_target_properties(${PROJECT_NAME} PROPERTIES - QT_ANDROID_EXTRA_LIBS "${CMAKE_CURRENT_BINARY_DIR}/liblsl_bin/liblsl.so") - qt_finalize_executable(${PROJECT_NAME}) -endif(Qt6_FOUND AND BUILD_GUI) - -set(CPACK_DEBIAN_LABRECORDER_PACKAGE_SECTION "science" CACHE INTERNAL "") -LSLGenerateCPackConfig() - -if(APPLE AND NOT DEFINED ENV{GITHUB_ACTIONS}) - # Qt6 QtNetwork depends on libbrotidec which depends on libbroticommon but whose search path uses @loader_path. - # Unfortunately, macdeployqt does not seem to traverse @loader_path dependencies. - # So we are forced to call `fixup_bundle`. For now, we only do this if homebrew is present - # because that seems to be where the bad dependency is coming from. - # Note that fixup_bundle also destroys the codesigning so we have to redo that. - # TODO: Checkout supercollider apple-specific stuff, e.g.: https://github.com/supercollider/supercollider/blob/develop/CMakeLists.txt#L260-L262 - - # Detect Apple Silicon - execute_process( - COMMAND uname -m - OUTPUT_VARIABLE ARCH - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - # Check for Homebrew - execute_process( - COMMAND brew --prefix - RESULT_VARIABLE BREW_LIB - OUTPUT_VARIABLE BREW_PREFIX - OUTPUT_STRIP_TRAILING_WHITESPACE +# Install xdfwriter library +install(TARGETS xdfwriter + RUNTIME DESTINATION "${INSTALL_BINDIR}" + LIBRARY DESTINATION "${INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${INSTALL_LIBDIR}" +) + +# Install CLI +install(TARGETS ${PROJECT_NAME}CLI + RUNTIME DESTINATION "${INSTALL_BINDIR}" +) + +# Install GUI +if(LABRECORDER_BUILD_GUI) + install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION "${INSTALL_BINDIR}" + BUNDLE DESTINATION "${INSTALL_BINDIR}" ) - - if (BREW_LIB EQUAL 0 AND EXISTS "${BREW_PREFIX}") - install(CODE - " - include(BundleUtilities) - fixup_bundle(\"${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/${PROJECT_NAME}.app\" \"\" \"${BREW_PREFIX}/lib\") - - # Fix Qt plugin references specifically for Apple Silicon - if(\"${ARCH}\" STREQUAL \"arm64\") - execute_process(COMMAND install_name_tool -change @rpath/QtGui.framework/Versions/A/QtGui @executable_path/../Frameworks/QtGui - \"${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/${PROJECT_NAME}.app/Contents/PlugIns/platforms/libqcocoa.dylib\") - endif() - - # Re-sign with the same approach the project already uses - execute_process(COMMAND codesign --remove-signature \"${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/${PROJECT_NAME}.app\") - execute_process(COMMAND find \"${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/${PROJECT_NAME}.app/Contents/Frameworks\" -type f -exec codesign --force --sign - {} \\; 2>/dev/null || true) - execute_process(COMMAND find \"${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/${PROJECT_NAME}.app/Contents/PlugIns\" -type f -exec codesign --force --sign - {} \\; 2>/dev/null || true) - execute_process(COMMAND codesign --force --deep --sign - \"${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/${PROJECT_NAME}.app\") " +endif() + +# Install auxiliary files +set(_config_dest "${INSTALL_DATADIR}") +if(APPLE AND LABRECORDER_BUILD_GUI) + set(_config_dest "${INSTALL_BINDIR}/${PROJECT_NAME}.app/Contents/MacOS") +endif() +install(FILES + ${PROJECT_NAME}.cfg + LICENSE + README.md + DESTINATION "${_config_dest}" +) + +# ============================================================================= +# Bundle liblsl with the application +# ============================================================================= +if(APPLE) + # macOS: Install framework to GUI bundle and CLI Frameworks directory + if(LABRECORDER_BUILD_GUI) + LSL_install_liblsl( + FRAMEWORK_DESTINATION "${INSTALL_BINDIR}/${PROJECT_NAME}.app/Contents/Frameworks" + ) + endif() + LSL_install_liblsl(FRAMEWORK_DESTINATION "Frameworks") +else() + # Windows/Linux: Single install location for all targets + LSL_install_liblsl(DESTINATION "${INSTALL_LIBDIR}") +endif() + +# ============================================================================= +# Qt Deployment +# ============================================================================= +if(LABRECORDER_BUILD_GUI) + LSL_deploy_qt(TARGET "${PROJECT_NAME}" DESTINATION "${INSTALL_BINDIR}") +endif() + +# ============================================================================= +# MinGW Runtime Deployment +# ============================================================================= +LSL_install_mingw_runtime(DESTINATION "${INSTALL_BINDIR}") + +# ============================================================================= +# macOS: Code Sign +# ============================================================================= +if(APPLE) + if(LABRECORDER_BUILD_GUI) + LSL_codesign( + TARGET "${PROJECT_NAME}" + DESTINATION "${INSTALL_BINDIR}" + ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/app.entitlements" + BUNDLE ) endif() -endif(APPLE AND NOT DEFINED ENV{GITHUB_ACTIONS}) \ No newline at end of file + + LSL_codesign( + TARGET "${PROJECT_NAME}CLI" + DESTINATION "${INSTALL_BINDIR}" + ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/app.entitlements" + FRAMEWORK "Frameworks/lsl.framework" + ) +endif() + +# ============================================================================= +# CPack Configuration +# ============================================================================= +LSL_get_target_arch() +LSL_get_os_name() + +set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") +set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") +set(CPACK_PACKAGE_VENDOR "Labstreaminglayer") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}") +set(CPACK_PACKAGE_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") +set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") +set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-${LSL_OS}_${LSL_ARCH}") +set(CPACK_STRIP_FILES ON) + +if(WIN32) + set(CPACK_GENERATOR ZIP) + set(CPACK_WIX_UPGRADE_GUID "ee28a351-3b27-4c2b-8b48-259c87d1b1b4") +elseif(APPLE) + set(CPACK_GENERATOR TGZ) + set(CPACK_DMG_VOLUME_NAME "${PROJECT_NAME}") +else() + set(CPACK_GENERATOR DEB TGZ) + set(CPACK_DEBIAN_PACKAGE_MAINTAINER "LabStreamingLayer Developers") + set(CPACK_DEBIAN_PACKAGE_SECTION "science") + set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") + set(CPACK_DEBIAN_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}.deb") + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF) + if(LABRECORDER_BUILD_GUI) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6widgets6, libqt6network6") + endif() +endif() + +include(CPack) diff --git a/app.entitlements b/app.entitlements new file mode 100644 index 0000000..99d0921 --- /dev/null +++ b/app.entitlements @@ -0,0 +1,17 @@ + + + + + + com.apple.security.network.client + + + + com.apple.security.network.server + + + + com.apple.security.network.multicast + + + diff --git a/scripts/sign_and_notarize.sh b/scripts/sign_and_notarize.sh new file mode 100755 index 0000000..970f532 --- /dev/null +++ b/scripts/sign_and_notarize.sh @@ -0,0 +1,119 @@ +#!/bin/bash +# ============================================================================= +# Apple Code Signing and Notarization Script +# ============================================================================= +# This script handles identity-based signing and notarization for macOS apps. +# It's designed to be called from CI (GitHub Actions) after the build. +# +# Usage: +# ./scripts/sign_and_notarize.sh [--notarize] +# +# Environment Variables (set in CI): +# APPLE_CODE_SIGN_IDENTITY_APP - Developer ID Application certificate name +# APPLE_NOTARIZE_KEYCHAIN_PROFILE - notarytool credential profile name +# ENTITLEMENTS_FILE - Path to entitlements file (optional) +# +# Examples: +# # Sign only (for testing) +# ./scripts/sign_and_notarize.sh build/install/LabRecorder.app +# +# # Sign and notarize (for release) +# ./scripts/sign_and_notarize.sh build/install/LabRecorder.app --notarize +# ============================================================================= + +set -e + +# Parse arguments +APP_PATH="$1" +DO_NOTARIZE=false + +if [[ "$2" == "--notarize" ]]; then + DO_NOTARIZE=true +fi + +if [[ -z "$APP_PATH" ]]; then + echo "Usage: $0 [--notarize]" + exit 1 +fi + +if [[ ! -e "$APP_PATH" ]]; then + echo "Error: $APP_PATH does not exist" + exit 1 +fi + +# Default to ad-hoc signing if no identity specified +SIGN_IDENTITY="${APPLE_CODE_SIGN_IDENTITY_APP:--}" +ENTITLEMENTS_ARG="" + +# Use entitlements if specified and exists +if [[ -n "${ENTITLEMENTS_FILE}" && -f "${ENTITLEMENTS_FILE}" ]]; then + ENTITLEMENTS_ARG="--entitlements ${ENTITLEMENTS_FILE}" +elif [[ -f "$(dirname "$0")/../app.entitlements" ]]; then + ENTITLEMENTS_ARG="--entitlements $(dirname "$0")/../app.entitlements" +fi + +echo "=== Code Signing ===" +echo "Target: $APP_PATH" +echo "Identity: $SIGN_IDENTITY" +echo "Entitlements: ${ENTITLEMENTS_ARG:-none}" + +if [[ -d "$APP_PATH" ]]; then + # App bundle - sign with deep and hardened runtime + codesign --force --deep --sign "$SIGN_IDENTITY" \ + --options runtime \ + $ENTITLEMENTS_ARG \ + "$APP_PATH" +else + # Single binary + codesign --force --sign "$SIGN_IDENTITY" \ + --options runtime \ + $ENTITLEMENTS_ARG \ + "$APP_PATH" +fi + +echo "Verifying signature..." +codesign --verify --verbose "$APP_PATH" + +# Check if we should notarize +if [[ "$DO_NOTARIZE" == true ]]; then + if [[ "$SIGN_IDENTITY" == "-" ]]; then + echo "Warning: Cannot notarize with ad-hoc signature. Skipping notarization." + exit 0 + fi + + if [[ -z "$APPLE_NOTARIZE_KEYCHAIN_PROFILE" ]]; then + echo "Error: APPLE_NOTARIZE_KEYCHAIN_PROFILE not set" + exit 1 + fi + + echo "" + echo "=== Notarizing ===" + + # Create zip for notarization submission + BASENAME=$(basename "$APP_PATH") + ZIP_PATH="/tmp/${BASENAME%.*}_notarize.zip" + + echo "Creating zip for submission: $ZIP_PATH" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" + + echo "Submitting to Apple notarization service..." + xcrun notarytool submit "$ZIP_PATH" \ + --keychain-profile "$APPLE_NOTARIZE_KEYCHAIN_PROFILE" \ + --wait + + # Staple the notarization ticket + if [[ -d "$APP_PATH" ]]; then + echo "Stapling notarization ticket..." + xcrun stapler staple "$APP_PATH" + xcrun stapler validate "$APP_PATH" + fi + + # Clean up + rm -f "$ZIP_PATH" + + echo "" + echo "=== Notarization Complete ===" +fi + +echo "" +echo "Done!" diff --git a/xdfwriter/CMakeLists.txt b/xdfwriter/CMakeLists.txt index 039b5ef..48155f0 100644 --- a/xdfwriter/CMakeLists.txt +++ b/xdfwriter/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.14) project(xdfwriter DESCRIPTION "C++ library for writing XDF files" @@ -6,11 +6,11 @@ project(xdfwriter LANGUAGES C CXX VERSION 1.16.0) -option(LABRECORDER_XDFZ "use Boost.Iostreams for XDFZ support" Off) -option(LABRECORDER_BOOST_TYPE_CONVERSIONS "Use boost for type conversions" Off) +option(LABRECORDER_XDFZ "use Boost.Iostreams for XDFZ support" OFF) +option(LABRECORDER_BOOST_TYPE_CONVERSIONS "Use boost for type conversions" OFF) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED On) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) add_library(${PROJECT_NAME} xdfwriter.cpp) @@ -25,7 +25,7 @@ if(NOT LABRECORDER_SKIP_CPUTESTS) try_run(IS_LITTLE_ENDIAN IS_IEC559 ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/test_iec559_and_little_endian.cpp" - CMAKE_FLAGS "-DCMAKE_CXX_STANDARD=14" "-DCMAKE_CXX_STANDARD_REQUIRED=On" + CMAKE_FLAGS "-DCMAKE_CXX_STANDARD=20" "-DCMAKE_CXX_STANDARD_REQUIRED=ON" COMPILE_OUTPUT_VARIABLE IEC559_COMPILE) if(NOT IS_IEC559) message(WARNING "IEC559 test: ${IEC559_COMPILE}") From e33df18e43ae756bbce1e0a0c2963ed509b9ba4b Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Sat, 10 Jan 2026 18:33:59 -0500 Subject: [PATCH 2/3] Update liblsl ref to 1.17.0 --- CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69eef7f..1f8029a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ if(POLICY CMP0177) endif() project(LabRecorder - VERSION 1.16.5 + VERSION 1.17.0 DESCRIPTION "Record and write LabStreamingLayer streams to an XDF file" HOMEPAGE_URL "https://github.com/labstreaminglayer/App-LabRecorder/" LANGUAGES C CXX @@ -40,8 +40,7 @@ set(LSL_INSTALL_ROOT "" CACHE PATH "Path to installed liblsl") # Priority 4: Fetch from GitHub if not found option(LSL_FETCH_IF_MISSING "Fetch liblsl from GitHub if not found locally" ON) -# TODO: Change back to version tag (e.g., "v1.16.2") once apple_framework branch is merged -set(LSL_FETCH_REF "cboulay/apple_framework" CACHE STRING "liblsl git ref to fetch (tag, branch, or commit)") +set(LSL_FETCH_REF "v1.17.0" CACHE STRING "liblsl git ref to fetch (tag, branch, or commit)") # ============================================================================= # Find/Fetch liblsl From 748c89bb9fe887c9c0310051da60d6666b50313f Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Mon, 12 Jan 2026 11:36:33 -0500 Subject: [PATCH 3/3] Update deps and README.md --- CMakeLists.txt | 2 +- README.md | 5 ++--- xdfwriter/CMakeLists.txt | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f8029a..5d70a3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ set(LSL_INSTALL_ROOT "" CACHE PATH "Path to installed liblsl") # Priority 4: Fetch from GitHub if not found option(LSL_FETCH_IF_MISSING "Fetch liblsl from GitHub if not found locally" ON) -set(LSL_FETCH_REF "v1.17.0" CACHE STRING "liblsl git ref to fetch (tag, branch, or commit)") +set(LSL_FETCH_REF "v1.17.4" CACHE STRING "liblsl git ref to fetch (tag, branch, or commit)") # ============================================================================= # Find/Fetch liblsl diff --git a/README.md b/README.md index 83cd195..6a4574d 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,11 @@ Run it with `open /usr/local/opt/labrecorder/LabRecorder/LabRecorder.app` The Ubuntu releases do not typically ship with their dependencies, so you must download and install those: * Download, extract, and install the latest [liblsl-{version}-{target}_amd64.deb from its release page](https://github.com/sccn/liblsl/releases) * We hope to make this available via a package manager soon. - * Quick ref Ubuntu 20.04: `curl -L https://github.com/sccn/liblsl/releases/download/v1.16.0/liblsl-1.16.0-bionic_amd64.deb -o liblsl.deb` - * Quick ref Ubuntu 22.04: `curl -L https://github.com/sccn/liblsl/releases/download/v1.16.0/liblsl-1.16.0-jammy_amd64.deb -o liblsl.deb` + * Quick ref Ubuntu 24.04: `curl -L https://github.com/sccn/liblsl/releases/download/v1.17.4/liblsl-1.17.4-noble_amd64.deb -o liblsl.deb` + * Quick ref Ubuntu 22.04: `curl -L https://github.com/sccn/liblsl/releases/download/v1.17.4/liblsl-1.17.4-jammy_amd64.deb -o liblsl.deb` * You can install liblsl directly by double-clicking on the deb, or with `sudo dpkg -i {filename}.deb` or `sudo apt install {filename}.deb` * See the bottom of the [lsl build env docs](https://labstreaminglayer.readthedocs.io/dev/build_env.html). * For most cases, this will amount to installing Qt and its dependencies: - * Ubuntu 18.xx or 20.xx: `sudo apt-get install build-essential qtbase5-dev libpugixml-dev` * Ubuntu >= 22.04: `sudo apt-get install qt6-base-dev freeglut3-dev` # Usage diff --git a/xdfwriter/CMakeLists.txt b/xdfwriter/CMakeLists.txt index 48155f0..4abb431 100644 --- a/xdfwriter/CMakeLists.txt +++ b/xdfwriter/CMakeLists.txt @@ -4,7 +4,7 @@ project(xdfwriter DESCRIPTION "C++ library for writing XDF files" HOMEPAGE_URL "https://github.com/labstreaminglayer/App-LabRecorder/" LANGUAGES C CXX - VERSION 1.16.0) + VERSION 1.17.0) option(LABRECORDER_XDFZ "use Boost.Iostreams for XDFZ support" OFF) option(LABRECORDER_BOOST_TYPE_CONVERSIONS "Use boost for type conversions" OFF)