Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top