cmake the following imported targets are referenced, but are missing - c++

I have a repository with two libraries (liba and libb) whereas liba
depends on libb. They are part of a single repository and are built using a single cmake "context". The file structure is shown below:
├── CMakeLists.txt
├── liba
│ ├── CMakeLists.txt
│ ├── internal
│ │ └── private.hh
│ ├── module.cc
│ ├── module.hh
└── libb
├── CMakeLists.txt
├── other.cc
└── other.hh
Everything compiles and installs without any issues. Although, if I try to create a new project that depends on liba. Like so:
cmake_minimum_required(VERSION 3.5)
find_package(Threads REQUIRED)
find_package(OpenCV REQUIRED)
find_package(liba REQUIRED)
add_executable(exec exec.cc)
target_link_libraries(exec PRIVATE is::liba)
I get the following error:
CMake Error at CMakeLists.txt:5 (find_package):
Found package configuration file:
/home/hodor/is-sdk/lib/cmake/liba/libaConfig.cmake
but it set liba_FOUND to FALSE so package "liba" is considered to be NOT
FOUND. Reason given by package:
The following imported targets are referenced, but are missing: is::libb
What I am missing here? Repository link for context
CMakeLists that generates liba:
cmake_minimum_required(VERSION 3.5)
include(GNUInstallDirs)
find_package(OpenCV REQUIRED core)
find_package(Threads REQUIRED)
list(APPEND liba_public_headers
"module.hh"
)
list(APPEND liba_private_headers
"internal/private.hh"
)
list(APPEND liba_sources
"module.cc"
${liba_public_headers}
${liba_private_headers}
)
add_library(liba ${liba_sources})
target_include_directories(
liba
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}> # for headers when building
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> # for generated files in build mode
$<INSTALL_INTERFACE:include/is/liba> # for clients in install mode
PRIVATE
${OpenCV_INCLUDE_DIRS}
)
target_link_libraries(liba
PRIVATE
is::libb
${OpenCV_LIBRARIES}
Threads::Threads
)
set_property(TARGET liba PROPERTY CXX_STANDARD 11)
install(
TARGETS liba EXPORT libaTargets
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
install(FILES ${liba_public_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/is/liba)
install(
EXPORT libaTargets
FILE libaConfig.cmake
NAMESPACE is::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liba
)
CMakeLists that generates libb:
cmake_minimum_required(VERSION 3.5)
include(GNUInstallDirs)
list(APPEND libb_public_headers
"other.hh"
)
list(APPEND libb_sources
"other.cc"
${libb_public_headers}
)
add_library(libb ${libb_sources})
target_include_directories(
libb
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}> # for headers when building
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> # for generated files in build mode
$<INSTALL_INTERFACE:include/is/libb> # for clients in install mode
)
install(
TARGETS libb EXPORT libbTargets
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
install(FILES ${libb_public_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/is/libb)
install(
EXPORT libbTargets
FILE libbConfig.cmake
NAMESPACE is::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libb
)
add_library(is::libb ALIAS libb)
Top level CMakeLists that includes liba and libb:
cmake_minimum_required(VERSION 3.5)
add_subdirectory(liba)
add_subdirectory(libb)

After watching C++Now 2017: Daniel Pfeifer “Effective CMake"
I now realized what was missing in my configuration. As mentioned by #Tsyvarev the problem was about libaConfig.cmake.
When exporting a library with dependencies you should export mylibraryTargets.cmake, like so:
install(
EXPORT libaTargets
FILE libaTargets.cmake
NAMESPACE is::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liba
)
And then manually (a bit disappointed here I have to say) write a mylibraryConfig.cmake with all the dependencies like so:
include(CMakeFindDependencyMacro)
find_dependency(libb)
find_dependency(OpenCV)
find_dependency(Threads)
include("${CMAKE_CURRENT_LIST_DIR}/libaTargets.cmake")

Related

CMake building library and executable once and linking it

I'm trying to build two projects using cmake at same-time.
My folder structure is as follows:
project
├── CMakeLists.txt
├── build
├── out
├── lib
├── yanthra_engine
│  ├── CMakeLists.txt
│   └── ...
└───sandbox
├── CMakeLists.txt
└── ...
main CmakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
project(yanthra_console VERSION 0.1 DESCRIPTION "A 3d Game Engine.")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fexceptions")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING "Build type selections" FORCE)
add_subdirectory(yanthra_engine)
add_subdirectory(sandbox)
yanthra_engine/CMakeLists.txt
set(THIRD_PARTY_DIR "../../../third-party")
set(MAIN_SOURCE_DIR "../../main/src")
include_directories(${THIRD_PARTY_DIR}/SDL/include)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../lib )
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../lib)
file(GLOB_RECURSE CPP_HEADERS ${MAIN_SOURCE_DIR}/*.hpp)
file(GLOB_RECURSE CPP_SOURCES ${MAIN_SOURCE_DIR}/*.cpp)
add_library(
yanthra
SHARED
${CPP_HEADERS}
${CPP_SOURCES}
)
set (CMAKE_SHARED_LINKER_FLAGS "-F../yanthra_engine/Frameworks -framework SDL2 -framework OpenGL")
sandbox/CMakeLists.txt
set(THIRD_PARTY_DIR "../../main")
set(MAIN_SOURCE_DIR "./src")
include_directories(${THIRD_PARTY_DIR}/include)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../out)
file(GLOB_RECURSE CPP_HEADERS ${MAIN_SOURCE_DIR}/includes/*.h)
file(GLOB_RECURSE CPP_SOURCES ${MAIN_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE LIB ${MAIN_SOURCE_DIR}/../lib/*.dylib)
add_executable(
yanthra_sandbox
${CPP_HEADERS}
${CPP_SOURCES}
)
set_target_properties(
yanthra_sandbox
PROPERTIES
LINK_FLAGS
"-F../yanthra_engine/Frameworks -framework SDL2 -framework OpenGL"
)
target_link_libraries(yanthra_sandbox PRIVATE ${LIB})
I would like to know if I'm generating library file in each build mode, how will I link it with it's corresponding executable, given the fact that each mode builds its output to to its own folder i.e for library its lib/Debug (for debug mode) and for executable its out/Debug.
You don't seem to link the link the yanthra target. You should do this though, since this will automatically choose the library compiled with the current configuration.
sandbox/CMakeLists.txt
...
target_link_libraries(yanthra_sandbox PRIVATE yanthra ${LIB})
...
As for importing the other libs: It would be preferrable to use find_library. This should automatically set the link options and make adding them for yanthra_sandbox unnecessary.
yanthra_engine/CMakeLists.txt
...
list(APPEND CMAKE_FRAMEWORK_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Frameworks")
find_library(SDL2_LIB SDL2 REQUIRED)
find_library(OPEN_GL_LIB OpenGL REQUIRED)
target_link_library(yanthra PUBLIC "${SDL2_LIB}" "${OPEN_GL_LIB}")
This should allow you to remove the compiler flags from both targets. If there are no dependencies in the lib directory you could also remove the search for the libraries on the file system/

Create and compile a base class to use in other c++ projects (ROS)

I would like to compile a project so I would be able to use it as a library in other projects.
To be more precise it is a base class that I would like many other project I use to inherit from.
├── include
│ ├── MyBase.hpp
│ ├── ...
│ └── Utils.hpp
└── src
├── MyBase.cpp
├── ...
└── Utils.cpp
After I followed a tutorial and adjusted My CMakeLists.txt file and now it looks like this.
cmake_minimum_required(VERSION 2.8.3)
project(my_commons)
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
find_package(catkin REQUIRED COMPONENTS
roscpp
tf
)
catkin_package(CATKIN_DEPENDS tf
INCLUDE_DIRS include)
include_directories(
${catkin_INCLUDE_DIRS}
include/
)
###########
## Build ##
###########
add_library(my_commons SHARED
src/MyBase.cpp
src/Utils.cpp
)
## Specify libraries to link a library or executable target against
set_target_properties(my_commons PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(my_commons
${catkin_LIBRARIES}
${roscpp_LIBRARIES}
)
install(DIRECTORY include/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.hpp"
PATTERN ".svn" EXCLUDE)
# Install library
install(TARGETS my_commons
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
It compiles fine, but I am not sure what needs to be added in other projects' CMakeFiles and how to use it there.
Thank you very much in advance.
In the CMakeLists.txt file you included above, you need to add a libraries line in the catkin_package as follows:
catkin_package(
INCLUDE_DIRS include
LIBRARIES ${PROJECT_NAME}
CATKIN_DEPENDS tf
)
Then in other nodes, you would include the package in packages.xml:
<build_depend>my_commons</build_depend>
And in the CMakeLists.txt file you would need to find the my_commons package and link it against a library or executable you are trying to build by doing the following:
find_package(catkin REQUIRED COMPONENTS
roscpp
my_commons
)
catkin_package(
INCLUDE_DIRS include
LIBRARIES ${PROJECT_NAME}
CATKIN_DEPENDS my_commons
)
target_link_libraries(${PROJECT_NAME}
${my_commons_LIBRARIES}
)

Build of multiple subprojects with library that has external dependency

I'm struggling with an project that includes CMake (version 3.11) and subdirectories. It includes ITK as an external library.
I want to create library that I can use in the different subdirectories like MyApp to build multiple applications that are based on MyLib and every change in MyLib is updated in the other applications. The MyLib is a header-only templated library. In addition this kind of libraries do not get a own project in VisualStudio.
My questions are:
What is the correct way of using CMake in this scenario? I have searched and tried some example but was not successful. Ideally I can build applications depending on the MyLib independently. The top CMakeLists.txt may not pull in the includes from the library. This should be done by the applications.
What would change if the MyLib becomes a non-header-only library? In the future I may add non templated classes.
Bonus question:
How can I add the header-only library to VisualStudio? This is more a question for convencience.
Any help is appreciated and I can provide more details if necessary.
The source environment looks like this:
ProjectDirectory
- CMakeLists.txt
-- MyLib
- CMakeLists.txt
-- include
- File1.h (template header)
- File1.hxx (template body)
-- src
- (empty for now)
-- MyApp
- CMakeLists.txt
- AppFile1.cxx (File containing main function)
This is an out-of-source-build project. Ideally the compiled libraries and application are put in a directory like this (on Windows):
└── bin
├── Debug
│ ├── MyApp.exe
│ └── MyLib.lib
└── Release
├── MyApp.exe
└── MyLib.lib
ProjectDirectory CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(project_name)
# Setup build locations.
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
endif()
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
endif()
if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
endif()
add_subdirectory(MyLib)
add_subdirectory(MyApp)
MyLib CMakeLists.txt:
find_package(ITK REQUIRED
COMPONENTS RTK ITKImageIO)
include(${ITK_USE_FILE})
set(HDRS
${CMAKE_CURRENT_SOURCE_DIR}/include/File1.h
${CMAKE_CURRENT_SOURCE_DIR}/include/File1.hxx
)
add_library(MyLib ${HDRS})
target_include_directories(MyLib
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE
src)
target_link_libraries(MyLib
PUBLIC ${ITK_LIBRARIES})
export(TARGETS MyLib FILE MyLibConfig.cmake)
MyApp CMakeLists.txt
find_package(ITK REQUIRED
COMPONENTS RTK ITKRegistrationMethodsv4 ITKTransformIO ITKImageIO)
include(${ITK_USE_FILE})
set(SRCS
AppFile1.cxx)
add_executable(MyApp ${SRCS})
include_directories(${CMAKE_SOURCE_DIR}/MyLib/include)
target_link_libraries(MyApp
${ITK_LIBRARIES}
MyLib)
Edit1: Remove the project(X) from MyLib and MyApp CMakeLists.txt and change target to MyLib.
You can have an empty project, just create a custom target:
add_custom_target(MyLib SOURCES ${CMAKE_MYLIB_SRC} ${CMAKE_MYLIB_HDR})
As your code is header only, any depend target will see the changes in the files and would be recompiled. There is nothing to do on top of this. You don't have to create the target, although for your third question, that's the answer.
But if ITK is only your dependency, now that you have a target, you can add PUBLIC properties on it, like dependent libraries that need to be linked against it because of your library.
In that case, the code for them needs to add:
target_link_library(${NEWTARGET} PRIVATE MyLib) # PUBLIC/PRIVATE has to be tailored
That's the answer for question 1.
If your library becomes non-header only, just change the add_custom_target call.

How do I Install bundled interface dependencies with modern CMake?

What is the proper way to install bundled interface dependencies in Modern CMake?
I have a library MyLib that has an interface dependency on libDep (MyLib.hpp contains #include <libDep.h>). Anything that depends on MyLib also transitively depends on libDep.
libDep is a single header taken from a gist so I have included it part of the source-tree of MyLib
$ tree
.
├── CMake
│   ├── MyLibConfig.cmake.in
│   └── modules
│   └── FindlibDep.cmake
├── CMakeLists.txt
├── include
│   └── MyLib
│   └── MyLib.hpp
├── src
│   └── MyLib.cpp
└── third_party
└── libDep
└── libDep.h
I would like to install libDep with myLib, in with a path like include/MyLib/third_party/libDep.
Here is the CMakeLists for MyLib
cmake_minimum_required(VERSION 3.3.0)
Project(MyLib
DESCRIPTION "Library with bundled interface dependency"
LANGUAGES CXX)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/modules)
# Find LibDep dependency
find_package(libDep REQUIRED)
# MyLib library
add_library(MyLib STATIC
${CMAKE_SOURCE_DIR}/src/MyLib.cpp)
target_include_directories(MyLib
PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/MyLib>
PUBLIC $<INSTALL_INTERFACE:include/MyLib>)
target_link_libraries(MyLib
INTERFACE libDep)
MyLib locates libDep with FindlibDep.cmake located in CMAKE_MODULE_PATH
find_path(LibDep_INCLUDE_DIR
NAMES LibDep.hpp
PATHS third_party/libDep)
PATH_SUFFIXES Mylib/third_party/libDep)
mark_as_advanced(LibDep_FOUND LibDep_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibDep
REQUIRED_VARS
LibDep_INCLUDE_DIR
)
if(LibDep_FOUND)
set(LibDep_INCLUDE_DIRS ${LibDep_INCLUDE_DIR})
endif()
if(LibDep_FOUND AND NOT TARGET MyLib::LibDep)
add_library(MyLib::LibDep INTERFACE IMPORTED)
set_target_properties(MyLib::LibDep PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${LibDep_INCLUDE_DIR})
endif()
I install MyLib like
install(TARGETS MyLib
EXPORT MyLibTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(MyLibConfigVersion.cmake)
install(EXPORT MyLibTargets
FILE MyLibTargets.cmake
NAMESPACE MyLib::
DESTINATION lib/cmake/MyLib)
configure_file(CMake/MyLibConfig.cmake.in MyLibConfig.cmake #ONLY)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/MyLibConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/MyLibConfigVersion.cmake"
DESTINATION lib/cmake/MyLib)
install(DIRECTORY ${MyLib_PUBLIC_INCLUDE_DIR}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
# Package with CPack
include(InstallRequiredSystemLibraries)
include(CPack)
MyLibConfig.cmake.in declares a dependency on libDep
include(CMakeFindDependencyMacro)
# Dependencies
add_library(libDep REQUIRED)
# Add the targets file
include("${CMAKE_CURRENT_LIST_DIR}/MyLibTargets.cmake")
libDep is installed into MyLib's tree with
install(DIRECTORY ${libDep_INCLUDE_DIRS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/MyLib/third_party)
and I copy the find module with
install(FILES
${CMAKE_MODULE_PATH}/FindlibDep.cmake
DESTINATION lib/cmake/MyLib)
Unfortunately users of MyLib don't see FindlibDep.cmake by default
$ cmake ..
CMake Error at /usr/share/cmake-3.10/Modules/CMakeFindDependencyMacro.cmake:48 (find_package):
By not providing "FindlibDep.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "libDep", but
CMake did not find one.
Could not find a package configuration file provided by "libDep" with any
of the following names:
libDepConfig.cmake
libDep-config.cmake
Add the installation prefix of "libDep" to CMAKE_PREFIX_PATH or set
"libDep_DIR" to a directory containing one of the above files. If "libDep"
provides a separate development package or SDK, be sure it has been
installed.
Call Stack (most recent call first):
/usr/local/lib/cmake/MyLib/MyLibConfig.cmake:5 (find_dependency)
CMakeLists.txt:9 (find_package)
-- Configuring incomplete, errors occurred!
The user can manually locate FindlibDep.cmake and add it to their CMAKE_MODULE_PATH but that shouldn't be required.
A reproduction of this issue is available on GitHub.
You need to use the PROJECT_ variable for the source dir instead of the CMAKE_ variable:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake/modules)
PROJECT_SOURCE_DIR gets the source dir from the most recently executed project() directive (in this case, your library).
You should also be adding your current CMAKE_MODULE_PATH to the new path, as shown above.

CMake - dependencies (headers) between apps/libraries in same project

I have the following project structure:
CMakeLists.txt
lib1/CMakeLists.txt and all cpp and header files of the lib
lib2/CMakeLists.txt and all cpp and header files of the lib
app/CMakeLists.txt and all cpp and header files of the app
The main CMakeLists.txt looks like:
PROJECT( ${PROJECT_NAME} )
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(app)
The lib1/CMakeLists.txt looks eg like (stripped):
SET(SOURCE
file.cpp
)
SET(HEADERS
some_lib_header.h
)
add_library( lib1 ${SOURCE} ${HEADERS} )
and the one for the app looks the same except of ADD_EXECUTABLE:
SET(SOURCE
main.cpp
)
SET(HEADERS
some_header.h
)
add_library( lib1 ${SOURCE} ${HEADERS} )
ADD_EXECUTABLE( app ${SOURCE} ${HEADERS} )
I found the setup working well this way because out of this, I can generate one Visual Studio solution file which contains all those three projects. But my problem is that my app includes header files of lib1 (and also of lib2, which depends on lib1). When I do
$mkdir build
$cd build
$cmake -C ..\myproject
it generates out-of-source VS .sln file as I want it, but the app doesn't compile because it can't find the header files of lib1 (obviously).
Now I read and tried many things, like TARGET_LINK_LIBRARIES( app lib1 ) (which got the app to link with the lib1, but not solve the header include issue), and things like add_subdirectory( ../lib1 ) in various variants in the CMakeLists.txt of app (which all throwed errors that I couldn't fix), and also find_package (which I guess is the wrong approach).
So how can I solve this (I guess simple...) problem?
Here's one possible solution:
Root CMakeLists.txt:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(${PROJECT_NAME})
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(app)
lib1/CMakeLists.txt:
project(Lib1)
add_library(lib1 lib1.cpp lib1.h)
lib2/CMakeLists.txt:
project(Lib2)
add_library(lib2 lib2.cpp lib2.h)
# Add /lib1 to #include search path
include_directories(${Lib1_SOURCE_DIR})
# Specify lib2's dependency on lib1
target_link_libraries(lib2 lib1)
app/CMakeLists.txt:
project(App)
add_executable(app main.cpp some_header.h)
# Add /lib1 and /lib2 to #include search path
include_directories(${Lib1_SOURCE_DIR} ${Lib2_SOURCE_DIR})
# Specify app's dependency on lib2.
# lib2's dependency on lib1 is automatically added.
target_link_libraries(app lib2)
There are plenty of different ways to achieve the same end result here. For a relatively small project, I'd probably just use a single CMakeLists.txt:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Test)
add_library(lib1 lib1/lib1.cpp lib1/lib1.h)
add_library(lib2 lib2/lib2.cpp lib2/lib2.h)
add_executable(app app/main.cpp app/some_header.h)
include_directories(${CMAKE_SOURCE_DIR}/lib1 ${CMAKE_SOURCE_DIR}/lib2)
target_link_libraries(lib2 lib1)
target_link_libraries(app lib2)
For further info on the relevant commands and their rationale, run:
cmake --help-command add_subdirectory
cmake --help-command include_directories
cmake --help-command target_link_libraries
Project
CMakeLists.txt
\-lib1
CMakeLists.txt
\- include \ lib1
\- src
\-lib2
CMakeLists.txt
\- include \ lib2
\- src
\-app
CMakeLists.txt
\- src
Suppose dependencies as follow:
lib1 ---> lib2 ---> app
\--------------> app
Something like this:
CMakeLists.txt:
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(app)
lib1/CMakeLists.txt:
file(GLOB_RECURSE _HDRS "include/*.hpp")
file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
add_library(lib1 ${_HDRS} ${_SRCS})
#target_link_libraries(lib1)
target_include_directories(lib1 PUBLIC include)
install(TARGETS lib1 DESTINATION lib)
install(FILES ${_HDRS} DESTINATION include/lib1)
lib2/CMakeLists.txt:
file(GLOB_RECURSE _HDRS "include/*.hpp")
file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
add_library(lib2 ${_HDRS} ${_SRCS})
target_link_libraries(lib2 lib1)
target_include_directories(lib2 PUBLIC include)
install(TARGETS lib2 DESTINATION lib)
install(FILES ${_HDRS} DESTINATION include/lib2)
so in lib2/src/file.cpp you could do #include <lib1/header.hpp>
app/CMakeLists.txt:
file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
add_executable(app ${_SRCS})
target_link_libraries(app lib1 lib2)
install(TARGETS app DESTINATION bin)
so in app/src/file.cpp you could do #include <lib1/header.hpp> and #include <lib2/header.hpp>
The magic is target_include_directories which attach the "include" directory to the target, so when linking with it you pull the include directory also ;)