How to set include_directories from a CMakeLists.txt file? - cmake

I seem to be having trouble setting the include path (-I) using the include_directories() command in CMake. My project directory is as follows:
Root
| - CMakeLists.txt
| - libs
| - | - CMakeLists.txt
| - | - inc
| - | - | - // lib specific includes
| - | - src
| - | - | - // lib specific sources
| - proj1
| - | - CMakeLists.txt
| - | - inc
| - | - | - // proj1 specific includes
| - | - src
| - | - | - // proj1 specific sources
The root CMakeLists.txt file looks like so:
project(ROOT)
add_subdirectory(libs)
add_subdirectory(proj1)
The CMakeLists.txt file under libs:
project(lib)
add_library(lib STATIC ${lib_hdrs} ${lib_srcs}) // for conciseness, omitted set()
And lastly, the CMakeLists.txt file under proj1:
project(proj1)
include_directories("${ROOT_SOURCE_DIR}/lib/inc") # <- problem line?
add_executable(proj1 ${proj1_srcs})
target_link_libraries(proj1 lib)
The goal is to create the library from the source and header files in libs, then link against the executable generated under proj1. Proj1 has some files that #include stuff in libs include, so I need to add the directories to be used with -I. Based on the documentation, that's what include_directories() is supposed to do. However despite explicitly setting that and following it with a debug message(${INCLUDE_DIRECTORIES}), the INCLUDE_DIRECTORIES variable is an empty string, and no directories are specified for the include path, so my compilation of proj1 fails.
I've also attempted removing the quotes around ${ROOT_SOURCE_DIR}/inc to see if that helped but no luck.

include_directories() populates a directory property called INCLUDE_DIRECTORIES:
http://www.cmake.org/cmake/help/v2.8.12/cmake.html#prop_dir:INCLUDE_DIRECTORIES
Note that CMake 2.8.11 learned the target_include_directories command, which populates the INCLUDE_DIRECTORIES target property.
http://www.cmake.org/cmake/help/v2.8.12/cmake.html#command:target_include_directories
Note also that you can encode the fact that 'to compile against the headers of the lib target, the include directory lib/inc is needed' into the lib target itself by using target_include_directories with the PUBLIC keyword.
add_library(lib STATIC ${lib_hdrs} ${lib_srcs}) # Why do you list the headers?
target_include_directories(lib PUBLIC "${ROOT_SOURCE_DIR}/lib/inc")
Note also I am assuming you don't install the lib library for others to use. In that case you would need to specify different header directories for the build location and for the installed location.
target_include_directories(lib
PUBLIC
# Headers used from source/build location:
"$<BUILD_INTERFACE:${ROOT_SOURCE_DIR}/lib/inc>"
# Headers used from installed location:
"$<INSTALL_INTERFACE:include>"
)
Anyway, that's only important if you are installing lib for others to use.
After the target_include_directories(lib ...) above you don't need the other include_directories() call. The lib target 'tells' proj1 the include directories it needs to use.
See also target_compile_defintions() and target_compile_options().

Related

How to configure a subdirectory project in CMake in a way that find_package in another one is able to find it?

I am trying to build the netCDF C++ library as a dependency to my project on Windows 10 using MSVC shipped with VS2017 (I think v141 but not sure). Since some of the dependencies I will mention below require CMake > 3.12 I am forced to use CMake that is not shipped with VS2017. The problem is that netCDF C++ requires the netCDF C library (I guess the former is a wrapper for the latter), which in terms depends on the HDF5 library.
All can be found on github as CMake projects:
https://github.com/HDFGroup/hdf5
https://github.com/Unidata/netcdf-c
https://github.com/Unidata/netcdf-cxx4
Currently my project's structure is as follows:
MAIN PROJECT
|
*--- CMakeLists.txt
|
*--- examples (CMake subproject)
| |
| *---CMakeLists.txt
| |
| *--- example1 (CMake subproject, uses my_library)
| |
| *--- example2 (CMake subproject, uses my_library)
|
*--- deps (CMake subproject)
| |
| *--- CMakeLists.txt
| |
| *--- jsoncpp (CMake subproject, git clone)
| |
| *--- ...
| |
| *--- hdf5 (CMake subproject, git clone)
| |
| *--- netcdf-c (CMake subproject, git clone)
| |
| *--- netcdf-cxx4 (CMake subproject, git clone)
|
*--- my_library (CMake subproject, my own library that uses deps)
|
*--- my_binary (CMake subproject, my own executable that uses my_library and deps)
Until I started tinkering with netCDF I didn't have any issues. My deps CMakeLists.txt look like this:
add_subdirectory(sqlite3)
set(JSONCPP_WITH_EXAMPLE OFF CACHE BOOL "Compile JsonCpp example")
set(JSONCPP_WITH_TESTS OFF CACHE BOOL "Compile and (for jsoncpp_check) run JsonCpp test executables")
set(JSONCPP_WITH_POST_BUILD_UNITTEST OFF CACHE BOOL "Automatically run unit-tests as a post build step")
set(BUILD_STATIC_LIBS ON CACHE BOOL "Build jsoncpp_lib as a static library.")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build jsoncpp_lib as a shared library.")
add_subdirectory(jsoncpp)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries")
set(BUILD_CURL_EXE OFF CACHE BOOL "Build curl EXE")
add_definitions("-DCURL_STATICLIB")
if(WIN32)
set(ENABLE_UNICODE OFF CACHE BOOL "Set to ON to use the Unicode version of the Windows API functions")
endif()
add_subdirectory(curl)
add_subdirectory(hdf5)
add_subdirectory(netcdf-c) # ISSUE with find_package and hdf5
add_subdirectory(netcdf-cxx4)
The netcdf-c subproject has the following lines, which cause a problem for me:
IF(MSVC)
SET(SEARCH_PACKAGE_NAME ${HDF5_PACKAGE_NAME})
FIND_PACKAGE(HDF5 NAMES ${SEARCH_PACKAGE_NAME} COMPONENTS C HL CONFIG REQUIRED ${NC_HDF5_LINK_TYPE})
ELSE(MSVC)
FIND_PACKAGE(HDF5 COMPONENTS C HL REQUIRED)
ENDIF(MSVC)
From what I saw the same applies to netcdf-cxx4 so solving this can hopefully be applied to it too.
I do not want to touch anything inside the respective dependenies' folders (I plan on adding those as git submodules later on). Is there a way to instruct the underlying sub-project (just like a did for e.g. JSON++) where to look without installing anything from the project one level up? Possibly a useful note here is that I also don't have any install() calls.

How to add C++REST SDK as a submodule with CMake?

I am trying to build a project with numerous dependencies such as Boost, OpenSSL, and C++ REST SDK. However, it is required that the source code is included in the project workspace and that the library is built from said source code.
The most consistently successful way I have found to achieve this is though the use of git submodule add <URL>, add_subdirectory, target_link_libraries, and some clever projects built for this purpose such as boost-cmake and openssl-cmake.
Take for example the following project structure:
prjct
| include/
| libs/
| | boost-cmake/
| | openssl-cmake/
| | cpprestsdk/
| src/
| tests/
| CMakeLists.txt
For which the top-level CMakeLists.txt would contain:
...
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/boost-cmake)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/openssl-cmake)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/cpprestsdk)
target_link_libraries(${PROJECT_NAME_L}
PUBLIC
Boost::system
Boost::thread
Boost::log
Boost::program_options
Boost::chrono
ssl # OpenSSL::SSL
crypto # OpenSSL::Crypto
cpprestsdk::cpprest
)
...
However, in the case of the cpprestsdk library, I recieve the following error upon running cmake .. from build/:
CMake Error at CMakeLists.txt:55 (add_library):
Target "prjct" links to target "cpprestsdk::cpprest" but the target
was not found. Perhaps a find_package() call is missing for and IMPORTED
target, or an ALIAS target is missing?
How can I link and use the C++ REST SDK within these constraints?

Can I add a library from the folder above?

I can't add my static library to my project.
I have the following project structure:
+ root/
+ CmakeLists.txt // Include all projects
+ Base/
| + foo.cpp
| + CmakeLists.txt
+ App1/
| + app1.cpp
| + CmakeLists.txt // Requires Base lib
+ App2/
| + app2.cpp
| + CmakeLists.txt // Requires Base lib
I try to do it in the following way:
Base CmakeLists.txt:
cmake_minimum_required(VERSION 3.10.2)
add_library(Base STATIC foo.cpp)
App1 CmakeLists.txt:
cmake_minimum_required(VERSION 3.10.2)
project(App1)
add_executable(${CMAKE_PROJECT_NAME} app1.cpp)
include(../Base/CMakeLists.txt)
But I have the following error:
CMake Error at C:/DPA/Base/CMakeLists.txt:3 (add_library):
Cannot find source file:
foo.cpp
How I can properly setup library to include in all projects?
That's not how you use such a directory structure. Instead, in App1/CmakeLists.txt, go with
add_executable(App1 app1.cpp)
target_link_libraries(App1 Base)
This declares that App1 depends on Base and shall be linked against that library. "Linking" means not only passing the correct arguments to your linker, it also propagates include flags and other options to the compiler when building App1 sources.
If you intend to build only parts of your project, you can use an additional argument to add_executable, i.e.
add_executable(App1 EXCLUDE_FROM_ALL app1.cpp)
This way, when you build the default target, App1 won't be part of the build. You can still build it manually/upon request, e.g. when working with makefiles,
make App1
will build the executable App1 and everything that's required for it.

How to add source files in another folder

I'm using cmake to build my project in C++. Assume I have the following directories on my Source folder
Source
|_Dir1
| |_Class.cpp
| |_Class.hpp
|
|_Dir2
|_Main.cpp
In Dir1 there's a class with its header and implementation files (Class.cpp and Class.hpp).
In Dir2 there's the main application which uses the class in Dir1
What is the good way to tell the CMakeLists in Dir2 to build the executable with Dir1/Class.cpp file?
EDIT: To be more specific, I want to define that the source file for Class.cpp has to be used in Dir1's CMakeLists.txt, and not in Dir2's. Doing it the other way feels plain wrong to me and it's hard to use, so if there's a reason they're enforcing me to do this some clarification on the topic would be nice.
What I'm currently doing is hard-coding the Class.cpp file location in Dir2/CMakeLists.txt but that just doesn't scale when I've got a bunch of classes interacting together.
Supposed you have a single CMakeLists.txt file at the Source directory, you'll create two variables using different file() commands
file(GLOB Dir1_Sources RELATIVE "Dir1" "*.cpp")
file(GLOB Dir2_Sources RELATIVE "Dir2" "*.cpp")
and add both sets generated by the file() commands to your target's source list:
add_executable(MyProgram ${Dir1_Sources} ${Dir2_Sources})
Alternatively you can place a CMakeLists.txt file under Dir1 and Dir2 (Main) looking as follows
Source
|
|_ CMakeLists.txt
| > project(MyProgram)
| > cmake_minimum_required(VERSION 3.8)
| > add_subdirectory("Dir1")
| > add_subdirectory("Dir2")
|
|_ Dir1
| |_ CMakeLists.txt
| > file(GLOB Sources "*.cpp")
| > add_library(Dir1 STATIC ${Sources})
|_ Dir2
|_ CMakeLists.txt
> file(GLOB Sources "*.cpp")
> add_executable(MyProgram ${Sources})
> target_link_libraries(MyProgram Dir1)
to add subdirectories as further (static) libraries linked to your main target.

Add a dependency not in a subdirectory using CMake

Let's say there's following directory structure:
root
|
+--projects
| |
| +-test
| |
| +-CMakeFiles.txt
|
+--libs
|
+-testlib
|
+-CMakeFiles.txt
test contains CMakeFiles.txt and testlib also contains CMakeFiles.txt. "test" produces an executable and "testlib" produces a static library.
I want "test" to link with "testlib" without using symlinks and without moving "testlib" library into a subdirectory within "test".
Because "testlib" isn't a subdirectory of "test", I can't do
add_subdirectory("../../libs/testlib")
In test's CMakeFiles.txt - CMake will complain about "testlib" not being in the "test" subdirectory.
Also, because system has several different compilers, I can't simply install "testlib" libraries into some kind of central directory, so I want test to compile a local copy of testlib and link with it (i.e. as if testlib was a subdirectory). I also want the "test" project to automatically rebuild "testlib" if it has been changed.
So, how can I deal with it? I am using CMake 2.8.4 on Windows XP SP3.
You could either provide a top-level CMakeLists.txt in root, or provide a binary directory to the add_subdirectory command; e.g.
add_subdirectory("../../libs/testlib" "${CMAKE_CURRENT_BINARY_DIR}/testlib_build")
This creates a subdirectory called testlib_build in your current build directory which contains the generated project files for testlib, but not the source.
For further info, run
cmake --help-command ADD_SUBDIRECTORY
The only way I see to do this - create CMakeLists.txt in root and put the following code there:
add_subdirectory(projects/test)
add_subdirectory(lib/testlib)
When you have done this, you can do target_link_libraries(test testlib) in test/CMakeLists.txt, and it will be automatically rebuilt if you change something in testlib.