CMake: target_link_libraries based on flag - cmake

There are 4 libs linked already and want to link a new library if FLAG is ON.
target_link_libraries (lib1 lib2 lib3 lib4 ${CMAKE_DL_LIBS})
I want it to be something like
target_link_libraries (lib1 lib2 lib3 lib4 if(FLAG) lib5 endif() ${CMAKE_DL_LIBS})
Is there anyway to implement this in cmakelists.txt?

Simply use multiple target_link_library commands.
E.g. the following could be used to add a lib for unix targets
target_link_libraries (lib1 lib2 lib3 lib4 ${CMAKE_DL_LIBS})
if(UNIX)
target_link_libraries(lib1 lib5)
endif()
Alternatively you could use a list containing the libs to include
set(LIBS lib2 lib3 lib4 ${CMAKE_DL_LIBS})
if(UNIX)
list(APPEND LIBS lib5)
endif()
target_link_libraries(lib1 ${LIBS})
In theory you could also use generator expressions, but imho this would make for the least readable alternative
target_link_libraries(lib1 lib2 lib3 lib4 ${CMAKE_DL_LIBS} $<$<BOOL:${UNIX}>:lib5>)

Related

Use CMake generator expression to conditionally link towards list of libraries

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?
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.

how to used cmake link the pthread and CURSES [duplicate]

I'm running RHEL 5.1 and use gcc.
How I tell cmake to add -pthread to compilation and linking?
#Manuel was part way there. You can add the compiler option as well, like this:
If you have CMake 3.1.0+, this becomes even easier:
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(my_app PRIVATE Threads::Threads)
If you are using CMake 2.8.12+, you can simplify this to:
find_package(Threads REQUIRED)
if(THREADS_HAVE_PTHREAD_ARG)
target_compile_options(my_app PUBLIC "-pthread")
endif()
if(CMAKE_THREAD_LIBS_INIT)
target_link_libraries(my_app "${CMAKE_THREAD_LIBS_INIT}")
endif()
Older CMake versions may require:
find_package(Threads REQUIRED)
if(THREADS_HAVE_PTHREAD_ARG)
set_property(TARGET my_app PROPERTY COMPILE_OPTIONS "-pthread")
set_property(TARGET my_app PROPERTY INTERFACE_COMPILE_OPTIONS "-pthread")
endif()
if(CMAKE_THREAD_LIBS_INIT)
target_link_libraries(my_app "${CMAKE_THREAD_LIBS_INIT}")
endif()
If you want to use one of the first two methods with CMake 3.1+, you will need set(THREADS_PREFER_PTHREAD_FLAG ON) there too.
The following should be clean (using find_package) and work (the find module is called FindThreads):
cmake_minimum_required (VERSION 2.6)
find_package (Threads)
add_executable (myapp main.cpp ...)
target_link_libraries (myapp ${CMAKE_THREAD_LIBS_INIT})
Here is the right anwser:
ADD_EXECUTABLE(your_executable ${source_files})
TARGET_LINK_LIBRARIES( your_executable
pthread
)
equivalent to
-lpthread
target_compile_options solution above is wrong, it won't link the library.
Use:
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -pthread")
OR
target_link_libraries(XXX PUBLIC pthread)
OR
set_target_properties(XXX PROPERTIES LINK_LIBRARIES -pthread)

cmake does non link ncurses

I am a total noob concerning cmake. My CMakeLists is really basic:
cmake_minimum_required(VERSION 2.4.6)
#set the default path for built executables to the "bin" directory
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#set the default path for built libraries to the "lib" directory
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
#For the Curses library to load:
SET(CURSES_USE_NCURSES TRUE)
include_directories(
"src/"
)
add_subdirectory(src)
when I make the linker does not find the ncurses commands and in the verbose mode of make I see that the compiler did not add the -lncurses. What do I have to add to the CMakeLists to make it work?
For the super noob, remember target_link_libraries() needs to be below add_executable():
cmake_minimum_required(VERSION 2.8) project(main)
find_package(Curses REQUIRED)
include_directories(${CURSES_INCLUDE_DIR})
add_executable(main main.cpp)
target_link_libraries(main ${CURSES_LIBRARIES})
before use some third party libs, you ought to find it!
in case of ncurses you need to add find_package(Curses REQUIRED) and then use ${CURSES_LIBRARIES} in a call to target_link_libraries() and target_include_directories(... ${CURSES_INCLUDE_DIR}).

Remove specific file from cmake build

I have a project in which i have essentially two main methods. One for testing and one for, well, running the code.
Normally you would create submodules, but this is not an option.
file(GLOB sources "*.cpp")
file(GLOB headers "*.h")
add_executable(testing ${sources} ${headers})
add_executable(main ${sources} ${headers})
So testing should compile all sources except for main.cpp.
Main should compile everything but testing.cpp.
The normal way would probably be to create a library from all the sources except main.cpp and testing.cpp, then link this to each executable. However, I guess you mean you can't do that when you say you can't create submodules.
Instead, you can use the list(REMOVE_ITEM ...) command:
file(GLOB sources "*.cpp")
file(GLOB headers "*.h")
set(testing_sources ${sources})
list(REMOVE_ITEM testing_sources ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
list(REMOVE_ITEM sources ${CMAKE_CURRENT_SOURCE_DIR}/testing.cpp)
add_executable(main ${sources} ${headers})
add_executable(testing ${testing_sources} ${headers})

CMake: Linking multiple libraries to two executables in one command

I've got two executables both of which need to be linked to N libraries which are the same:
add_executable(MyExe1 main1.cpp)
add_executable(MyExe2 main2.cpp)
target_link_libraries(MyExe1 lib1 lib2 lib3 ... libN)
target_link_libraries(MyExe2 lib1 lib2 lib3 ... libN)
So I have to write target_link_libraries twice; once for MyExe1 and once for MyExe2. Is there any way to shorten the way some common libraries are linked to two different executables? I am wondering if it's possible to link lib1 ... libN libraries to both MyExe1 and MyExe2 in one command to avoid redundancy and make the CMake file cleaner.
You can use the set command to set a variable from a list of arguments:
add_executable(MyExe1 main1.cpp)
add_executable(MyExe2 main2.cpp)
set(LIBS lib1 lib2 lib3 ... libN)
target_link_libraries(MyExe1 ${LIBS})
target_link_libraries(MyExe2 ${LIBS})