Using liblsl in your project
liblsl has a C API (#include <lsl_c.h>) and a header-only C++ wrapper around it
(#include <lsl_cpp.h>). Both come from the same library, so any way of linking below works
for C and C++ programs.
The CMake package is the best-supported route: it carries the include directories, the
compile definitions and, for static builds, every dependency, so your project only names one
target. The same package is installed by release archives, package managers and cmake --install.
CMake: an installed liblsl
find_package(LSL REQUIRED)
target_link_libraries(myapp PRIVATE LSL::lsl)
If CMake doesn’t find it on its own, point it at the install prefix (the folder that contains
lib/ and include/) when configuring:
cmake -S . -B build -DCMAKE_PREFIX_PATH=/path/to/liblsl # extracted release, or your own install
cmake -S . -B build -DCMAKE_PREFIX_PATH="$(brew --prefix lsl)" # Homebrew
A static liblsl is used the same way. Its CMake package looks up what liblsl itself needs (threads, a system pugixml if liblsl was built against one, and the Windows socket libraries) and passes it on, so you don’t link anything extra.
cmake --install of a macOS framework build also puts the CMake package in lib/cmake/lsl, so
the CMAKE_PREFIX_PATH above works for it too. The release .pkg and older installs only have
it inside the framework; for those, configure with
-DLSL_DIR=/Library/Frameworks/lsl.framework/Resources/CMake (or the framework’s location).
CMake: build liblsl with your project (FetchContent)
include(FetchContent)
FetchContent_Declare(liblsl
GIT_REPOSITORY https://github.com/sccn/liblsl.git
GIT_TAG v1.18.0 # a release tag
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(liblsl)
target_link_libraries(myapp PRIVATE LSL::lsl)
liblsl is then configured and built with your compiler and settings. Good to know:
Shared or static. liblsl builds a shared library by default. Set
LSL_BUILD_STATIC ONbeforeFetchContent_MakeAvailable, or setBUILD_SHARED_LIBS OFF(liblsl follows it when it is defined).macOS. liblsl builds an
lsl.frameworkby default (LSL_FRAMEWORK); setLSL_FRAMEWORK OFFfor a plainliblsl.dylib.Network at configure time. liblsl downloads pugixml while configuring. For offline or sandboxed builds use a system pugixml with
LSL_FETCH_PUGIXML OFF(see Building liblsl).No side effects. As a subproject, liblsl adds no install rules, tests or packaging targets to your project.
Shipping your application
A program linked to a shared liblsl needs to find it at run time:
Windows:
lsl.dllmust be next to your.exe(or onPATH). In CMake, copy it with$<TARGET_RUNTIME_DLLS:myapp>, or useLSL_install_liblsl(below).Linux: a liblsl in a system library folder is found automatically. If you ship liblsl next to your program, give the program an RPATH such as
$ORIGIN/../lib.macOS: liblsl’s install name starts with
@rpath, so your program needs an RPATH entry for the folder that holdslsl.frameworkorliblsl.dylib(CMake adds one for the build tree; for installed apps use e.g.@executable_path/../Frameworks). In an app bundle, putlsl.frameworkinContents/Frameworks.
A static liblsl has none of these concerns. It also keeps its symbols to itself: a program or shared library that links it does not export liblsl’s API.
LSLCMake helpers
liblsl installs LSLCMake.cmake next to its CMake package with helpers for applications:
find_package(LSL REQUIRED)
include("${LSL_DIR}/LSLCMake.cmake") # with FetchContent: "${liblsl_SOURCE_DIR}/cmake/LSLCMake.cmake"
LSL_configure_rpath() # before creating targets
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE LSL::lsl)
install(TARGETS myapp RUNTIME DESTINATION bin)
LSL_install_liblsl(DESTINATION bin FRAMEWORK_DESTINATION Frameworks)
Function |
What it does |
|---|---|
|
Sets relative RPATHs so installed programs find a liblsl shipped next to them. |
|
Copies |
|
MinGW only: copies the compiler’s runtime DLLs. |
|
Runs |
|
Ad-hoc signs a macOS app or program, e.g. with the multicast entitlement. |
|
Set |
Package managers that ship liblsl and Qt themselves set LSL_BUNDLE_DEPENDENCIES OFF, which
turns LSL_install_liblsl, LSL_deploy_qt and LSL_codesign into no-ops.
pkg-config
Linux installs and macOS installs made with cmake --install (including Homebrew) include lsl.pc:
c++ main.cpp $(pkg-config --cflags --libs lsl) -o myapp
c++ main.cpp $(pkg-config --static --cflags --libs lsl) -o myapp # static liblsl
On macOS the flags include the RPATH that liblsl’s @rpath install name needs. A framework
install also provides lib/liblsl.dylib and include/ links into the framework, so the same
flags work there. If liblsl is installed outside the default search path, set
PKG_CONFIG_PATH=<prefix>/lib/pkgconfig.
Other build systems and plain compilers
Add
<prefix>/includeto the include path and link-llsl(lsl.libwith MSVC).Windows, static liblsl: define
LIBLSL_STATICwhen compiling your code. With a shared liblsl, define nothing.MSVC: including the headers already asks the linker for
lsl.lib(#pragma comment(lib, ...)); defineLSLNOAUTOLINKto turn that off.macOS framework: compile and link with
-F <dir containing lsl.framework> -framework lsland include the headers as#include <lsl/lsl_cpp.h>.
Xcode, iOS and iPadOS
Add lsl.xcframework from a release to your target
with Embed & Sign, and #include <lsl/lsl_cpp.h> (or lsl_c.h). Stream discovery uses UDP
multicast, so iOS apps need the com.apple.developer.networking.multicast entitlement
(requested from Apple per app ID) and an NSLocalNetworkUsageDescription entry in
Info.plist. To build the frameworks yourself see Building liblsl.
Examples
The examples/ folder has small C and C++
programs (sending and receiving data, markers, chunks, metadata) with a CMakeLists.txt
that uses find_package(LSL). testing/consumer/ is the minimal project CI uses to check every
way of linking described on this page.