|
| 1 | +From 892320ffc446eb2d18b19fff73f8fdbadf834f68 Mon Sep 17 00:00:00 2001 |
| 2 | +From: myd7349 <myd7349@gmail.com> |
| 3 | +Date: Mon, 21 Sep 2026 00:04:51 +0800 |
| 4 | +Subject: [PATCH 1/2] Fix transitive dependencies for static LSL::lsl |
| 5 | + |
| 6 | +Static builds of lsl did not forward its transitive dependencies |
| 7 | +(Threads, Windows iphlpapi/winmm/mswsock/ws2_32, Linux rt/dl, system |
| 8 | +pugixml) because they were linked PRIVATE via the lslobj object |
| 9 | +library. Consumers linking LSL::lsl therefore had to manually add |
| 10 | +these transitive dependencies themselves. |
| 11 | +--- |
| 12 | + cmake/Dependencies.cmake | 49 +++++++++++++++++++++++++++++++++++----- |
| 13 | + cmake/Installation.cmake | 22 +++++++++++------- |
| 14 | + cmake/LSLConfig.cmake.in | 17 ++++++++++++++ |
| 15 | + cmake/TargetLib.cmake | 2 +- |
| 16 | + cmake/TargetObjLib.cmake | 21 +---------------- |
| 17 | + testing/CMakeLists.txt | 10 -------- |
| 18 | + 6 files changed, 76 insertions(+), 45 deletions(-) |
| 19 | + create mode 100644 cmake/LSLConfig.cmake.in |
| 20 | + |
| 21 | +diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake |
| 22 | +index 223cfe11..125b5a9f 100644 |
| 23 | +--- a/cmake/Dependencies.cmake |
| 24 | ++++ b/cmake/Dependencies.cmake |
| 25 | +@@ -26,9 +26,6 @@ if(LSL_FETCH_PUGIXML) |
| 26 | + FetchContent_MakeAvailable(pugixml) |
| 27 | + set(BUILD_SHARED_LIBS ${_lsl_saved_build_shared_libs}) |
| 28 | + unset(_lsl_saved_build_shared_libs) |
| 29 | +- if(TARGET pugixml AND NOT TARGET pugixml::pugixml) |
| 30 | +- add_library(pugixml::pugixml ALIAS pugixml) |
| 31 | +- endif() |
| 32 | + # Hide pugixml symbols - apply hidden visibility to the pugixml target |
| 33 | + set_target_properties(pugixml PROPERTIES |
| 34 | + CXX_VISIBILITY_PRESET hidden |
| 35 | +@@ -50,9 +47,6 @@ else() |
| 36 | + unset(_lsl_arch_count) |
| 37 | + endif() |
| 38 | + find_package(pugixml REQUIRED) |
| 39 | +- if(NOT TARGET pugixml::pugixml) |
| 40 | +- add_library(pugixml::pugixml ALIAS pugixml) |
| 41 | +- endif() |
| 42 | + set(LSL_PUGIXML_IS_FETCHED FALSE) |
| 43 | + endif() |
| 44 | + |
| 45 | +@@ -73,3 +67,46 @@ else() |
| 46 | + target_link_libraries(lslboost INTERFACE Boost::boost Boost::disable_autolinking) |
| 47 | + endif() |
| 48 | + target_compile_definitions(lslboost INTERFACE BOOST_ALL_NO_LIB) |
| 49 | ++ |
| 50 | ++# Single source of truth for every external (system/third-party) library lsl needs to link |
| 51 | ++# against. lslobj (which internal tests also link directly) and the real lsl target both |
| 52 | ++# link this same list, so it only has to be kept up to date in one place. Having lsl itself |
| 53 | ++# link these directly (not only indirectly via lslobj) matters for static builds: CMake |
| 54 | ++# records a STATIC library's PRIVATE link dependencies as $<LINK_ONLY:...> entries in its |
| 55 | ++# exported INTERFACE_LINK_LIBRARIES, so consumers linking the installed LSL::lsl get them |
| 56 | ++# transitively instead of having to add them by hand. For shared builds these stay private/ |
| 57 | ++# hidden, which is correct since the dependencies are already resolved inside the shared lib. |
| 58 | ++set(lsllinklibs Threads::Threads) |
| 59 | ++ |
| 60 | ++if(NOT LSL_PUGIXML_IS_FETCHED) |
| 61 | ++ if(TARGET pugixml::pugixml) |
| 62 | ++ list(APPEND lsllinklibs pugixml::pugixml) |
| 63 | ++ elseif(TARGET pugixml) |
| 64 | ++ # For pugixml versions before 1.11 |
| 65 | ++ list(APPEND lsllinklibs pugixml) |
| 66 | ++ else() |
| 67 | ++ message(FATAL_ERROR "pugixml library target not found!") |
| 68 | ++ endif() |
| 69 | ++endif() |
| 70 | ++ |
| 71 | ++if(NOT LSL_BUNDLED_BOOST) |
| 72 | ++ list(APPEND lsllinklibs Boost::boost Boost::disable_autolinking) |
| 73 | ++endif() |
| 74 | ++ |
| 75 | ++if(MINGW) |
| 76 | ++ list(APPEND lsllinklibs bcrypt) |
| 77 | ++endif() |
| 78 | ++ |
| 79 | ++if(UNIX AND NOT APPLE) |
| 80 | ++ # check that clock_gettime is present in the stdlib, link against librt otherwise |
| 81 | ++ include(CheckSymbolExists) |
| 82 | ++ check_symbol_exists(clock_gettime time.h HAS_GETTIME) |
| 83 | ++ if(NOT HAS_GETTIME) |
| 84 | ++ list(APPEND lsllinklibs rt) |
| 85 | ++ endif() |
| 86 | ++ if(LSL_DEBUGLOG) |
| 87 | ++ list(APPEND lsllinklibs dl) |
| 88 | ++ endif() |
| 89 | ++elseif(WIN32) |
| 90 | ++ list(APPEND lsllinklibs iphlpapi winmm mswsock ws2_32) |
| 91 | ++endif() |
| 92 | +diff --git a/cmake/Installation.cmake b/cmake/Installation.cmake |
| 93 | +index 19e57233..51710f56 100644 |
| 94 | +--- a/cmake/Installation.cmake |
| 95 | ++++ b/cmake/Installation.cmake |
| 96 | +@@ -61,23 +61,29 @@ install(TARGETS ${LSLTargets} |
| 97 | + install(DIRECTORY include/lsl DESTINATION ${LSL_INSTALL_INCLUDEDIR}) |
| 98 | + install(FILES include/lsl_c.h include/lsl_cpp.h DESTINATION ${LSL_INSTALL_INCLUDEDIR}) |
| 99 | + |
| 100 | +-# Generate the LSLConfig.cmake file and mark it for installation |
| 101 | ++# Export the targets to a separate LSLTargets.cmake file, included by the |
| 102 | ++# LSLConfig.cmake below. |
| 103 | + install(EXPORT LSLTargets |
| 104 | +- FILE LSLConfig.cmake |
| 105 | ++ FILE LSLTargets.cmake |
| 106 | + COMPONENT liblsl |
| 107 | + NAMESPACE "LSL::" |
| 108 | + DESTINATION ${LSL_CONFIG_INSTALL_DIR} |
| 109 | + ) |
| 110 | +-# A common alternative to installing the exported package config file is to generate it from a template. |
| 111 | +-#configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/lslConfig.cmake.in |
| 112 | +-# ${CMAKE_CURRENT_BINARY_DIR}/LSLConfig.cmake |
| 113 | +-# INSTALL_DESTINATION ${LSL_CONFIG_INSTALL_DIR}) |
| 114 | +-# If we use this method, then we need a corresponding install(FILES ...) command to install the generated file. |
| 115 | + |
| 116 | +-# Install the version file and the helper CMake script. |
| 117 | ++# Generate LSLConfig.cmake from a template so it can call find_dependency() for |
| 118 | ++# the transitive dependencies that a static LSL::lsl requires its consumers to |
| 119 | ++# link against. |
| 120 | ++configure_package_config_file( |
| 121 | ++ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/LSLConfig.cmake.in |
| 122 | ++ ${CMAKE_CURRENT_BINARY_DIR}/LSLConfig.cmake |
| 123 | ++ INSTALL_DESTINATION ${LSL_CONFIG_INSTALL_DIR} |
| 124 | ++) |
| 125 | ++ |
| 126 | ++# Install the version file, generated config file, and the helper CMake script. |
| 127 | + install( |
| 128 | + FILES |
| 129 | + cmake/LSLCMake.cmake |
| 130 | ++ ${CMAKE_CURRENT_BINARY_DIR}/LSLConfig.cmake |
| 131 | + ${CMAKE_CURRENT_BINARY_DIR}/LSLConfigVersion.cmake |
| 132 | + COMPONENT liblsl |
| 133 | + DESTINATION ${LSL_CONFIG_INSTALL_DIR} |
| 134 | +diff --git a/cmake/LSLConfig.cmake.in b/cmake/LSLConfig.cmake.in |
| 135 | +new file mode 100644 |
| 136 | +index 00000000..0a7bc0ba |
| 137 | +--- /dev/null |
| 138 | ++++ b/cmake/LSLConfig.cmake.in |
| 139 | +@@ -0,0 +1,17 @@ |
| 140 | ++@PACKAGE_INIT@ |
| 141 | ++ |
| 142 | ++include(CMakeFindDependencyMacro) |
| 143 | ++ |
| 144 | ++find_dependency(Threads) |
| 145 | ++ |
| 146 | ++if(NOT @LSL_BUNDLED_BOOST@) |
| 147 | ++ find_dependency(Boost) |
| 148 | ++endif() |
| 149 | ++ |
| 150 | ++if(NOT @LSL_FETCH_PUGIXML@) |
| 151 | ++ find_dependency(pugixml) |
| 152 | ++endif() |
| 153 | ++ |
| 154 | ++include("${CMAKE_CURRENT_LIST_DIR}/LSLTargets.cmake") |
| 155 | ++ |
| 156 | ++check_required_components(LSL) |
| 157 | +diff --git a/cmake/TargetLib.cmake b/cmake/TargetLib.cmake |
| 158 | +index 89606b6e..45097421 100644 |
| 159 | +--- a/cmake/TargetLib.cmake |
| 160 | ++++ b/cmake/TargetLib.cmake |
| 161 | +@@ -30,7 +30,7 @@ endif() |
| 162 | + # but are used by the internal tests. |
| 163 | + # Note: We use BUILD_INTERFACE to avoid requiring lslobj in the export set - the object library's |
| 164 | + # objects are linked directly into lsl, so consumers don't need lslobj. |
| 165 | +-target_link_libraries(lsl PRIVATE $<BUILD_INTERFACE:lslobj>) |
| 166 | ++target_link_libraries(lsl PRIVATE $<BUILD_INTERFACE:lslobj> ${lsllinklibs}) |
| 167 | + |
| 168 | + # Set the include directories for the lsl target. |
| 169 | + # Note: We had to link lslobj as a PRIVATE dependency, therefore we must manually expose the include directories |
| 170 | +diff --git a/cmake/TargetObjLib.cmake b/cmake/TargetObjLib.cmake |
| 171 | +index 8c1f6afb..24720bd6 100644 |
| 172 | +--- a/cmake/TargetObjLib.cmake |
| 173 | ++++ b/cmake/TargetObjLib.cmake |
| 174 | +@@ -29,23 +29,7 @@ target_include_directories(lslobj |
| 175 | + |
| 176 | + # Link system libs |
| 177 | + # (boost might be bundled or system) |
| 178 | +-target_link_libraries(lslobj PRIVATE lslboost Threads::Threads) |
| 179 | +-if(MINGW) |
| 180 | +- target_link_libraries(lslobj PRIVATE bcrypt) |
| 181 | +-endif() |
| 182 | +-if(UNIX AND NOT APPLE) |
| 183 | +- # check that clock_gettime is present in the stdlib, link against librt otherwise |
| 184 | +- include(CheckSymbolExists) |
| 185 | +- check_symbol_exists(clock_gettime time.h HAS_GETTIME) |
| 186 | +- if(NOT HAS_GETTIME) |
| 187 | +- target_link_libraries(lslobj PRIVATE rt) |
| 188 | +- endif() |
| 189 | +- if(LSL_DEBUGLOG) |
| 190 | +- target_link_libraries(lslobj PRIVATE dl) |
| 191 | +- endif() |
| 192 | +-elseif(WIN32) |
| 193 | +- target_link_libraries(lslobj PRIVATE iphlpapi winmm mswsock ws2_32) |
| 194 | +-endif() |
| 195 | ++target_link_libraries(lslobj PRIVATE lslboost ${lsllinklibs}) |
| 196 | + |
| 197 | + # Compiler settings |
| 198 | + target_compile_definitions(lslobj |
| 199 | +@@ -102,7 +86,4 @@ if(LSL_PUGIXML_IS_FETCHED) |
| 200 | + if(UNIX AND NOT APPLE) |
| 201 | + target_link_options(lslobj PRIVATE "LINKER:--exclude-libs,libpugixml.a") |
| 202 | + endif() |
| 203 | +-else() |
| 204 | +- # System pugixml may be shared or static |
| 205 | +- target_link_libraries(lslobj PRIVATE pugixml::pugixml) |
| 206 | + endif() |
| 207 | +diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt |
| 208 | +index fa66c7d9..a71c4eb2 100644 |
| 209 | +--- a/testing/CMakeLists.txt |
| 210 | ++++ b/testing/CMakeLists.txt |
| 211 | +@@ -102,8 +102,6 @@ target_link_libraries(lsl_test_internal PRIVATE lslobj lslboost common catch_mai |
| 212 | + # Internal tests need pugixml headers (lslobj links pugixml privately) |
| 213 | + if(LSL_PUGIXML_IS_FETCHED) |
| 214 | + target_include_directories(lsl_test_internal PRIVATE ${pugixml_SOURCE_DIR}/src) |
| 215 | +-else() |
| 216 | +- target_link_libraries(lsl_test_internal PRIVATE pugixml::pugixml) |
| 217 | + endif() |
| 218 | + # Pretend that lsl_test_internal is part of a shared lib so that it can use the __export symbols lslobj. REQ by MinGW. |
| 219 | + target_compile_definitions(lsl_test_internal PRIVATE LIBLSL_EXPORTS) |
| 220 | +@@ -120,8 +118,6 @@ target_compile_definitions(lsl_test_resolve_bad_interface PRIVATE LIBLSL_EXPORTS |
| 221 | + # Needs pugixml headers (resolver_impl.h -> stream_info_impl.h includes pugixml) |
| 222 | + if(LSL_PUGIXML_IS_FETCHED) |
| 223 | + target_include_directories(lsl_test_resolve_bad_interface PRIVATE ${pugixml_SOURCE_DIR}/src) |
| 224 | +-else() |
| 225 | +- target_link_libraries(lsl_test_resolve_bad_interface PRIVATE pugixml::pugixml) |
| 226 | + endif() |
| 227 | + |
| 228 | + # resolve_machine test sets the api_config singleton, so it lives in its own executable. |
| 229 | +@@ -131,8 +127,6 @@ target_compile_definitions(lsl_test_resolve_machine PRIVATE LIBLSL_EXPORTS) |
| 230 | + # Needs pugixml headers (resolver_impl.h -> stream_info_impl.h includes pugixml) |
| 231 | + if(LSL_PUGIXML_IS_FETCHED) |
| 232 | + target_include_directories(lsl_test_resolve_machine PRIVATE ${pugixml_SOURCE_DIR}/src) |
| 233 | +-else() |
| 234 | +- target_link_libraries(lsl_test_resolve_machine PRIVATE pugixml::pugixml) |
| 235 | + endif() |
| 236 | + |
| 237 | + # resolve_over_tcp test sets the api_config singleton, so it lives in its own executable. |
| 238 | +@@ -142,8 +136,6 @@ target_compile_definitions(lsl_test_resolve_over_tcp PRIVATE LIBLSL_EXPORTS) |
| 239 | + # Needs pugixml headers (resolver_impl.h -> stream_info_impl.h includes pugixml) |
| 240 | + if(LSL_PUGIXML_IS_FETCHED) |
| 241 | + target_include_directories(lsl_test_resolve_over_tcp PRIVATE ${pugixml_SOURCE_DIR}/src) |
| 242 | +-else() |
| 243 | +- target_link_libraries(lsl_test_resolve_over_tcp PRIVATE pugixml::pugixml) |
| 244 | + endif() |
| 245 | + |
| 246 | + # resolve_query_port test sets the api_config singleton, so it lives in its own executable. |
| 247 | +@@ -153,8 +145,6 @@ target_compile_definitions(lsl_test_resolve_query_port PRIVATE LIBLSL_EXPORTS) |
| 248 | + # Needs pugixml headers (resolver_impl.h -> stream_info_impl.h includes pugixml) |
| 249 | + if(LSL_PUGIXML_IS_FETCHED) |
| 250 | + target_include_directories(lsl_test_resolve_query_port PRIVATE ${pugixml_SOURCE_DIR}/src) |
| 251 | +-else() |
| 252 | +- target_link_libraries(lsl_test_resolve_query_port PRIVATE pugixml::pugixml) |
| 253 | + endif() |
| 254 | + |
| 255 | + if(LSL_BENCHMARKS) |
| 256 | +-- |
| 257 | +2.55.0.windows.2 |
| 258 | + |
0 commit comments