Recursive CMake search for header and source files - build

I am new to CMake and would like to ask if somebody can help in the following problem.
I have C++ source and header files in their respective folders and now, I want to make a CMake text file that recursively searches for them.
Currently, I am doing it in this way:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(CarDetectorDAISY)
file(GLOB_RECURSE SRCS *.cpp)
file(GLOB_RECURSE HDRS *.h)
ADD_EXECUTABLE(stereo_framework ${SRCS} ${HDRS})
TARGET_LINK_LIBRARIES(stereo_framework)
This creates my CarDetectorDAISY.sln solution file and when I try to build it, it shows
an error that header files are not found (No such file or directory).
It would be really grateful if someone can please help me. Thanks.

You're probably missing one or more include_directories calls. Adding headers to the list of files in the add_executable call doesn't actually add then to the compiler's search path - it's a convenience feature whereby they are only added to the project's folder structure in IDEs.
So, in your root, say you have /my_lib/foo.h, and you want to include that in a source file as
#include "my_lib/foo.h"
Then in your CMakeLists.txt, you need to do:
include_directories(${CMAKE_SOURCE_DIR})
If, instead you just want to do
#include "foo.h"
then in the CMakeLists.txt, do
include_directories(${CMAKE_SOURCE_DIR}/my_lib)
I should mention that file(GLOB...) is not the recommended way to gather your list of sources - you should really just add each file explicitly in the CMakeLists.txt. By doing this, if you add or remove a source file later, the CMakeLists.txt is modified, and CMake automatically reruns the next time you try and build. From the docs for file:
We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.

My answer is mostly a hack, but I find it useful if you don't want to add all dir manually.
This macro will recursively scan all sub-directories (and their sub-directories, etc ...). If a directory contains a header (.h) file, it will append its path to the return_list. This list can then be used with target_include_directories.
MACRO(HEADER_DIRECTORIES return_list)
FILE(GLOB_RECURSE new_list *.h)
SET(dir_list "")
FOREACH(file_path ${new_list})
GET_FILENAME_COMPONENT(dir_path ${file_path} PATH)
SET(dir_list ${dir_list} ${dir_path})
ENDFOREACH()
LIST(REMOVE_DUPLICATES dir_list)
SET(${return_list} ${dir_list})
ENDMACRO()
Usage:
HEADER_DIRECTORIES(header_dir_list)
list(LENGTH header_dir_list header_dir_list_count)
message(STATUS "[INFO] Found ${header_dir_list_count} header directories.")
target_include_directories(
my_program
PUBLIC
${header_dir_list} # Recursive
)
Macro credit: Christoph
Tested with Cmake 3.10

Just to further clarify one point in Fraser's answer:
Headers should not be passed to ADD_EXECUTABLE.
The reason is that the intended compilation command on Linux for example is just:
gcc main.c mylib.c
and not:
gcc main.c mylib.c mylib.h
The C pre-processor then parses mylib.c, and sees a #include "mylib.h", and uses it's search path for those files.
By using include_directories instead, we modify the cpp preprocessor search path instead, which is the correct approach. In GCC, this translates to adding the -I flag to the command line:
gcc -Inew/path/to/search/for/headers main.c mylib.c

Related

CMake: copy header file to output directory

I have a directory with c++ source and header files. I want to create a CMakeLists.txt to build this as a library for use in other CMake projects that include it as a sub directory.
Structure:
example/
foo.h
foo.cpp
CMakeLists.txt
The problem I run into is CMake doesn't seem to put foo.h anywhere, so getting the parent CMake to know how to find the header file is beguiling me.
Here's my current CMakeLists.txt:
cmake_minimum_required(VERSION 3.8.2)
project(example)
set (CMAKE_CXX_STANDARD 11)
# add library target foo
add_library(foo STATIC foo.cpp)
# tell cmake where to find headers for it
target_include_directories(foo PUBLIC .)
# sad attempt to get it to output the header
set_target_properties(foo PROPERTIES PUBLIC_HEADER foo.h)
I DON'T want to have to do install. The idea here is that the library would be used by other CMake projects, not by the entire system.
Ideally, the foo.h would show up next to libfoo.a in the build directory.
I've tried calling it a "FRAMEWORK", no luck; that only makes is a macOs framework.
I believe I can jury rig this, but methinks there's a best practice out there.
Open to an answer that says "here's a better way", too...
UPDATE
It might help to clarify how I think I want to pull this project into another. I've seen other projects use something like this:
add_subdirectory(<path_to_foo>/foo foo_build)
which causes the foo build to happen in a subdirectory. This allows me to refer to the library using 'foo_build', which is nice and clean. However, I still have to point at the original include directory to get the .h file, which makes me feel like I'm missing something.
It seems like cmake would have a clean solution for this.
I am fairly new to CMake but what I think you want is a 'add_custom_command'.
add_custom_command(TARGET foo.a POST_BUILD COMMAND copy foo.h ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
That might work.
What you are looking for is the following structure:
example/
- CMakeLists.txt
- src/
- main.c
- sub/
- foo/
- CMakeLists.txt
- src/
- foo/
- foo.c
- foo.h
Your CMakeLists will look like the following
example/CMakeLists.txt
# use modern target-based cmake features
cmake_minimum_required (VERSION 3.0)
# projectname
project (ff1_selfcheck)
add_subdirectory (sub/foo)
# executable to create
add_executable(${PROJECT_NAME}
src/main.c
)
# link libraries
target_link_libraries(${PROJECT_NAME}
PRIVATE
foo # imported target
)
example/sub/foo/CMakeLists.txt
# use modern target-based cmake features
cmake_minimum_required (VERSION 3.0)
# projectname
project (foo)
# executable to create
add_library(${PROJECT_NAME}
src/foo.c
)
# directories where to search for header files
target_include_directories(${PROJECT_NAME}
PUBLIC
source # the headerfiles in source are the includes
)
By using the project name foo in target_link_libraries(...) you refer to the foo library target
Furthermore, by using the PUBLIC keyword in the foo library, your headers (your include directory) is automatically propagated to every CMake project that adds this library via add_subdirectory(...).
Therefore you don't need to copy your headers! CMake >= 2.8.12 is beautiful, isn't it?
If you really want to copy files via CMake, the following would work:
file(COPY srcDir
DESTINATION dstDir
FILES_MATCHING
PATTERN .h
)
Take a look here: https://cmake.org/cmake/help/v3.2/command/file.html
As a general rule for CMake, sources are kept in the source directory and binaries and other generated files are within the build directory. So you wish is not very CMake-ish.
CMake would put headers and libraries according to your wishes when you install the project. Then you can specify what to copy where.
As you don't want to install this module, the best way is to create a package by providing a CMake config file for your project. This means that your project Foo would generate a file FooConfig.cmake which contains the paths to includes and libraries. The other CMake project would use find_package(Foo) to look for the file. By adding a hint to Foo_DIR you can make CMake find your project in a non-standard directory.
Further reading:
CMake documentation about packages
About how to use your library
Note, that configure_file is unrelated to what you wish, the confusing name has historic reasons. You can use this command, but per se it is unrelated.
UPDATE: after the update, I think that you want to use an external project. Behaves like an internal library, but pretty separated. See https://cmake.org/cmake/help/latest/module/ExternalProject.html
you should use generator expression for your "foo" include directory:
target_include_directories(foo PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR})
And since you don't want install rules not need to also add a $<INSTALL_INTERFACE:include>...
BTW you should don't care to copy the include file in the build directory (supposing you are building out of the source).
ps: if you also generate headers files simply add $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>

CMake add library with subdirectories

TL;DR
Using CMake, how can I include subdirectories into a library such that they can be included without referencing the directories they reside?
End TL;DR
In attempt to be brief and speak in higher level ideas of what and how, I have removed everything that I consider to be unnecessary details. I will make edits if need be. As such, this is a brief synopsis of my project structure.
ParentDir
--src
----source.cpp
----source.h
----entities_dir
------entity.cpp
------entity.h
------CMakeLists.txt
----CMakeLists.txt
--CMakeLists.txt
--main.cpp
as it currently stands, I have a library defined by the CMakeLists in the src directory. As such, I can include src files in main by #include as apposed to #include "src/file.h" I would like to be able to do the same for my headers that exist within the subdirectories of src.
CMakeLists.txt
cmake_minimum_required(VERSION 3.6)
project(Project)
add_executable(Project ${SOURCE_FILES} main.cpp)
include_directories(src)
add_subdirectory(src)
target_link_libraries(Project Library) # Engine Libraries
src/CMakeLists.txt
file(GLOB SOURCE_FILES *.cpp)
file(GLOB HEADER_FILES *.h)
add_library(Library STATIC ${SOURCE_FILES} ${HEADER_FILES})
main.cpp
#include <source.h> // this works
#include <entity.h> // this does not work but I want it to
#include <entities/entity.h> // this works but I don't want this
int main() {}
I am not sure how to do this exactly. I have tried to GLOB_RECURSE, add_subdirectory(entities), etc. I have also tried creating a library called Entities inside the src/entities/CMakeLists.txt and linking that with link_libraries. None of these have been successful. What is the proper way to accomplish this, because I think I am probably approaching this completely wrong.
You need that path in your compilers header search path, which is achieved with include_directories() call. You can amend your existing include_directories(src) call to be:
include_directories(src src/entities)
Also, this SO post is related and worth reading: Recursive CMake search for header and source files. There is an excerpt there from the CMake website itself recommending against the usage of file(GLOB ...), which lends to recommending against recursive solutions in general. As a heavy user of CMake, I agree with the arguments made against it.
You just need to add:
include_directories(${CMAKE_CURRENT_LIST_DIR})
In each CMakeLists.txt in your your hierarchy.
CMake in itself doesn't compile your project, it only calls your toolchain and passes parameters to it, and your toolchain doesn't 'know' that it is being called by CMake, or the structure of your project. As such, you need to tell the toolchain where to locate include files.
While it is commonplace to have a CMakeLists.txt in every subdirectory, this is by no means a requirement. The CMakeLists.txt in your src directory could contain all instructions necessary to generate a build. Generally, CMakeLists.txt are put at each level to make the structure easier to manage, eg. each directory only needs to know what it needs to do (presumably, with the files in that directory).

Avoiding many "../include" in CMake

I just started getting into CMake with C++ and was wondering how other programmers avoid having to do "../include" in all their CMakeFiles.txt.
One example is here: https://github.com/clab/cnn/blob/master/examples/CMakeLists.txt
They create an executable for each example without having to call INCLUDE_DIRECTORIES(...).
I tried adding the headers when calling ADD_LIBRARY(...), but that didn't seem to work.
Example:
tl/src/CMakeLists.txt:
SET(SRCS "x1.cpp" "x2.cpp")
SET(HDRS "../include/tl/x1.h" "../include/tl/x2.h")
INCLUDE_DIRECTORIES("../include")
ADD_LIBRARY(test_lib ${SRCS} ${HDRS})
tl/CMakeLists.txt:
PROJECT(TEST_LIB VERSION 0.1)
ADD_SUBDIRECTORY("src")
tl/examples/CMakeLists.txt:
INCLUDE_DIRECTORIES("../include")
ADD_EXECUTABLE(e1 e1.cpp)
TARGET_LINK_LIBRARIES(e1 test_lib)
Edit: I believe that INCLUDE_DIRECTORIES(...) is only necessary one per each directory throughout the tree.
Just add the INCLUDE_DIRECTORIES command at the top level. No need to explicitly add included files then.
tl/CMakeLists.txt:
PROJECT(TEST_LIB VERSION 0.1)
INCLUDE_DIRECTORIES("include")
ADD_SUBDIRECTORY("src")
ADD_SUBDIRECTORY("examples")
tl/src/CMakeLists.txt:
ADD_LIBRARY(test_lib "x1.cpp" "x2.cpp")
tl/examples/CMakeLists.txt:
ADD_EXECUTABLE(e1 e1.cpp)
TARGET_LINK_LIBRARIES(e1 test_lib)
How about this? tl/CMakeLists.txt
SET(SRCS "x1.cpp" "x2.cpp")
SET(HDRS "../include/tl/x1.h" "../include/tl/x2.h")
INCLUDE_DIRECTORIES("${CMAKE_PROJECT_DIR}/include")
ADD_LIBRARY(test_lib ${SRCS} ${HDRS})
You do not need to add headers to ADD_LIBRARY or ADD_EXECUTABLE if you want to compile your programs and libs. Only source files "cpp,c,cxx,..." are required because through the include macro #include you tell the compiler where it finds the header files.
With INCLUDE_DIRECTORIES(...) you only add a search path to the compiler where to look for headers. If you have your headers in the same directory as your source you don't need another search path. Also subpaths with include macro like this #include "../../include" is possible. So it really depends on the structure of your source files. Also remember, compiler settings setups know where some of the system headers are found. That is why you also do not need to define them.
And last but not least there are cmake scripts and pkg search files where adding paths to specific libraries is done automatically.
This is how I did it in a project of mine:
file(GLOB_RECURSE SRC
engine/*.cpp
platfoorm/*.cpp
)
file(GLOB_RECURSE INCLUDES
engine/*.h
platform/*.h
)
This generate an internal "hardcoded" list of files that the generated makefil will use, so if you add a new source file you will need to re-run cmake.
Of course you can change and add paths, the one in the example are the one I used in my project.

CMake link files from subdirectories and parent directories

I have a folder net like:
main
headers
cls1.hpp cls2.hpp ...
sources
cls1.cpp cls2.cpp ...
resources
r1.hpp r2.hpp ...
I have tried more cmake methods to link the files, like
set(SRC ${SRC})
in parent dir and
set(SRC ${SRC} ${CMAKE_CURRENT_SOURCE_DIR}/cls1.cpp PARENT_SCOPE)
in subdir
OR
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE HDR_FILES ${PROJECT_SOURCE_DIR}/*.hpp)
to get the .cpp and .hpp files, but when I do
#include "resources/r1.hpp"
I get error like "resources/r1.hpp" No such a file or directory
Can anyone help me pleas? How can I do linking between files in folders in my case?
To solve this specific problem, in your main CMakeLists.txt add this line before adding subfolders:
include_directories(".")
This will allow the compiler to see the file located in resources/r1.hpp starting from the root path.
However, I suggest you take a look to some CMake projects examples, because it doesn't seem you are doing things in the standard way (e.g. usually a good way is to add a sub directory that creates its own library, that then you link to your main executable)

Handling header files dependencies with cmake

I am using CMake on a small C++ project and so far it works great... with one twist :x
When I change a header file, it typically requires recompiling a number of sources files (those which include it, directly or indirectly), however it seems that cmake only detects some of the source files to be recompiled, leading to a corrupted state. I can work around this by wiping out the project and rebuilding from scratch, but this circumvents the goal of using a make utility: only recompiling what is needed.
Therefore, I suppose I am doing something wrong.
My project is very simply organized:
a top directory where all resources sit, the main CMakeLists.txt sits there
a "include" directory where all public headers lies (in various subdirectories)
a "src" directory where all the subdirectories for sources files are, the src CMakeLists.txt sits there
a CMakeLists.txt per subdirectory in the "src" directory
The main directory has:
cmake_minimum_required(VERSION 2.8)
project(FOO)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
# Compiler Options
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++0x -Wall -Wextra -Werror")
include_directories($(FOO_SOURCE_DIR)/include)
add_subdirectory(src)
The "src" directory:
add_subdirectory(sub1)
add_subdirectory(sub2)
add_subdirectory(sub3)
add_subdirectory(sub4)
add_executable(foo main.cpp)
target_link_libraries(foo sub1 sub2 sub3 sub4)
Where sub4 depends on sub3 which depends on sub2 which depends on sub1
And an example of a subdirectory (sub3):
set(SUB3_SRCS
File1.cpp
File2.cpp
File3.cpp
File4.cpp
File5.cpp
File6.cpp
)
add_library(sub3 ${SUB3_SRCS})
target_link_libraries(sub3 sub1 sub2)
I'd be glad if anyone could point my mistake to me, searching here or on CMake didn't yield anything so I guess it's very easy or should work out of the box...
(for reference, I am using cmake version 2.8.2 on MSYS)
EDIT:
Thanks to Bill's suggestion I have checked the depend.make file generated by CMake, and it is indeed lacking (severely). Here is an example:
src/sub3/CMakeFiles/sub3.dir/File1.cpp.obj: ../src/sub3/File1.cpp
Yep, that's all, none of the includes were referenced at all :x
You should look at the depend.make files in your binary tree. It will be in CMakeFiles/target.dir/depend.make. Try to find one of those that is missing a .h file that you think it should have. Then create a bug report for cmake or email the cmake mailing list.
I just hit the same issue. After changing paths in include_directories() from absolute to relative it added appropriate dependencies.
Looks like CMake tries to guess which headers are system and which are project related. I suspect that directories that starts with / passed as -isystem /some/path and thus are not presented in generated dependencies.
If you can't replace ${FOO_SOURCE_DIR} with relative path you can try to calculate relative path using appropriate CMake functions. I.e.:
file(RELATIVE_PATH FOO_SOURCE_REL_DIR
${CMAKE_CURRENT_SOURCE_DIR}
${FOO_SOURCE_DIR}/.)
include_directories(${FOO_SOURCE_REL_DIR}/include)
Did you run cmake before or after adding the includes to your cpp files?
I ran into this problem and re-running cmake fixed it. I'd added the include post-cmake.
Apparently cmake removes system include paths from the dependency trees (thank you #ony for this hint). This probably makes sense most of the time, but sometimes cmake doesn't know what the compiler thinks is a system path or not. We are using a custom gcc build that ignores /usr/include, but cmake thinks it doesn't ignore it. To force cmake to make /usr/include a dependency that is NOT optimized away, try this trick: prepend /. to the path.
I am trying to make all of the library dependencies use the cmake dependency feature, including certain "3rd" party libraries that are not always installed by default on Linux or even available. For example, Z-lib compression.
The following interface target worked fine if the Z lib includes were not in /usr/include, but would break if they were.
find_package(ZLIB REQUIRED)
message(status "found zlib ${ZLIB_LIBRARIES}")
message(status "found zlib includes ${ZLIB_INCLUDE_DIRS}")
target_link_libraries(zlib_target INTERFACE ${ZLIB_LIBRARIES})
target_include_directories(zlib_target INTERFACE ${ZLIB_INCLUDE_DIRS})
I changed the last line to
target_include_directories(zlib_target INTERFACE /.${ZLIB_INCLUDE_DIRS})
and it worked. Now targets that depended on zlib_target would automatically get -I/./usr/include during compilation.
Make sure that the include statement for the missing header is placed before the first program instruction. In my case cmake depend.make was not including the header file, because it was following the first program instruction.