About a year ago I asked about header dependencies in CMake.
I realized recently that the issue seemed to be that CMake considered those header files to be external to the project. At least, when generating a Code::Blocks project the header files do not appear within the project (the source files do). It therefore seems to me that CMake consider those headers to be external to the project, and does not track them in the depends.
A quick search in the CMake tutorial only pointed to include_directories which does not seem to do what I wish...
What is the proper way to signal to CMake that a particular directory contains headers to be included, and that those headers should be tracked by the generated Makefile?
Two things must be done.
First add the directory to be included:
target_include_directories(test PRIVATE ${YOUR_DIRECTORY})
In case you are stuck with a very old CMake version (2.8.10 or older) without support for target_include_directories, you can also use the legacy include_directories instead:
include_directories(${YOUR_DIRECTORY})
Then you also must add the header files to the list of your source files for the current target, for instance:
set(SOURCES file.cpp file2.cpp ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_executable(test ${SOURCES})
This way, the header files will appear as dependencies in the Makefile, and also for example in the generated Visual Studio project, if you generate one.
How to use those header files for several targets:
set(HEADER_FILES ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_library(mylib libsrc.cpp ${HEADER_FILES})
target_include_directories(mylib PRIVATE ${YOUR_DIRECTORY})
add_executable(myexec execfile.cpp ${HEADER_FILES})
target_include_directories(myexec PRIVATE ${YOUR_DIRECTORY})
First, you use include_directories() to tell CMake to add the directory as -I to the compilation command line. Second, you list the headers in your add_executable() or add_library() call.
As an example, if your project's sources are in src, and you need headers from include, you could do it like this:
include_directories(include)
add_executable(MyExec
src/main.c
src/other_source.c
include/header1.h
include/header2.h
)
Structure of project
.
├── CMakeLists.txt
├── external //We simulate that code is provided by an "external" library outside of src
│ ├── CMakeLists.txt
│ ├── conversion.cpp
│ ├── conversion.hpp
│ └── README.md
├── src
│ ├── CMakeLists.txt
│ ├── evolution //propagates the system in a time step
│ │ ├── CMakeLists.txt
│ │ ├── evolution.cpp
│ │ └── evolution.hpp
│ ├── initial //produces the initial state
│ │ ├── CMakeLists.txt
│ │ ├── initial.cpp
│ │ └── initial.hpp
│ ├── io //contains a function to print a row
│ │ ├── CMakeLists.txt
│ │ ├── io.cpp
│ │ └── io.hpp
│ ├── main.cpp //the main function
│ └── parser //parses the command-line input
│ ├── CMakeLists.txt
│ ├── parser.cpp
│ └── parser.hpp
└── tests //contains two unit tests using the Catch2 library
├── catch.hpp
├── CMakeLists.txt
└── test.cpp
How to do it
1. The top-level CMakeLists.txt is very similar to Recipe 1, Code reuse with functions and macros
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-07 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# defines targets and sources
add_subdirectory(src)
# contains an "external" library we will link to
add_subdirectory(external)
# enable testing and define tests
enable_testing()
add_subdirectory(tests)
2.Targets and sources are defined in src/CMakeLists.txt (except the conversion target)
add_executable(automata main.cpp)
add_subdirectory(evolution)
add_subdirectory(initial)
add_subdirectory(io)
add_subdirectory(parser)
target_link_libraries(automata
PRIVATE
conversion
evolution
initial
io
parser
)
3.The conversion library is defined in external/CMakeLists.txt
add_library(conversion "")
target_sources(conversion
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/conversion.cpp
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/conversion.hpp
)
target_include_directories(conversion
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
4.The src/CMakeLists.txt file adds further subdirectories, which in turn contain CMakeLists.txt files. They are all similar in structure; src/evolution/CMakeLists.txt contains the following:
add_library(evolution "")
target_sources(evolution
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/evolution.cpp
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/evolution.hpp
)
target_include_directories(evolution
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
5.The unit tests are registered in tests/CMakeLists.txt
add_executable(cpp_test test.cpp)
target_link_libraries(cpp_test evolution)
add_test(
NAME
test_evolution
COMMAND
$<TARGET_FILE:cpp_test>
)
How to run it
$ mkdir -p build
$ cd build
$ cmake ..
$ cmake --build .
Refer to: https://github.com/sun1211/cmake_with_add_subdirectory
Add include_directories("/your/path/here").
This will be similar to calling gcc with -I/your/path/here/ option.
Make sure you put double quotes around the path. Other people didn't mention that and it made me stuck for 2 days. So this answer is for people who are very new to CMake and very confused.
CMake is more like a script language if comparing it with other ways to create Makefile (e.g. make or qmake). It is not very cool like Python, but still.
There are no such thing like a "proper way" if looking in various opensource projects how people include directories. But there are two ways to do it.
Crude include_directories will append a directory to the current project and all other descendant projects which you will append via a series of add_subdirectory commands. Sometimes people say that such approach is legacy.
A more elegant way is with target_include_directories. It allows to append a directory for a specific project/target without (maybe) unnecessary inheritance or clashing of various include directories. Also allow to perform even a subtle configuration and append one of the following markers for this command.
PRIVATE - use only for this specified build target
PUBLIC - use it for specified target and for targets which links with this project
INTERFACE -- use it only for targets which links with the current project
PS:
Both commands allow to mark a directory as SYSTEM to give a hint that it is not your business that specified directories will contain warnings.
A similar answer is with other pairs of commands target_compile_definitions/add_definitions, target_compile_options/CMAKE_C_FLAGS
I had the same problem.
My project directory was like this:
--project
---Classes
----Application
-----.h and .c files
----OtherFolders
--main.cpp
And what I used to include the files in all those folders:
file(GLOB source_files CONFIGURE_DEPENDS
"*.h"
"*.cpp"
"Classes/*/*.cpp"
"Classes/*/*.h"
)
add_executable(Server ${source_files})
And it totally worked.
You have two options.
The Old:
include_directories(${PATH_TO_DIRECTORY})
and the new
target_include_directories(executable-name PRIVATE ${PATH_TO_DIRECTORY})
To use target_include_directories, You need to have your executable defined - add_executable(executable-name sourcefiles).
So your code should appear like
add_executable(executable-name sourcefiles)
target_include_directories(executable-name PRIVATE ${PATH_TO_DIRECTORY})
You can read more here https://cmake.org/cmake/help/latest/command/target_include_directories.html
This worked for me:
set(SOURCE main.cpp)
add_executable(${PROJECT_NAME} ${SOURCE})
# target_include_directories must be added AFTER add_executable
target_include_directories(${PROJECT_NAME} PUBLIC ${INTERNAL_INCLUDES})
Don't forget to include ${CMAKE_CURRENT_LIST_DIR}.
That's what was causing problems for me.
Example should be like this:
target_include_directories(projectname
PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include"
)
PUBLIC for dependencies which you want to be included by a parent project.
PRIVATE for ones that you don't.
Note to site curators: This answer is very long. In case you are wondering, no it is not from a blog post. I wrote this specifically tailored to answer this question. If you think the length of the answer and its content warrant closing the question as needing focus, then I have no qualms with that. I personally am not a fan of the question anyway, but wanted to give a good answer because it has gotten so much attention over the years and thought the existing answers were lacking in certain ways.
In all the answers to this questions, there is a whole lot of "how" (to get what you want), and precious little "why" (digging into the problem that motivated the question and what the asker may have misunderstood about the ways in which different types of tools like IDEs and build tools do / do not interact and share information with each other, and what information CMake passes / needs to pass to those tools).
This question is vexxing, as it is motivated by a specific behaviour of a specific IDE- Code::Blocks) and CMake, but then poses a question unrelated to that IDE and instead about Makefiles and CMake, assuming that they have done something wrong with CMake which led to a problem with Makefiles, which led to a problem with their IDE.
TL;DR CMake and Makefiles have their own way of tracking header dependencies given include directories and source files. How CMake configures the Code::Blocks IDE is a completely separate story.
What is an "external" header in CMake?
I realized recently that the issue seemed to be that CMake considered those header files to be external to the project. [...]
It therefore seems to me that CMake consider those headers to be external to the project, and does not track them in the depends
As far as I know, there is no official or useful definition of "external header" when it comes to CMake. I have not seen that phrase used in documentation. Also note that the word "project" is a quite overloaded term. Each buildsystem generated by CMake consists of one top-level project, possibly including other external or subdirectory projects. Each project can contain multiple targets (libraries, executables, etc.). What CMake refers to as a target sometimes translates to what IDEs call projects (Ix. Visual Studio, and possibly Code::Blocks). If you had to given such a phrase a meaning, here's what would make sense to me:
In the case that the question is referring to some IDEs' sense of the word "project", which CMake calls "targets", header files are external to a project would be those that aren't intended to be accessed through any of the include directories of a target (Ex. Include directories that come from targets linked to the target in question).
In the case that the question is referring to CMake's sense of the word "project": Targets are either part of a project (defined/created by a call to the project() command, and built by the generated buildsystem), or IMPORTED, (not built by the generated buildsystem and expected to already exist, or built by some custom step added to the generated buildsystem, such as via ExternalProject_Add). Include directories of IMPORTED targets would be those headers which are external to the CMake project in question, and include directories of non-IMPORTED targets would be those that are "part of" the project.
Does CMake track header dependencies? (It depends!)
[...] CMake consider those headers to be external to the project, and does not track them in the depends
I'm not super familiar with the history of CMake, or with header dependency tracking in build tooling, but here is what I've gathered from the searching I have done on the topic.
CMake itself doesn't have much to do with any information related to header/include dependencies of implmentation files / translation units. The only way in which that information is important to CMake is if CMake needs to be the one to tell the generated buildsystem what those dependencies are. It's the generated buildsystem which wants to track changes in header file dependencies to avoid any unnecessary recompilation. For the Unix Makefiles generator in particular, before CMake 3.20, CMake would do the job of scanning header/include dependencies to tell the Makefiles buildsystem about those dependencies. Since v3.20, where supported by the compiler, CMake delegates that resposibility to the compiler by default. See the option which can be used to revert that behaviour here.
The exact details of how header/include dependency scanning differs for each supported CMake generator. For example, you can find some high-level description about the Ninja capabilities/approach on their manual. Since this question is only about Makefiles, I won't attempt to go into detail about other generators.
Notice how to get the header/include dependency information for the buildsystem, you only need to give CMake a list of a target's include directories, and a list of the implementation source files to compile? You don't need to give it a list of header files because that information can be scanned for (either by CMake or by a compiler).
Do IDEs get information about target headers by scanning?
Each IDE can display information in whatever way it wants. Problems like you are having with the IDE not showing headers usually only happen for IDE display formats of the project layout other than the filesystem layout (project headers files are usually in the same project directory as implementation files). For example, such non-filesystem layout views are available in Visual Studio and Code::Blocks.
Each IDE can get header information in whatever way it chooses. As far as I am aware (but I may be wrong for Visual Studio), both Visual Studio and Code::Blocks expect the list of project headers to be explicitly listed in the IDE project configuration files. There are other possible approaches (Ex. header dependency scanning), but it seems that many IDEs choose the explicit list approach. My guess would be because it is simple implementation-wise.
Why would scanning be burdensome for an IDE to find header files associated with a target?(Note: this is somewhat speculation, since I am not a maintainer of any such tools and have only used a couple of them) An IDE could implement the file scanning (which itself is a complicated task), but to know which headers are "in" the target, they'd either need to get information from the buildsystem about how the translation units of the target will get compiled, and that's assuming that all "not-in-target" header include paths are specified with a "system"-like flag, which doesn't have to be the case. Or, it could try to get that information from the meta-buildsystem, which here is CMake. Or it could try to do what CMake now does and try to invoke the selected compiler to scan dependencies. But in either case, they'd have to make some difficult decision about which buildsystems, meta buildsystems, and/or compilers to support, and then do the difficult work of extracting that information from whatever formats those tools store that information in, possibly without any guarantees that those formats will be the same in future tool versions (supporting a change in the format in a newer tool version could be similar to having to supporting a completely separate tool). The IDE could do all that work, or it could just ask you to give it a list of the headers belonging to each target. As you can see, there are cons to the diversity in tooling that the C/C++ ecosystem has. There are pros too, but that's outside the scope of this question.
On the bright side, CMake actually does have a mechanism to try to take some of that work off your shoulders. For such IDEs that have non-filesystem-views, it does implement a simple-heuristic to try to find header files that are associated with source files...
How does header file discovery work for the Code::Block IDE generator for CMake?
At least, when generating a Code::Blocks project the header files do not appear within the project (the source files do).
Here's something interesting: The CodeBlocks editor has the concept of source files and header files that are part of a project, and since CMake doesn't expect/require its users to tell it about each and every header file in the project (it only needs to know about what include directories should be associated with targets), it tries to use a certain heuristic to discover header files that are associated to implementation files. That heuristic is very basic: take the path of each source file in a project, and try changing the extenstion to be like one that is usually given to header files, and see if any such file exists. See the cmExtraCodeBlocksGenerator::CreateNewProjectFile member function in :/Source/cmExtraCodeBlocksGenerator.cxx.
In "Pitchfork Layout" terminology, it would be said that the heuristic assumes that the project uses "merged-header" placement instead of "split-header" placement, where there are separate src/ and include/ directories. So if you don't use merged-header layout, or otherwise have any target headers that don't meet that heuristic, such as utility header files, you'll need to explicitly tell CMake about those files (Ex. using target_sources) for it to pass that knowledge on to the IDE config it generates.
Further readings:
Here's the CMake documentation on its Code::Blocks generator (not much info related to the topic at hand, but good to link anyway).
Here's Code::Blocks' documentation on its "Project View". Here's the .cpb xml schema documentation (see in particular, the Unit element).
If you want to read the CMake code which does the associated header detection, you can find it in the cmExtraCodeBlocksGenerator::CreateNewProjectFile function in the Source/cmExtraCodeBlocksGenerator.cxx file.
Closing Words
I'm certain there are many people who know these tools better than I do. If you are one of those people and notice that I have made a mistake, please graciously correct me in the comments or in chat, or just to edit this post.
Note that while installation of build artifacts is an important part of many projects' lifecycles and is therefore incorporated into the designs of most C/C++ buildsystems, since the question didn't explicitly ask about the configuring the installation part, I have chosen to leave it out of this answer, since it in itself is not a trivial topic to cover (just see how long the related chapters in the "Mastering CMake" book are: The chapter on installation, and the chapter on importing and exporting).
In newer CMake versions we can limit our include-paths to target, like:
target_include_directories(MyApp PRIVATE "${CMAKE_CURRENT_LIST_DIR}/myFolder")
I mean, if the CMakeLists.txt has multiple targets, else, the include-paths are NOT shared with other CMakeLists.txt scripts, and it's enough to do something like:
include_directories("${CMAKE_CURRENT_LIST_DIR}/myFolder")
However, maybe we can simulate what target_include_directories(...) does for CMake 2.8.10 or older versions, like:
set_property(
TARGET MyApp
APPEND PROPERTY
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/myFolder"
)
All done, but seems if you want source-files to be re-compiled once any header-file they use is changed, all such header-files need to be added to each target as well, like:
set(SOURCES src/main.cpp)
set(HEADERS
${CMAKE_CURRENT_LIST_DIR}/myFolder/myHeaderFile.h
${CMAKE_CURRENT_LIST_DIR}/myFolder/myOtherHeader.h
)
add_executable(MyApp ${SOURCES} ${HEADERS})
Where with "seems" I mean that, CMake could detect such header-files automatically if it wanted, because it parses project's C/C++ files anyway.
I am using CLion also my project structure is the following :
--main.cpp
--Class.cpp
--Class.h
--CMakeLists.txt
The CMakeLists.txt before the change:
add_executable(ProjectName main.cpp)
The CMakeLists.txt after the change:
add_executable(ProjectName main.cpp Class.cpp Class.h)
By doing that the program compiled successfully.
Related
I have a project that's becoming large enough that I want to switch to from a plain Makefile to CMake. My project contains only one application, but supports two different boards (each board has a set of source files, and some defines specific to the board). The (simplified) project structure currently looks like this:
CMakeLists.txt
src/
├─ board/
│ ├─ board_a/
│ │ ├─ board.c
│ ├─ board_b/
│ │ ├─ board.c
├─ app/
│ ├─ main.c
CMakeLists.txt
I could (and currently have) just put everything in the root CMakeLists.txt file, but I don't want that file to become enormous as the project expands. Essentially, I am wondering how I can create a project which allows me to build an executable for either board where each executable can have a separate set of defines (that are used in both the board.c and main.c files), source files (board.c in this case, while sharing the main.c), and can share compile/linker options (I want to share some common compilation settings between both executables) without having one enormous CMakeLists.txt.
You already have a src/CMakeLists.txt, so you are part of the way there. Put your overall build settings -- dependencies, C standard version, global compiler flags -- in the top-level CMakeLists.txt. In the subdirectories, put only your CMake commands for the executables, or whatever target makes sense locally.
(As an aside, define "enormous"? I've got top-level CMakeLists here that are anywhere between 200-950 lines, but I've seen 3000-line monstrosities as well)
Personally, from the minimal sketch of the source layout here, I'd do:
src/CMakeLists.txt does an add_subdirectory() command for each board, e.g. add_subdirectory(board/board_a) . If you like, set() a variable to a list of board names and you can iterate over it.
In each board's subdirectory, create a library -- shared, static, or OBJECT -- named after the board, with the sources for that board. For instance add_library(board_a OBJECT board.c)
Back in src/CMakeLists.txt again, for each board, add an executable with the source from app/ and link to the library defined for the board, like
add_executable(exe_board_a app/source.c)
target_link_library(exe_board_a PRIVATE board_a)
If there are special considerations for that executable, set them there as well. Compile flags can be obtained from the library targets (use STATIC then, not OBJECT).
This moves most of the long-lists-of-sources and potentially compile flags to the per-board CMakeLists.txt and turns the intermediate level into a long list of "make this executable".
how I can create a project which allows me to build an executable for either board where each executable can have a separate set of defines
Put CMakeLists.txt inside board_a that does add_library(board_a board.c).
Put CMakeLists.txt inside board_b that does add_library(board_b board.c).
If the boards are somewhat similar:
In the root CMakeLists.txt create a add_executable(exe_board_a main.c) that target_link_libraries(exe_board_a PUBLIC board_a).
Repeat above for exe_board_b
If the boards are unrelated, like need many different compiler flags or separate toolchain files or even different compilers:
In the root CMakeLists.txt add_executable(exe main.c) that does target_link_libraries(exe PUBLIC ${USE_BOARD}).
Compile your project twice with cmake -DUSE_BOARD=board_a and cmake -DUSE_BOARD=board_b. Use two separate build directories. The double compilation can be scripted with a custom script, a root custom Makefile, or you can research cmake-presets.
Remember to use target_* commands, not the directory specific commands.
This isn't too bad with object libraries:
cmake_minimum_required(VERSION 3.22)
project(boards LANGUAGES C)
add_library(board_a OBJECT src/board_a/board.c)
target_compile_definitions(
board_a PUBLIC "defines for board_a.c and main.c")
add_library(board_b OBJECT src/board_b/board.c)
target_compile_definitions(
board_b PUBLIC "defines for board_b.c and main.c")
add_executable(main_a src/app/main.c)
target_link_libraries(main_a PRIVATE board_a)
add_executable(main_b src/app/main.c)
target_link_libraries(main_b PRIVATE board_b)
You could of course move the add_library calls down into subdirectories (via add_subdirectory), but the trick I'm using here is to put things like defines on as PUBLIC usage requirements for the object libraries, so that they will propagate to main.c when the associated application compiles.
You would have one add_executable call per board in the top level which you could of course place in a loop if you wind up with many boards.
About a year ago I asked about header dependencies in CMake.
I realized recently that the issue seemed to be that CMake considered those header files to be external to the project. At least, when generating a Code::Blocks project the header files do not appear within the project (the source files do). It therefore seems to me that CMake consider those headers to be external to the project, and does not track them in the depends.
A quick search in the CMake tutorial only pointed to include_directories which does not seem to do what I wish...
What is the proper way to signal to CMake that a particular directory contains headers to be included, and that those headers should be tracked by the generated Makefile?
Two things must be done.
First add the directory to be included:
target_include_directories(test PRIVATE ${YOUR_DIRECTORY})
In case you are stuck with a very old CMake version (2.8.10 or older) without support for target_include_directories, you can also use the legacy include_directories instead:
include_directories(${YOUR_DIRECTORY})
Then you also must add the header files to the list of your source files for the current target, for instance:
set(SOURCES file.cpp file2.cpp ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_executable(test ${SOURCES})
This way, the header files will appear as dependencies in the Makefile, and also for example in the generated Visual Studio project, if you generate one.
How to use those header files for several targets:
set(HEADER_FILES ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_library(mylib libsrc.cpp ${HEADER_FILES})
target_include_directories(mylib PRIVATE ${YOUR_DIRECTORY})
add_executable(myexec execfile.cpp ${HEADER_FILES})
target_include_directories(myexec PRIVATE ${YOUR_DIRECTORY})
First, you use include_directories() to tell CMake to add the directory as -I to the compilation command line. Second, you list the headers in your add_executable() or add_library() call.
As an example, if your project's sources are in src, and you need headers from include, you could do it like this:
include_directories(include)
add_executable(MyExec
src/main.c
src/other_source.c
include/header1.h
include/header2.h
)
Structure of project
.
├── CMakeLists.txt
├── external //We simulate that code is provided by an "external" library outside of src
│ ├── CMakeLists.txt
│ ├── conversion.cpp
│ ├── conversion.hpp
│ └── README.md
├── src
│ ├── CMakeLists.txt
│ ├── evolution //propagates the system in a time step
│ │ ├── CMakeLists.txt
│ │ ├── evolution.cpp
│ │ └── evolution.hpp
│ ├── initial //produces the initial state
│ │ ├── CMakeLists.txt
│ │ ├── initial.cpp
│ │ └── initial.hpp
│ ├── io //contains a function to print a row
│ │ ├── CMakeLists.txt
│ │ ├── io.cpp
│ │ └── io.hpp
│ ├── main.cpp //the main function
│ └── parser //parses the command-line input
│ ├── CMakeLists.txt
│ ├── parser.cpp
│ └── parser.hpp
└── tests //contains two unit tests using the Catch2 library
├── catch.hpp
├── CMakeLists.txt
└── test.cpp
How to do it
1. The top-level CMakeLists.txt is very similar to Recipe 1, Code reuse with functions and macros
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-07 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# defines targets and sources
add_subdirectory(src)
# contains an "external" library we will link to
add_subdirectory(external)
# enable testing and define tests
enable_testing()
add_subdirectory(tests)
2.Targets and sources are defined in src/CMakeLists.txt (except the conversion target)
add_executable(automata main.cpp)
add_subdirectory(evolution)
add_subdirectory(initial)
add_subdirectory(io)
add_subdirectory(parser)
target_link_libraries(automata
PRIVATE
conversion
evolution
initial
io
parser
)
3.The conversion library is defined in external/CMakeLists.txt
add_library(conversion "")
target_sources(conversion
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/conversion.cpp
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/conversion.hpp
)
target_include_directories(conversion
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
4.The src/CMakeLists.txt file adds further subdirectories, which in turn contain CMakeLists.txt files. They are all similar in structure; src/evolution/CMakeLists.txt contains the following:
add_library(evolution "")
target_sources(evolution
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/evolution.cpp
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/evolution.hpp
)
target_include_directories(evolution
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
5.The unit tests are registered in tests/CMakeLists.txt
add_executable(cpp_test test.cpp)
target_link_libraries(cpp_test evolution)
add_test(
NAME
test_evolution
COMMAND
$<TARGET_FILE:cpp_test>
)
How to run it
$ mkdir -p build
$ cd build
$ cmake ..
$ cmake --build .
Refer to: https://github.com/sun1211/cmake_with_add_subdirectory
Add include_directories("/your/path/here").
This will be similar to calling gcc with -I/your/path/here/ option.
Make sure you put double quotes around the path. Other people didn't mention that and it made me stuck for 2 days. So this answer is for people who are very new to CMake and very confused.
CMake is more like a script language if comparing it with other ways to create Makefile (e.g. make or qmake). It is not very cool like Python, but still.
There are no such thing like a "proper way" if looking in various opensource projects how people include directories. But there are two ways to do it.
Crude include_directories will append a directory to the current project and all other descendant projects which you will append via a series of add_subdirectory commands. Sometimes people say that such approach is legacy.
A more elegant way is with target_include_directories. It allows to append a directory for a specific project/target without (maybe) unnecessary inheritance or clashing of various include directories. Also allow to perform even a subtle configuration and append one of the following markers for this command.
PRIVATE - use only for this specified build target
PUBLIC - use it for specified target and for targets which links with this project
INTERFACE -- use it only for targets which links with the current project
PS:
Both commands allow to mark a directory as SYSTEM to give a hint that it is not your business that specified directories will contain warnings.
A similar answer is with other pairs of commands target_compile_definitions/add_definitions, target_compile_options/CMAKE_C_FLAGS
I had the same problem.
My project directory was like this:
--project
---Classes
----Application
-----.h and .c files
----OtherFolders
--main.cpp
And what I used to include the files in all those folders:
file(GLOB source_files CONFIGURE_DEPENDS
"*.h"
"*.cpp"
"Classes/*/*.cpp"
"Classes/*/*.h"
)
add_executable(Server ${source_files})
And it totally worked.
You have two options.
The Old:
include_directories(${PATH_TO_DIRECTORY})
and the new
target_include_directories(executable-name PRIVATE ${PATH_TO_DIRECTORY})
To use target_include_directories, You need to have your executable defined - add_executable(executable-name sourcefiles).
So your code should appear like
add_executable(executable-name sourcefiles)
target_include_directories(executable-name PRIVATE ${PATH_TO_DIRECTORY})
You can read more here https://cmake.org/cmake/help/latest/command/target_include_directories.html
This worked for me:
set(SOURCE main.cpp)
add_executable(${PROJECT_NAME} ${SOURCE})
# target_include_directories must be added AFTER add_executable
target_include_directories(${PROJECT_NAME} PUBLIC ${INTERNAL_INCLUDES})
Don't forget to include ${CMAKE_CURRENT_LIST_DIR}.
That's what was causing problems for me.
Example should be like this:
target_include_directories(projectname
PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include"
)
PUBLIC for dependencies which you want to be included by a parent project.
PRIVATE for ones that you don't.
Note to site curators: This answer is very long. In case you are wondering, no it is not from a blog post. I wrote this specifically tailored to answer this question. If you think the length of the answer and its content warrant closing the question as needing focus, then I have no qualms with that. I personally am not a fan of the question anyway, but wanted to give a good answer because it has gotten so much attention over the years and thought the existing answers were lacking in certain ways.
In all the answers to this questions, there is a whole lot of "how" (to get what you want), and precious little "why" (digging into the problem that motivated the question and what the asker may have misunderstood about the ways in which different types of tools like IDEs and build tools do / do not interact and share information with each other, and what information CMake passes / needs to pass to those tools).
This question is vexxing, as it is motivated by a specific behaviour of a specific IDE- Code::Blocks) and CMake, but then poses a question unrelated to that IDE and instead about Makefiles and CMake, assuming that they have done something wrong with CMake which led to a problem with Makefiles, which led to a problem with their IDE.
TL;DR CMake and Makefiles have their own way of tracking header dependencies given include directories and source files. How CMake configures the Code::Blocks IDE is a completely separate story.
What is an "external" header in CMake?
I realized recently that the issue seemed to be that CMake considered those header files to be external to the project. [...]
It therefore seems to me that CMake consider those headers to be external to the project, and does not track them in the depends
As far as I know, there is no official or useful definition of "external header" when it comes to CMake. I have not seen that phrase used in documentation. Also note that the word "project" is a quite overloaded term. Each buildsystem generated by CMake consists of one top-level project, possibly including other external or subdirectory projects. Each project can contain multiple targets (libraries, executables, etc.). What CMake refers to as a target sometimes translates to what IDEs call projects (Ix. Visual Studio, and possibly Code::Blocks). If you had to given such a phrase a meaning, here's what would make sense to me:
In the case that the question is referring to some IDEs' sense of the word "project", which CMake calls "targets", header files are external to a project would be those that aren't intended to be accessed through any of the include directories of a target (Ex. Include directories that come from targets linked to the target in question).
In the case that the question is referring to CMake's sense of the word "project": Targets are either part of a project (defined/created by a call to the project() command, and built by the generated buildsystem), or IMPORTED, (not built by the generated buildsystem and expected to already exist, or built by some custom step added to the generated buildsystem, such as via ExternalProject_Add). Include directories of IMPORTED targets would be those headers which are external to the CMake project in question, and include directories of non-IMPORTED targets would be those that are "part of" the project.
Does CMake track header dependencies? (It depends!)
[...] CMake consider those headers to be external to the project, and does not track them in the depends
I'm not super familiar with the history of CMake, or with header dependency tracking in build tooling, but here is what I've gathered from the searching I have done on the topic.
CMake itself doesn't have much to do with any information related to header/include dependencies of implmentation files / translation units. The only way in which that information is important to CMake is if CMake needs to be the one to tell the generated buildsystem what those dependencies are. It's the generated buildsystem which wants to track changes in header file dependencies to avoid any unnecessary recompilation. For the Unix Makefiles generator in particular, before CMake 3.20, CMake would do the job of scanning header/include dependencies to tell the Makefiles buildsystem about those dependencies. Since v3.20, where supported by the compiler, CMake delegates that resposibility to the compiler by default. See the option which can be used to revert that behaviour here.
The exact details of how header/include dependency scanning differs for each supported CMake generator. For example, you can find some high-level description about the Ninja capabilities/approach on their manual. Since this question is only about Makefiles, I won't attempt to go into detail about other generators.
Notice how to get the header/include dependency information for the buildsystem, you only need to give CMake a list of a target's include directories, and a list of the implementation source files to compile? You don't need to give it a list of header files because that information can be scanned for (either by CMake or by a compiler).
Do IDEs get information about target headers by scanning?
Each IDE can display information in whatever way it wants. Problems like you are having with the IDE not showing headers usually only happen for IDE display formats of the project layout other than the filesystem layout (project headers files are usually in the same project directory as implementation files). For example, such non-filesystem layout views are available in Visual Studio and Code::Blocks.
Each IDE can get header information in whatever way it chooses. As far as I am aware (but I may be wrong for Visual Studio), both Visual Studio and Code::Blocks expect the list of project headers to be explicitly listed in the IDE project configuration files. There are other possible approaches (Ex. header dependency scanning), but it seems that many IDEs choose the explicit list approach. My guess would be because it is simple implementation-wise.
Why would scanning be burdensome for an IDE to find header files associated with a target?(Note: this is somewhat speculation, since I am not a maintainer of any such tools and have only used a couple of them) An IDE could implement the file scanning (which itself is a complicated task), but to know which headers are "in" the target, they'd either need to get information from the buildsystem about how the translation units of the target will get compiled, and that's assuming that all "not-in-target" header include paths are specified with a "system"-like flag, which doesn't have to be the case. Or, it could try to get that information from the meta-buildsystem, which here is CMake. Or it could try to do what CMake now does and try to invoke the selected compiler to scan dependencies. But in either case, they'd have to make some difficult decision about which buildsystems, meta buildsystems, and/or compilers to support, and then do the difficult work of extracting that information from whatever formats those tools store that information in, possibly without any guarantees that those formats will be the same in future tool versions (supporting a change in the format in a newer tool version could be similar to having to supporting a completely separate tool). The IDE could do all that work, or it could just ask you to give it a list of the headers belonging to each target. As you can see, there are cons to the diversity in tooling that the C/C++ ecosystem has. There are pros too, but that's outside the scope of this question.
On the bright side, CMake actually does have a mechanism to try to take some of that work off your shoulders. For such IDEs that have non-filesystem-views, it does implement a simple-heuristic to try to find header files that are associated with source files...
How does header file discovery work for the Code::Block IDE generator for CMake?
At least, when generating a Code::Blocks project the header files do not appear within the project (the source files do).
Here's something interesting: The CodeBlocks editor has the concept of source files and header files that are part of a project, and since CMake doesn't expect/require its users to tell it about each and every header file in the project (it only needs to know about what include directories should be associated with targets), it tries to use a certain heuristic to discover header files that are associated to implementation files. That heuristic is very basic: take the path of each source file in a project, and try changing the extenstion to be like one that is usually given to header files, and see if any such file exists. See the cmExtraCodeBlocksGenerator::CreateNewProjectFile member function in :/Source/cmExtraCodeBlocksGenerator.cxx.
In "Pitchfork Layout" terminology, it would be said that the heuristic assumes that the project uses "merged-header" placement instead of "split-header" placement, where there are separate src/ and include/ directories. So if you don't use merged-header layout, or otherwise have any target headers that don't meet that heuristic, such as utility header files, you'll need to explicitly tell CMake about those files (Ex. using target_sources) for it to pass that knowledge on to the IDE config it generates.
Further readings:
Here's the CMake documentation on its Code::Blocks generator (not much info related to the topic at hand, but good to link anyway).
Here's Code::Blocks' documentation on its "Project View". Here's the .cpb xml schema documentation (see in particular, the Unit element).
If you want to read the CMake code which does the associated header detection, you can find it in the cmExtraCodeBlocksGenerator::CreateNewProjectFile function in the Source/cmExtraCodeBlocksGenerator.cxx file.
Closing Words
I'm certain there are many people who know these tools better than I do. If you are one of those people and notice that I have made a mistake, please graciously correct me in the comments or in chat, or just to edit this post.
Note that while installation of build artifacts is an important part of many projects' lifecycles and is therefore incorporated into the designs of most C/C++ buildsystems, since the question didn't explicitly ask about the configuring the installation part, I have chosen to leave it out of this answer, since it in itself is not a trivial topic to cover (just see how long the related chapters in the "Mastering CMake" book are: The chapter on installation, and the chapter on importing and exporting).
In newer CMake versions we can limit our include-paths to target, like:
target_include_directories(MyApp PRIVATE "${CMAKE_CURRENT_LIST_DIR}/myFolder")
I mean, if the CMakeLists.txt has multiple targets, else, the include-paths are NOT shared with other CMakeLists.txt scripts, and it's enough to do something like:
include_directories("${CMAKE_CURRENT_LIST_DIR}/myFolder")
However, maybe we can simulate what target_include_directories(...) does for CMake 2.8.10 or older versions, like:
set_property(
TARGET MyApp
APPEND PROPERTY
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/myFolder"
)
All done, but seems if you want source-files to be re-compiled once any header-file they use is changed, all such header-files need to be added to each target as well, like:
set(SOURCES src/main.cpp)
set(HEADERS
${CMAKE_CURRENT_LIST_DIR}/myFolder/myHeaderFile.h
${CMAKE_CURRENT_LIST_DIR}/myFolder/myOtherHeader.h
)
add_executable(MyApp ${SOURCES} ${HEADERS})
Where with "seems" I mean that, CMake could detect such header-files automatically if it wanted, because it parses project's C/C++ files anyway.
I am using CLion also my project structure is the following :
--main.cpp
--Class.cpp
--Class.h
--CMakeLists.txt
The CMakeLists.txt before the change:
add_executable(ProjectName main.cpp)
The CMakeLists.txt after the change:
add_executable(ProjectName main.cpp Class.cpp Class.h)
By doing that the program compiled successfully.
I'm having trouble organizing my project using CMake with multiple executables. I have the following structure:
CmakeLists.txt
main.cpp
somelib.cpp
somelib.h
dir1
main.cpp
file1.h
file1.cpp
...
dir2
main.cpp
lib1.h
lib2.cpp
...
In general, I want to be able to choose the executable in Clion and run any project independently including the outer one which depends on two other projects. In the outer main.cpp I include the headers from dir1 and dir2. The dir1, dir2 projects itself depend on different libraries like Boost, Eigen, Qt etc. What is the best way to make this structure work? I'm new to Cmake and multiple tries using add_subdirectory haven't brought me closer to a solution. I made it work only in case when I have outer CmakeLists.txt and include all libraries there while using dir1, dir2 just as folders without any CmakeLists.txt inside. I'd appreciate any help.
From a plain CMake perspective -- so I have no idea how this interacts with CLion, but you indicate in comments that writing-the-CMakeLists.txt is the important bits -- one way to do it is this:
have a top-level CMakeLists.txt which sets up CMake parameters, C++ standards, compiler flags, options, etc.
after all the setup, add_subdirectory(dir1/) and add_subdirectory(dir2/)
after that, whatever you need for the top-level target, such as add_executable(mytoplevelprogram main.cpp somelib.cpp). If the build of mytoplevelprogram needs headers from the libraries, use suitable target_include_directories(mytoplevelprogram ...) and/or link to artifacts created in the subdirectories
in each of the subdirectories dir1 and dir2, write a CMakeLists.txt that finds the dependencies and builds the executable for that subdirectory, with suitable add_executable() commands.
There's generally no reason to put more than one project() command in your source tree.
About a year ago I asked about header dependencies in CMake.
I realized recently that the issue seemed to be that CMake considered those header files to be external to the project. At least, when generating a Code::Blocks project the header files do not appear within the project (the source files do). It therefore seems to me that CMake consider those headers to be external to the project, and does not track them in the depends.
A quick search in the CMake tutorial only pointed to include_directories which does not seem to do what I wish...
What is the proper way to signal to CMake that a particular directory contains headers to be included, and that those headers should be tracked by the generated Makefile?
Two things must be done.
First add the directory to be included:
target_include_directories(test PRIVATE ${YOUR_DIRECTORY})
In case you are stuck with a very old CMake version (2.8.10 or older) without support for target_include_directories, you can also use the legacy include_directories instead:
include_directories(${YOUR_DIRECTORY})
Then you also must add the header files to the list of your source files for the current target, for instance:
set(SOURCES file.cpp file2.cpp ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_executable(test ${SOURCES})
This way, the header files will appear as dependencies in the Makefile, and also for example in the generated Visual Studio project, if you generate one.
How to use those header files for several targets:
set(HEADER_FILES ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_library(mylib libsrc.cpp ${HEADER_FILES})
target_include_directories(mylib PRIVATE ${YOUR_DIRECTORY})
add_executable(myexec execfile.cpp ${HEADER_FILES})
target_include_directories(myexec PRIVATE ${YOUR_DIRECTORY})
First, you use include_directories() to tell CMake to add the directory as -I to the compilation command line. Second, you list the headers in your add_executable() or add_library() call.
As an example, if your project's sources are in src, and you need headers from include, you could do it like this:
include_directories(include)
add_executable(MyExec
src/main.c
src/other_source.c
include/header1.h
include/header2.h
)
Structure of project
.
├── CMakeLists.txt
├── external //We simulate that code is provided by an "external" library outside of src
│ ├── CMakeLists.txt
│ ├── conversion.cpp
│ ├── conversion.hpp
│ └── README.md
├── src
│ ├── CMakeLists.txt
│ ├── evolution //propagates the system in a time step
│ │ ├── CMakeLists.txt
│ │ ├── evolution.cpp
│ │ └── evolution.hpp
│ ├── initial //produces the initial state
│ │ ├── CMakeLists.txt
│ │ ├── initial.cpp
│ │ └── initial.hpp
│ ├── io //contains a function to print a row
│ │ ├── CMakeLists.txt
│ │ ├── io.cpp
│ │ └── io.hpp
│ ├── main.cpp //the main function
│ └── parser //parses the command-line input
│ ├── CMakeLists.txt
│ ├── parser.cpp
│ └── parser.hpp
└── tests //contains two unit tests using the Catch2 library
├── catch.hpp
├── CMakeLists.txt
└── test.cpp
How to do it
1. The top-level CMakeLists.txt is very similar to Recipe 1, Code reuse with functions and macros
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-07 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# defines targets and sources
add_subdirectory(src)
# contains an "external" library we will link to
add_subdirectory(external)
# enable testing and define tests
enable_testing()
add_subdirectory(tests)
2.Targets and sources are defined in src/CMakeLists.txt (except the conversion target)
add_executable(automata main.cpp)
add_subdirectory(evolution)
add_subdirectory(initial)
add_subdirectory(io)
add_subdirectory(parser)
target_link_libraries(automata
PRIVATE
conversion
evolution
initial
io
parser
)
3.The conversion library is defined in external/CMakeLists.txt
add_library(conversion "")
target_sources(conversion
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/conversion.cpp
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/conversion.hpp
)
target_include_directories(conversion
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
4.The src/CMakeLists.txt file adds further subdirectories, which in turn contain CMakeLists.txt files. They are all similar in structure; src/evolution/CMakeLists.txt contains the following:
add_library(evolution "")
target_sources(evolution
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/evolution.cpp
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/evolution.hpp
)
target_include_directories(evolution
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
5.The unit tests are registered in tests/CMakeLists.txt
add_executable(cpp_test test.cpp)
target_link_libraries(cpp_test evolution)
add_test(
NAME
test_evolution
COMMAND
$<TARGET_FILE:cpp_test>
)
How to run it
$ mkdir -p build
$ cd build
$ cmake ..
$ cmake --build .
Refer to: https://github.com/sun1211/cmake_with_add_subdirectory
Add include_directories("/your/path/here").
This will be similar to calling gcc with -I/your/path/here/ option.
Make sure you put double quotes around the path. Other people didn't mention that and it made me stuck for 2 days. So this answer is for people who are very new to CMake and very confused.
CMake is more like a script language if comparing it with other ways to create Makefile (e.g. make or qmake). It is not very cool like Python, but still.
There are no such thing like a "proper way" if looking in various opensource projects how people include directories. But there are two ways to do it.
Crude include_directories will append a directory to the current project and all other descendant projects which you will append via a series of add_subdirectory commands. Sometimes people say that such approach is legacy.
A more elegant way is with target_include_directories. It allows to append a directory for a specific project/target without (maybe) unnecessary inheritance or clashing of various include directories. Also allow to perform even a subtle configuration and append one of the following markers for this command.
PRIVATE - use only for this specified build target
PUBLIC - use it for specified target and for targets which links with this project
INTERFACE -- use it only for targets which links with the current project
PS:
Both commands allow to mark a directory as SYSTEM to give a hint that it is not your business that specified directories will contain warnings.
A similar answer is with other pairs of commands target_compile_definitions/add_definitions, target_compile_options/CMAKE_C_FLAGS
I had the same problem.
My project directory was like this:
--project
---Classes
----Application
-----.h and .c files
----OtherFolders
--main.cpp
And what I used to include the files in all those folders:
file(GLOB source_files CONFIGURE_DEPENDS
"*.h"
"*.cpp"
"Classes/*/*.cpp"
"Classes/*/*.h"
)
add_executable(Server ${source_files})
And it totally worked.
You have two options.
The Old:
include_directories(${PATH_TO_DIRECTORY})
and the new
target_include_directories(executable-name PRIVATE ${PATH_TO_DIRECTORY})
To use target_include_directories, You need to have your executable defined - add_executable(executable-name sourcefiles).
So your code should appear like
add_executable(executable-name sourcefiles)
target_include_directories(executable-name PRIVATE ${PATH_TO_DIRECTORY})
You can read more here https://cmake.org/cmake/help/latest/command/target_include_directories.html
This worked for me:
set(SOURCE main.cpp)
add_executable(${PROJECT_NAME} ${SOURCE})
# target_include_directories must be added AFTER add_executable
target_include_directories(${PROJECT_NAME} PUBLIC ${INTERNAL_INCLUDES})
Don't forget to include ${CMAKE_CURRENT_LIST_DIR}.
That's what was causing problems for me.
Example should be like this:
target_include_directories(projectname
PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include"
)
PUBLIC for dependencies which you want to be included by a parent project.
PRIVATE for ones that you don't.
Note to site curators: This answer is very long. In case you are wondering, no it is not from a blog post. I wrote this specifically tailored to answer this question. If you think the length of the answer and its content warrant closing the question as needing focus, then I have no qualms with that. I personally am not a fan of the question anyway, but wanted to give a good answer because it has gotten so much attention over the years and thought the existing answers were lacking in certain ways.
In all the answers to this questions, there is a whole lot of "how" (to get what you want), and precious little "why" (digging into the problem that motivated the question and what the asker may have misunderstood about the ways in which different types of tools like IDEs and build tools do / do not interact and share information with each other, and what information CMake passes / needs to pass to those tools).
This question is vexxing, as it is motivated by a specific behaviour of a specific IDE- Code::Blocks) and CMake, but then poses a question unrelated to that IDE and instead about Makefiles and CMake, assuming that they have done something wrong with CMake which led to a problem with Makefiles, which led to a problem with their IDE.
TL;DR CMake and Makefiles have their own way of tracking header dependencies given include directories and source files. How CMake configures the Code::Blocks IDE is a completely separate story.
What is an "external" header in CMake?
I realized recently that the issue seemed to be that CMake considered those header files to be external to the project. [...]
It therefore seems to me that CMake consider those headers to be external to the project, and does not track them in the depends
As far as I know, there is no official or useful definition of "external header" when it comes to CMake. I have not seen that phrase used in documentation. Also note that the word "project" is a quite overloaded term. Each buildsystem generated by CMake consists of one top-level project, possibly including other external or subdirectory projects. Each project can contain multiple targets (libraries, executables, etc.). What CMake refers to as a target sometimes translates to what IDEs call projects (Ix. Visual Studio, and possibly Code::Blocks). If you had to given such a phrase a meaning, here's what would make sense to me:
In the case that the question is referring to some IDEs' sense of the word "project", which CMake calls "targets", header files are external to a project would be those that aren't intended to be accessed through any of the include directories of a target (Ex. Include directories that come from targets linked to the target in question).
In the case that the question is referring to CMake's sense of the word "project": Targets are either part of a project (defined/created by a call to the project() command, and built by the generated buildsystem), or IMPORTED, (not built by the generated buildsystem and expected to already exist, or built by some custom step added to the generated buildsystem, such as via ExternalProject_Add). Include directories of IMPORTED targets would be those headers which are external to the CMake project in question, and include directories of non-IMPORTED targets would be those that are "part of" the project.
Does CMake track header dependencies? (It depends!)
[...] CMake consider those headers to be external to the project, and does not track them in the depends
I'm not super familiar with the history of CMake, or with header dependency tracking in build tooling, but here is what I've gathered from the searching I have done on the topic.
CMake itself doesn't have much to do with any information related to header/include dependencies of implmentation files / translation units. The only way in which that information is important to CMake is if CMake needs to be the one to tell the generated buildsystem what those dependencies are. It's the generated buildsystem which wants to track changes in header file dependencies to avoid any unnecessary recompilation. For the Unix Makefiles generator in particular, before CMake 3.20, CMake would do the job of scanning header/include dependencies to tell the Makefiles buildsystem about those dependencies. Since v3.20, where supported by the compiler, CMake delegates that resposibility to the compiler by default. See the option which can be used to revert that behaviour here.
The exact details of how header/include dependency scanning differs for each supported CMake generator. For example, you can find some high-level description about the Ninja capabilities/approach on their manual. Since this question is only about Makefiles, I won't attempt to go into detail about other generators.
Notice how to get the header/include dependency information for the buildsystem, you only need to give CMake a list of a target's include directories, and a list of the implementation source files to compile? You don't need to give it a list of header files because that information can be scanned for (either by CMake or by a compiler).
Do IDEs get information about target headers by scanning?
Each IDE can display information in whatever way it wants. Problems like you are having with the IDE not showing headers usually only happen for IDE display formats of the project layout other than the filesystem layout (project headers files are usually in the same project directory as implementation files). For example, such non-filesystem layout views are available in Visual Studio and Code::Blocks.
Each IDE can get header information in whatever way it chooses. As far as I am aware (but I may be wrong for Visual Studio), both Visual Studio and Code::Blocks expect the list of project headers to be explicitly listed in the IDE project configuration files. There are other possible approaches (Ex. header dependency scanning), but it seems that many IDEs choose the explicit list approach. My guess would be because it is simple implementation-wise.
Why would scanning be burdensome for an IDE to find header files associated with a target?(Note: this is somewhat speculation, since I am not a maintainer of any such tools and have only used a couple of them) An IDE could implement the file scanning (which itself is a complicated task), but to know which headers are "in" the target, they'd either need to get information from the buildsystem about how the translation units of the target will get compiled, and that's assuming that all "not-in-target" header include paths are specified with a "system"-like flag, which doesn't have to be the case. Or, it could try to get that information from the meta-buildsystem, which here is CMake. Or it could try to do what CMake now does and try to invoke the selected compiler to scan dependencies. But in either case, they'd have to make some difficult decision about which buildsystems, meta buildsystems, and/or compilers to support, and then do the difficult work of extracting that information from whatever formats those tools store that information in, possibly without any guarantees that those formats will be the same in future tool versions (supporting a change in the format in a newer tool version could be similar to having to supporting a completely separate tool). The IDE could do all that work, or it could just ask you to give it a list of the headers belonging to each target. As you can see, there are cons to the diversity in tooling that the C/C++ ecosystem has. There are pros too, but that's outside the scope of this question.
On the bright side, CMake actually does have a mechanism to try to take some of that work off your shoulders. For such IDEs that have non-filesystem-views, it does implement a simple-heuristic to try to find header files that are associated with source files...
How does header file discovery work for the Code::Block IDE generator for CMake?
At least, when generating a Code::Blocks project the header files do not appear within the project (the source files do).
Here's something interesting: The CodeBlocks editor has the concept of source files and header files that are part of a project, and since CMake doesn't expect/require its users to tell it about each and every header file in the project (it only needs to know about what include directories should be associated with targets), it tries to use a certain heuristic to discover header files that are associated to implementation files. That heuristic is very basic: take the path of each source file in a project, and try changing the extenstion to be like one that is usually given to header files, and see if any such file exists. See the cmExtraCodeBlocksGenerator::CreateNewProjectFile member function in :/Source/cmExtraCodeBlocksGenerator.cxx.
In "Pitchfork Layout" terminology, it would be said that the heuristic assumes that the project uses "merged-header" placement instead of "split-header" placement, where there are separate src/ and include/ directories. So if you don't use merged-header layout, or otherwise have any target headers that don't meet that heuristic, such as utility header files, you'll need to explicitly tell CMake about those files (Ex. using target_sources) for it to pass that knowledge on to the IDE config it generates.
Further readings:
Here's the CMake documentation on its Code::Blocks generator (not much info related to the topic at hand, but good to link anyway).
Here's Code::Blocks' documentation on its "Project View". Here's the .cpb xml schema documentation (see in particular, the Unit element).
If you want to read the CMake code which does the associated header detection, you can find it in the cmExtraCodeBlocksGenerator::CreateNewProjectFile function in the Source/cmExtraCodeBlocksGenerator.cxx file.
Closing Words
I'm certain there are many people who know these tools better than I do. If you are one of those people and notice that I have made a mistake, please graciously correct me in the comments or in chat, or just to edit this post.
Note that while installation of build artifacts is an important part of many projects' lifecycles and is therefore incorporated into the designs of most C/C++ buildsystems, since the question didn't explicitly ask about the configuring the installation part, I have chosen to leave it out of this answer, since it in itself is not a trivial topic to cover (just see how long the related chapters in the "Mastering CMake" book are: The chapter on installation, and the chapter on importing and exporting).
In newer CMake versions we can limit our include-paths to target, like:
target_include_directories(MyApp PRIVATE "${CMAKE_CURRENT_LIST_DIR}/myFolder")
I mean, if the CMakeLists.txt has multiple targets, else, the include-paths are NOT shared with other CMakeLists.txt scripts, and it's enough to do something like:
include_directories("${CMAKE_CURRENT_LIST_DIR}/myFolder")
However, maybe we can simulate what target_include_directories(...) does for CMake 2.8.10 or older versions, like:
set_property(
TARGET MyApp
APPEND PROPERTY
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/myFolder"
)
All done, but seems if you want source-files to be re-compiled once any header-file they use is changed, all such header-files need to be added to each target as well, like:
set(SOURCES src/main.cpp)
set(HEADERS
${CMAKE_CURRENT_LIST_DIR}/myFolder/myHeaderFile.h
${CMAKE_CURRENT_LIST_DIR}/myFolder/myOtherHeader.h
)
add_executable(MyApp ${SOURCES} ${HEADERS})
Where with "seems" I mean that, CMake could detect such header-files automatically if it wanted, because it parses project's C/C++ files anyway.
I am using CLion also my project structure is the following :
--main.cpp
--Class.cpp
--Class.h
--CMakeLists.txt
The CMakeLists.txt before the change:
add_executable(ProjectName main.cpp)
The CMakeLists.txt after the change:
add_executable(ProjectName main.cpp Class.cpp Class.h)
By doing that the program compiled successfully.
I have a C++ project where I've used directories as more of an organizational element -- the way one might use packages in Java or directories in PHP. Directories are not intended to be self-sufficient elements, but rather just a way of organizing the whole of the project and keeping me from being overwhelmed by sources. How can I construct my CMakeLists.txt files to deal with this? Making the directories libraries doesn't seem to fit here, since they are all interdependent and not intended to be used that way.
As a related issue, most of the examples I've seen of multiple subdirectories in CMake (and there aren't very many of those) have ignored or glossed over the issue of setting include_directories, which is something I've been having trouble with. Short of combing my source files to determine which file depends on which and in what directory, is there anyway to just set all directories under /src/ as potential include directories and let CMake work out which ones are actually dependent?
Here's an example structure:
--src
--top1
--mid1
--bot1
--src1.cpp
--hdr1.h
--bot2
--src2.cpp
--hdr2.h
--mid2
--bot3
--src3.cpp
--src4.cpp
--hdr3.h
--top2
--mid3
--src5.cpp
--hdr4.h
So on and so forth. How can I structure my CMakeLists.txt files to handle this sort of structure?
Since the directory structure in your project is just there to keep your files organized, one approach is to have a CMakeLists.txt that automatically finds all sources files in the src directory and also adds all directories as include directories that have a header file in them. The following CMake file may serve as a starting point:
cmake_minimum_required(VERSION 3.12)
project (Foo)
file (GLOB_RECURSE Foo_SOURCES CONFIGURE_DEPENDS "src/*.cpp")
file (GLOB_RECURSE Foo_HEADERS CONFIGURE_DEPENDS "src/*.h")
set (Foo_INCLUDE_DIRS "")
foreach (_headerFile ${Foo_HEADERS})
get_filename_component(_dir ${_headerFile} PATH)
list (APPEND Foo_INCLUDE_DIRS ${_dir})
endforeach()
list (REMOVE_DUPLICATES Foo_INCLUDE_DIRS)
add_executable(FooExe ${Foo_SOURCES})
target_include_directories(FooExe PRIVATE ${Foo_INCLUDE_DIRS})
The two file(GLOB_RECURSE ... commands determine the set of source and header files. The foreach loop computes the set of include directories from the list of all header files. The CONFIGURE_DEPENDS flags tells CMake to re-run the glob command at build time.
One drawback with computing the set of source files is that CMake will not automatically detect when new files are added to your source tree. You manually have to re-create your build files then.
Though #sakra gave a good answer to this question, I believe it is more proper to approach it more in depth.
We want to separate our code into modules and libraries for many reasons. Like code encapsulation, re usability, easier debugging etc. This idea would propagate in compiling process too.
In other word, we want to divide the compilation process into little compilation steps, each belong to one module. So every module must have its own compilation procedure. This is why we use one CMakeLists.txt file per directory. Hence every directory would have its own compilation commands and there would be one master CMakeLists.txt file in the root directory of your project.
Here is an example. Consider the following structure of a project:
src/
|
- main.cpp
|
_sum/
|
- sum.h
|
- sum.cpp
We would have one CmakeLists.txt Per directory. First directory is the root directory of the project which src/ folder is in it. here is content for that file:
cmake_minimum_required(VERSION 3.4)
project(multi_file)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-Wall")
add_subdirectory(src)
Next CMakeLists.txt would located in src/ directory:
add_subdirectory("sum")
add_executable(out main.cpp)
target_link_libraries(out sum)
And the last one will be in the sum/ directory:
add_library(sum SHARED sum.cpp)
I hope this helps. I created a github repository in case you feel you need to see the code or you need further explanation.
I'm not an expert on CMake but since there are no other answers I'll take a look at the documentaton and give it a go. Organizing source and include files in different directories is pretty much the norm.
It looks like CMake allows you to give a list of include directories:
http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
So something like:
include_directories("src/top1/mid1/bot1" "src/top1/mid1/bot2/" ... )
These are passed to the compiler so it can find the header files and will be passed for each of the source files. So any of your source files should be able to include any of the header files (which I think is what you're asking for).
Similar to that you should be able to list all your source files in the add_executable command:
add_executable(name "src/top1/mid1/bot1/src1.cpp" "src/top1/id1/bot2/src2.cpp" ...)
So this would be a naive way of getting everything to build. Each source file will be compiled and will look for headers in all those directories and then the object files will get linked together. Consider if there is any way of simplifying this such that you don't need so many include folders, maybe there are only a few common header files that need to be referenced by all source files. If things get more complex you can buiild sub-hierarchies into libraries etc. Also consider seperating source files and headers (e.g. in src and include).