CMake target_include_directories does not affect header files - c++

My project is roughly structured like this:
├CMakeLists.txt
|
├───ExampleApp
| ├───CMakeLists.txt
| ├───header.hpp
| └───main.cpp
|
└───ExampleLibrary
├───CMakeLists.txt
├───mylib.hpp
└───mylib.cpp
In the root CMakeLists.txt I call
add_subdirectory(ExampleLibrary)
add_subdirectory(ExampleApp)
To build the library I call:
add_library(ExampleLibrary
mylib.hpp mylib.cpp
)
And finally, in the executable, I try to do:
add_executable(ExampleApp
header.hpp main.cpp
)
target_include_directories(ExampleApp
PRIVATE ${PROJECT_SOURCE_DIR}/ExampleLibrary
)
target_link_libraries(ExampleApp
Path/To/The/Binary/Directory
)
Now the build files generate just fine, and the project also builds with no errors. However, when I now try to include mylib.hpp in header.hpp, I get build errors because it can't find the file mylib.hpp. But I actually can include mylib.hpp in main.cpp and the project builds and compiles.
Am I missing something? I thought target_include_directories() works for both .cpp and .hpp files.

It seems like you may not have added the correct directory as an include directory for the ExampleApp. The PROJECT_SOURCE_DIR variable evaluates to the directory in which the last project() call was made in your CMake project. You have not shown where this is, but you could use the root directory of the CMake project to be sure it is correct; try using ${CMAKE_SOURCE_DIR}/ExampleLibrary in the target_include_directories call instead:
target_include_directories(ExampleApp
PRIVATE ${CMAKE_SOURCE_DIR}/ExampleLibrary
)
A couple more notes:
If you aren't using an IDE such as Visual Studio for compilation, there is no need to add header files to calls like add_library() and add_executable(). Doing this only ensures they are shown in an IDE.
Instead, specify directories within which the headers can be found, using target_include_directories(). In your case, it sounds like you should have both directories listed here.
To link the ExampleLibrary target to the executable, you can simply use the target name in target_link_libraries(). There is no need to list out the binary directory (unless you are linking other libraries from there).
So with this in mind, the ExampleApp CMake file could look something like this:
add_executable(ExampleApp
main.cpp
)
target_include_directories(ExampleApp PRIVATE
${PROJECT_SOURCE_DIR}/ExampleLibrary
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(ExampleApp PRIVATE
ExampleLibrary
)

Related

Cmake adding a source folder to xcode without compiling the sources inside

I have a project that I am porting to cmake. The architecture of the sources is as follow:
src
|- FolderA
|-fileAa.cpp
|-fileAb.cpp
...
|- fileA.cpp
|-CMakeLists.txt
...
The file fileA.cpp is as follow:
#include <FolderA/fileAa.cpp>
#include <FolderA/fileAb.cpp>
//etc
My CMakeFiles.txt is as follow (the files from FolderA ARE NOT included in the add_library function)
#...
add_library(... fileA.cpp ...)
#...
And it works well. When I tried to build the library, if I modify any files inside FolderA, only the file fileA.cpp is rebuilt and the library is remade.
However, when I generate my project for Xcode, the files inside FolderA are not shown. Is there a way to tell cmake that I want it to include the files inside FolderA in my Xcode project (and any other supported IDE) but without adding them to the list of files to compile for the add_library function?
I tried to set the property of the files in FolderA as HEADER and still include them in add_library (as mentioned here) and it sort of worked, but in Xcode the files were displayed in a flat hierarchy and I would like to keep the same structure:
What I want in Xcode:
|-FolderA
|-fileAa.cpp
|-fileAb.cpp
...
|- fileA.cpp
What I have in Xcode:
|-fileAa.cpp
|-fileAb.cpp
|-fileA.cpp
...
I there a way to tell cmake to include a folder and its content to the project generated for an IDE, without adding the files I want to the list of files to compile ?
I solved my problem.
As mentioned here I need to use the files in a target for source_group to work. I used the trick that I mentionned of setting the sources of FolderA as header files and it worked perfectly:
file(GLOB COMPILED_SOURCES "*.cpp")
file(GLOB FOLDERA_SOURCES "FolderA/*.cpp")
set_source_files_properties(${FOLDERA_SOURCES} PROPERTIES HEADER_FILES_ONLY TRUE)
source_group(TREE ${PROJECT_SOURCE_DIR}/src FILES ${COMPILED_SOURCES} ${FOLDERA_SOURCES})
#...
<any function that create a target>(... ${COMPILED_SOURCES} ${FOLDERA_SOURCES} ... )
#...

Make headers appear like they are in a different folder

So I have a fancy-organized project that references headers from other projects like this:
#include <GeographicLib/Geocentric.hpp>
The thing is:
there is no GeographicLib folder
the project does compile with make
when I try to import it in CLion, it doesn't compile as it complains about missing headers
Is there a way to include a folder with CMakeLists.txt (the standard used by CLion) to make that .hpp file reference-able like it is in that GeographicLib folder without having to move files around or change the actual code?
Edit : (.hpp file is in a folder like ../other_proj/src/geolib)
One possible approach would be as follows: create a dummy target library (grouped_includes below) and link it to all your other targets (using target_link_libraries(target grouped_includes))
execute_process(
COMMAND ${CMAKE_COMMAND} -E create_symlink
"${CMAKE_SOURCE_DIR}/other_proj/src/geolib"
"${CMAKE_CURRENT_BINARY_DIR}/GeographicLib")
add_library(grouped_includes INTERFACE)
target_include_directories(grouped_includes INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)

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 doesn't include header directory of submodule A within submodule B

I have a CMake project that looks like this:
project/
CMakeLists.txt
subprojectA/
CMakeLists.txt
include/
headerA.hpp
src/
libraryA.cpp
subprojectB/
CMakeLists.txt
src/
mainB.cpp
The "library" subproject, A, is compiled as a static library, becoming libsubprojectA.a. The "main" project, B, is compiled as a binary and depends on the library. mainB.cpp includes a reference to headerA.hpp.
Here is subprojectA/CMakeLists.txt:
project(SubProjectA)
include_directories(include)
add_library(subprojectA STATIC src/libraryA.cpp)
set(${PROJECT_NAME}_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/include
CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
And here is subprojectB/CMakeLists.txt:
project(SubProjectB)
include_directories(${SubProjectA_INCLUDE_DIRS})
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
The main Project CMakeLists.txt looks like:
project(Project)
add_subdirectory(subprojectB)
add_subdirectory(subprojectA)
Note that subprojectB, the main project, is listed before subprojectA.
Here's the problem. When I first run "cmake" on this project, ${SubProjectA_INCLUDE_DIRS} is not set within SubProjectB.
What I think is happening is that the CMakeLists for SubProjectB loads first, when ${SubProjectA_INCLUDE_DIRS} has not yet been set. It sets its own include path to an empty string as a result. However, even though libsubprojectA.a gets built successfully before mainBinary, the include path was already set empty beforehand. As a result, I get this error when trying to make mainBinary:
subprojectB/src/mainB.cpp:1:23: fatal error: headerA.hpp: No such file or directory
#include "headerA.hpp"
^
It's a workaround to put subprojectA before subprojectB in the main Project CMakeLists in the declarative world of CMake. What I really want is to know the proper way to indicate to CMake that the include_directories(${SubProjectA_INCLUDE_DIRS}) line depends on the definitions that exist inside SubProjectA's CMakeLists. Is there a better way to do this?
If you want to express that include directory subprojectA/include is an interface of the library subprojectA, attach this property to the target with target_include_directories command:
subprojectA/CMakeLists.txt:
project(SubProjectA)
add_library(subprojectA STATIC src/libraryA.cpp)
# PUBLIC adds both:
# 1) include directories for compile library and
# 2) include directories for library's interface
target_include_directories(subprojectA PUBLIC include)
So any executable(or other library) which linked with subprojectA will have this include directory automatically:
subprojectB/CMakeLists.txt:
project(SubProjectB)
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
Of course, for use last command properly you need to process directory with library before one with executable:
CMakeLists.txt:
project(Project)
add_subdirectory(subprojectA)
add_subdirectory(subprojectB)

CMake Difference between include_directories and add_subdirectory?

I'm learning CMake for building C++ code, and struggling with the following concept. On my root level directory I have some cpp files and a CMakeLists.txt that succesfully generates some thrift code in a gen-cpp directory. My root level CMakeLists.txt contains :
include_directories("path-to-root"/gen-cpp). (along with the relevant thrift auto-generating and includes.
Everything compiles ok but I get run time dynamic library linked errors for undefined symbol referencing a class defined in the gen-cpp directory. When I move the files in the directory to the root level, it runs fine. what am I missing? (I had also adjusted the #include in the root level cpp directorie s to point to "path-to-root"/gen-cpp).
Is this a misunderstanding of using include_directory, where I should be using add_subdirectory. If the latter, would the code in gen-cpp needs its own CMakeLists.txt? Why is this additional file not needed, when the contents of said directory are root level?
add_subdirectory(source_dir): Used to add a subdirectory to the build. There is also a CMakeLists.txt file in the source_dir. This CMakeLists.txt file in the specified source directory will be processed immediately by CMake before processing in the current input file continues beyond this command.
include_directories(dir): Add the given directories to those the compiler uses to search for include files. These directories are added to the directory property INCLUDE_DIRECTORIES for the current CMakeLists file.
The include_directories() is used for adding headers search paths (-I flag) and add_subdirectory() will make no difference in this case.
I suppose, you need to list *.cpp files from gen-cpp folder in add_executable() or add_library() calls, in which you wish these symbols to be.
Alternatively, you can compile all thrift sources into the library and link it with your code.