1

cmake-genex can be used to conditionally link libraries based on information only available at CMake build-time:

Example 1: Using one genex per lib

cmake_minimum_required(VERSION 3.20.0)

project(cmake-genex)

add_library(lib1 SHARED source1.hpp source1.cpp)
add_library(lib2 SHARED source2.hpp source2.cpp)
add_library(lib3 SHARED source3.hpp source3.cpp)

add_executable(main main.cpp)
target_link_libraries(main
    $<$<PLATFORM_ID:Linux>:lib1>
    $<$<PLATFORM_ID:Linux>:lib2>
    $<$<PLATFORM_ID:Linux>:lib3>
)

This works as intended, however is a bit verbose. It'd be neat to use a single genex for all libs:

Example 2: Using one genex for all libs

cmake_minimum_required(VERSION 3.20.0)

project(cmake-genex)

add_library(lib1 SHARED source1.hpp source1.cpp)
add_library(lib2 SHARED source2.hpp source2.cpp)
add_library(lib3 SHARED source3.hpp source3.cpp)

set(linux_libs
    lib1
    lib2
    lib3
)

add_executable(main main.cpp)
target_link_libraries(main
    $<$<PLATFORM_ID:Linux>:${linux_libs}>
)

However, Example2 fails. In my case I used ninja as generator. ninja.build shows this:

ninja.build (excerpt)

LINK_LIBRARIES = -Wl,-rpath,/mnt/c/Users/joakim.thoren/programming/cmake-genex/build  $<1:lib1  liblib2.so  -llib3>

I expected the following:

LINK_LIBRARIES = -Wl,-rpath,/mnt/c/Users/joakim.thoren/programming/cmake-genex/build  liblib1.so  liblib2.so  liblib3.so

How can one genex decide whether to conditionally link towards several libraries or not?

Joakim Thorén
  • 1,111
  • 10
  • 17
  • Why use generator expressions here? I'd consider `if(UNIX) target_link_libraries(main lib1 lib2 lib3) endif()` much easier to comprehend... – fabian Oct 18 '21 at 15:52
  • @fabian This is just an SSCCE instead of my real-world use case. You can of course just do it like you did and avoid genexes altogether. – Joakim Thorén Oct 20 '21 at 05:30

1 Answers1

2

It's possible to use one genex for all libs if the genex is quoted:

Working example with one genex for all libs

cmake_minimum_required(VERSION 3.20.0)

project(cmake-genex)

add_library(lib1 SHARED source1.hpp source1.cpp)
add_library(lib2 SHARED source2.hpp source2.cpp)
add_library(lib3 SHARED source3.hpp source3.cpp)

set(linux_libs
    lib1
    lib2
    lib3
)

add_executable(main main.cpp)
target_link_libraries(main
    "$<$<PLATFORM_ID:Linux>:${linux_libs}>"
)

This will generate the expected output:

LINK_LIBRARIES = -Wl,-rpath,/mnt/c/Users/joakim.thoren/programming/cmake-genex/build  liblib1.so  liblib2.so  liblib3.so

I don't know why quoting works. Maybe someone else can explain this.

Joakim Thorén
  • 1,111
  • 10
  • 17
  • This post inspired me to ask the same on the CMake discourse site [here](https://discourse.cmake.org/t/target-link-libraries-and-list-of-platform-ids/6549). Basically you can lose the temp variable for the list if you quote the genex and use the semicolon as the list separator on the arguments. The quoting is needed due to how CMake parsing and splitting works apparently. – firmament Sep 27 '22 at 09:20