CMake add a library which is a group of other libraries - cmake

I have a core library which branches off into several other libraries. In CMakeLists.txt it looks a bit like this
ADD_LIBRARY (core ...)
ADD_LIBRARY (branch1 ...)
ADD_LIBRARY (branch2 ...)
...
TARGET_LINK_LIBRARIES (branch1 core)
TARGET_LINK_LIBRARIES (branch2 core)
...
I have some executables which may depend on any or all of the branches. For those that depend on all the branches, instead of writing
ADD_EXECUTABLE (foo ...)
TARGET_LINK_LIBRARIES (foo branch1 branch2 ...)
I tried
ADD_LIBRARY (all-branches)
TARGET_LINK_LIBRARIES (all-branches branch1 branch2 ...)
then
TARGET_LINK_LIBRARIES (foo all-branches)
This works but CMake spits out a warning.
You have called ADD_LIBRARY for library all-branches without any source files. This typically indicates a problem with your CMakeLists.txt file
I understand the message, but it's not an error. What does CMake think is an acceptable way to build a meta-library like this?

I added a new type of library, the INTERFACE library to the upcoming CMake 3.0.0 release. That is designed as the solution to this problem:
http://www.cmake.org/cmake/help/git-master/manual/cmake-buildsystem.7.html#interface-libraries
add_library(all_branches INTERFACE)
target_link_libraries(all_branches INTERFACE branch1 branch2)
add_executable(myexe ...)
target_link_libraries(myexe all_branches)

In CMAKE the add_executable and add_library are very similar. They just tell to CMAKE that it should create a MAKE instruction for a library or executable based on the list of src files that you provide after the name of the library/executable and options (such as SHARED, etc).
What you can do is to add the names of your libs that you want to link in a name variable that you increase such as
SET(TARGET_LIBS ${TARGET_LIBS} myFirstLib)
SET(TARGET_LIBS ${TARGET_LIBS} myNextLib)
and then simply:
target_link_libraries(myExe ${TARGET_LIBS})
In this way you can easily define groups of libraries that may be needed for different sub projects without creating a meta-lib.

Related

CMake build and install shared library from subdirectory before building main directory

Here is my source code structure:
cd my_git_repo/
CMakeLists.txt
src/
main.cpp
mylibrary/
a.hpp
b.hpp
a.cpp
b.cpp
CMakeLists.txt
Root CMakeLists.txt:
cmake_minimum_required(VERSION 3.9)
project(myexe CXX)
add_subdirectory(src/mylibrary)
find_library(mylib NAMES mylibrary.so PATHS "./src/mylibrary/mylibrary.so")
add_executable(myexe src/main.cpp)
target_link_libraries(myexe ${mylib})
mylibrary/CMakeLists.txt is very simple. It builds a shared library and installs them.
Ideally, mylibrary target should be built and installed before myexe is built. But this doesn't happen. mylibrary is built followed by myexe. Installation happens later. Because of this, find_library fails. pkg_check_modules() works for other shared libraries but fails here because of the same reason.
I appreciate your help.
Edit:
This question differs from the duplicate because the answers posted to that question seem to be statically linking the library target_link_libraries(game engine). I want to dynamically link the .so library.
The idea in CMake is to build modules and then link them together.
You haven't shared the CMakeLists.txt for my library, so we cannot tell what it is doing. However, assuming that it is something like:
ADD_LIBRARY(mylibrary
file1.cpp
file2.cpp
)
Since you specified that you want mylibrary to always be linked as shared, you need to tell CMake that as well by either setting BUILD_SHARED_LIBS TO ON or by specifying SHARED in add_library:
ADD_LIBRARY(mylibrary SHARED
file1.cpp
file2.cpp
)
This is your library module. We will keep it simple for now and not worry about packing the library archive and installation here.
Now, back to your main CMakeLists.txt and how to make myexe consume it. Since you have already add_subdirectory(src/mylibrary), CMake knows about mylibrary. So simply link it using the module name. There is no need to find_library as you have already defined the module.
add_executable(myexe src/main.cpp)
target_link_libraries(myexe mylibrary)
This should suffice.
Do note, however, this is a very basic example to explain to you how CMake is designed to work. If you aren't building the library, and it is already installed, you would call find_library. Modern CMake is a bit more sophisticated and uses generator expressions, so be sure to read up on that as you progress to more complex projects.

Including headers in Visual Studio project via TARGET_INCLUDE_DIRECTORIES? [duplicate]

I had a project which uses CMake as build tool and made a simple template for me and my collegues to use. As I searched for best and easy to use practices online, I've came across different approaches to make a library.
In this template, I've listed header files and source files in two seperate variables, and I'm not passing the headers to add_library command - just sources. And then I use set_target_properties with PUBLIC_HEADER variable to give the header-file list.
So far it seems to work, but I wonder if I'm making thing unnecessarily complex. Some people online give header files to add_library command as well and doesn't even use set_target_properties and such.
In short:
should we include header files to add_library or should we not (as a best practice)? And impacts of the two usage.
what is purpose being served by adding headers in the add_library/add_executable? As they seem working even without it (seems forward declaration and symbols only). confirm on understanding please.
(Here is the template I'm talking about:)
cmake_minimum_required(VERSION 3.1.0)
project(lae CXX C)
set(CMAKE_CXX_STANDARD 14)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
set(SOURCE_FILES
...
)
set(HEADER_FILES
...
)
set( PRIVATE_HEADER_FILES
...
)
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} )
set( REQUIRED_LIBRARIES
...
)
target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBRARIES} )
SET_TARGET_PROPERTIES(
${PROJECT_NAME}
PROPERTIES
FRAMEWORK ON
SOVERSION 0
VERSION 0.1.0
PUBLIC_HEADER "${HEADER_FILES}"
PRIVATE_HEADER "${PRIVATE_HEADER_FILES}"
ARCHIVE_OUTPUT_DIRECTORY "lib"
LIBRARY_OUTPUT_DIRECTORY "lib"
OUTPUT_NAME ${PROJECT_NAME}
)
In our projects we use a "simple" way of yours - add_library with both headers and sources.
If you add only sources, then you won't see headers in IDE-generated project.
However, when installing, we have to do it like that, using two install commands:
install(TARGETS library_name
LIBRARY DESTINATION lib)
install(FILES ${PUBLIC_HEADERS}
DESTINATION include/library_name)
If you want to do it as a single command, you can use set_target_properties with PUBLIC_HEADER, as you suggested.
Then, this kind of install is possible:
install(TARGETS library_name
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include/library_name)
Choose the one you like the most and stick to it.

CMake add_custom_command with target_link_libraries

For a number of reasons I have to manually generate a static library through a custom command.
However, it seems that the custom command is only executed when a target specifically requests its output files.
If I try to link the generated static library with target_link_libraries, CMake complains that it cannot find a rule to generate it.
# Building library on the fly
add_custom_command(OUTPUT mylib.a
COMMAND ...
)
add_executable(myexe main.cpp)
target_link_libraries(myexe mylib.a) # Fails miserably
I imagine I have to insert a target or dependency somehow between the add_custom_command call and the target_link_libraries one, but I cannot understand how to do so correctly.
For preserve dependency between executable and library file, you need to use full path to the library file when link with it:
target_link_libraries(my_exe ${CMAKE_CURRENT_BINARY_DIR}/mylib.a)
When use relative path, CMake expects library to be found by the linker (according to its rules), so CMake cannot adjust dependency with the library file in that case..
I've had to do this to invoke MATLAB's RTW to build DLLs for me. The function I used was add_custom_target.
add_custom_target(Name [ALL] [command1 [args1...]]
[COMMAND command2 [args2...] ...]
[DEPENDS depend depend depend ... ]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS]
[SOURCES src1 [src2...]])
For you it may look like this:
add_custom_target(MyLib ALL
<Put your command here>
COMMENT "Building MyLib"
)
add_executable(MyExe main.cpp)
target_link_libraries(MyExe MyLib)
If that doesn't work I've heard that you can use add_library() to create a dummy library. Then, use set_target_properties() to create an INTERFACE property for it.
Refences:
add_custom_target

Why add header files into ADD_LIBRARY/ADD_EXECUTABLE command in CMake

I had a project which uses CMake as build tool and made a simple template for me and my collegues to use. As I searched for best and easy to use practices online, I've came across different approaches to make a library.
In this template, I've listed header files and source files in two seperate variables, and I'm not passing the headers to add_library command - just sources. And then I use set_target_properties with PUBLIC_HEADER variable to give the header-file list.
So far it seems to work, but I wonder if I'm making thing unnecessarily complex. Some people online give header files to add_library command as well and doesn't even use set_target_properties and such.
In short:
should we include header files to add_library or should we not (as a best practice)? And impacts of the two usage.
what is purpose being served by adding headers in the add_library/add_executable? As they seem working even without it (seems forward declaration and symbols only). confirm on understanding please.
(Here is the template I'm talking about:)
cmake_minimum_required(VERSION 3.1.0)
project(lae CXX C)
set(CMAKE_CXX_STANDARD 14)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
set(SOURCE_FILES
...
)
set(HEADER_FILES
...
)
set( PRIVATE_HEADER_FILES
...
)
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} )
set( REQUIRED_LIBRARIES
...
)
target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBRARIES} )
SET_TARGET_PROPERTIES(
${PROJECT_NAME}
PROPERTIES
FRAMEWORK ON
SOVERSION 0
VERSION 0.1.0
PUBLIC_HEADER "${HEADER_FILES}"
PRIVATE_HEADER "${PRIVATE_HEADER_FILES}"
ARCHIVE_OUTPUT_DIRECTORY "lib"
LIBRARY_OUTPUT_DIRECTORY "lib"
OUTPUT_NAME ${PROJECT_NAME}
)
In our projects we use a "simple" way of yours - add_library with both headers and sources.
If you add only sources, then you won't see headers in IDE-generated project.
However, when installing, we have to do it like that, using two install commands:
install(TARGETS library_name
LIBRARY DESTINATION lib)
install(FILES ${PUBLIC_HEADERS}
DESTINATION include/library_name)
If you want to do it as a single command, you can use set_target_properties with PUBLIC_HEADER, as you suggested.
Then, this kind of install is possible:
install(TARGETS library_name
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include/library_name)
Choose the one you like the most and stick to it.

CMake: Link a library to library

I have a problem with cmake. I have, lets say, CMakeLists1 which has a subdirectory where CMakeLists2 is.
In CMakeLists2 my target is a static library. And I want to link it to external library.
I've made it just like that:
link_directories ("path_to_library")
add_library (project2 ${sources})
target_link_libraries (project2 "name_of_external_lib")
Then, I want to use a class from this project2 in my project1. I've made it that way:
add_executable (project1 ${sources})
target_link_libraries (project1 project2)
But that doesn't work at all. First of all, project2 didn't link to external library. Just for checking, I've added this library through vs10 project properties, and the sizes were different. And the second thing, somehow project1 sees that external library (it is in library dependencies of this project) and of course can't find it.
What is the problem?
I think it's CMake's default behavior to not link project2 to the external library,
but to link both libraries to the executable.
From the book "Mastering CMake".
Since static libraries do not link to the libraries on which they depend, it is
important for CMake to keep track of the libraries so they can be specified on the
link line of the executable being created.
You could try to use an absolute path in your CMakeLists2:
add_library (project2 ${sources})
target_link_libraries (project2 "path to ext lib"/"name of ext lib")
or you could add
link_directories ("path_to_library")
to the CMakeLists file of project1.
If you really want to do something like in Visual Studio, you could probably use the command given in this answer to build a custom_command in CMake.
It probably would look something like this (I didn't test it).
set(EXT_LIB "path_to_library/name_of_external_lib")
set(BIG_LIB "path_to_big_lib/name_of_big_lib")
add_library (project2 ${sources})
get_property(PROJ2_LOC TARGET project2 PROPERTY LOCATION)
add_custom_command(OUTPUT ${BIG_LIB}
DEPENDS ${EXT_LIB} project2
COMMAND "lib.exe /OUT:${BIG_LIB} ${EXT_LIB} ${PROJ2_LOC} )
Then you could link your executable with ${BIG_LIB}.
Some things you have to consider:
Maybe you have to use LOCATION_CONFIG (CMake docs, I found the get_property command in this answer )
link.exe has to be in your path
watch the scope of the BIG_LIB variable if you want to use it in an other CMakeLists.txt
I'm guessing the trouble will likely be that *name_of_external_lib* is not correct so it can't find it.
I would go with:
find_library(
LIB_I_NEED name_of_external_lib
HINTS "path_to_library"
)
if(${LIB_I_NEED} STREQUAL "LIB_I_NEED-NOTFOUND")
message(FATAL_ERROR "Couldn't find the 'external_lib' library)
endif()
message(STATUS "Found 'external_lib' at: ${LIB_I_NEED}")
add_library (project2 ${sources})
target_link_libraries (project2 ${LIB_I_NEED})
If that doesn't help, have a quick read of the example in the cmake docs:
http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:target_link_libraries
One thing it mentions in there is:
While one repetition is usually sufficient, pathological object file
and symbol arrangements can require more. One may handle such cases by
manually repeating the component in the last target_link_libraries
call
So I would say the other thing to try might be in project2:
set(PROJECT_2_LIBS project2 "name_of_external_lib" PARENT_SCOPE)
then in the exe:
target_link_libraries (project1 ${PROJECT_2_LIBS})
That will have the 'external_lib' linkage repeated in the two places and give you more chance of it working ;)