CMake: copy header file to output directory - c++

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}>

Related

Facing problems in my first time handling CMake, Third party(header only) libraries

I want to use the following library
https://github.com/gmeuli/caterpillar
It's documentation says that it's a header-only library, and that I should "directly integrate it into my source files with #include <caterpillar/caterpillar.h>." It also depends on a few other libraries, one of which I need to use directly as well.
So far I have done the following:
create cmake project to make an 'executable' (with the vscode extension)
created a 'lib' folder, inside which I did
git clone https://github.com/gmeuli/caterpillar
Then, I did include_directories(lib) in my cmake file.
But #include <caterpillar/caterpillar.h> doesn't quite work in my singular main.cpp file.
I played around with various CMake functions, and it either gave the error "No such file or directory" regarding caterpillar/caterpillar.h itself, or it gave "cannot open source file... dependent of caterpillar/caterpillar.h" depending on how I messed with the cmake file.
For reference:
cat ~/project/main.cpp
#include <caterpillar/caterpillar.hpp>
#include <lorina/lorina.hpp> //how do I include this ? it's in the lib folder of caterpillar itself, or do I need to have a copy of it in my lib folder too
int main()
{
// stuff in lorina:: namespace
// stuff in caterpillar:: namespace
return 0;
}
cat ~/project/CMakeLists.txt
include_directories(lib)
//... rest is stuff like CXX standard, etc etc
tree ~/project
main.cpp
lib/
caterpillar/
build/
cmake generated stuff
CMakeLists.txt
Firstly, modern cmake recommends target_include_directories() instead of old include_directories() for better scope management.
Actually <caterpillar/caterpillar.hpp> is not in $PROJECT_SOURCE_DIR/lib directory. That's why your code not works.
CMakeLists example:
cmake_minimum_required(VERSION 3.22)
project(myproject)
set(CMAKE_CXX_STANDARD 17)
add_executable(my_project main.cpp)
target_include_directories(my_project PRIVATE ${PROJECT_SOURCE_DIR}/lib/caterpillar/include)
# project_src_dir/lib/catepillar/include/ is the directory where you find the headers like <catepillar/catepillar.hpp>
target_include_directories(my_project PRIVATE ${PROJECT_SOURCE_DIR}/lib/caterpillar/lib/lorina)
caterpillar's document describes how to include their headers in a traditional style, assuming the readers could understand this and decide where to put the headers themselves. (which means you don't need the whole git repo but only the "include" dir.)
For this specific problem, the library has provided a detailed CMakeLists.txt for users to include:
cmake_minimum_required(VERSION 3.22)
project(my_project)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(lib/caterpillar)
# this works because "project_src_dir/lib/catepillar/CMakeLists.txt" exists.
add_executable(my_project main.cpp)
target_link_libraries(my_project PRIVATE caterpillar)
# you need to tell cmake to add all catepillar settings into your project

Collect all header files when compiling static library

I am using Cmake to compile a static version of the library from source.
The source code has a structure that looks like this:
src/
module1/
x.cpp
x.h
...
module2/
y.cpp
y.h
...
and so on...
Compiling a static version of the library is not difficult. However for distribution purposes, I just want to distribute the the headers (x.h, y.h, ...) and static libraries (module1.a, module2.a, ...).
Is there some command in GCC or CMAKE to automatically collect all of the headers and put them into a separate folder?
I am aware that I could manually separate the source and headers, or I could simply distribute all of the code (source and headers), but that is wasteful and undesireable for my particular use case. Alternatively, I could write a pretty simple Python script to do it, but it seems to me that this is probably a pretty common scenario. So I would guess that there is something in Gcc or Cmake to do it.
Note: I am not in charge of maintaining the codebase, so I have no say in how the project is structured. If I was, I could have separated the code into src and include folders.
The best thing to do is have cmake glob and install all your artifacts.
# append to your existing CMakeLists.txt
install(TARGETS module1 module2 #adjust to use your names
ARCHIVE DESTINATION lib)
file(GLOB_RECURSE header_list "*.h") #adjust if necessary
install(FILES ${header_list}
DESTINATION include)
Be aware that globbing isn't perfect, and the file list is only updated when cmake is run (i.e., it won't detect added or removed files on its own).

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 with gmock

I just want to make sure that my understanding about CMakeLists.txt is correct. My dummy project structure:
|-+ dummy
|-+ CMakeLists.txt
|-+ src
|-- CMakeLists.txt
|-- Converter.cpp
|-- Converter.hpp
|-- main.cpp
|-+ tests
|-- CMakeLists.txt
|-- Converter_ut.cpp
|-+ thirdparty
|-+ gmock-1.7.0
My goal is to create build process with CMake. This is my first attempt so I assume that there are some mistakes. It works but I am not sure if I understand everything correctly and I would be thankful if you could share with some comments / suggestions.
dummy/CMakeLists.txt
cmake_minimum_required (VERSION 2.8.11)
project (SUB)
add_subdirectory (src)
add_subdirectory (tests)
cmake_minimum_required is pretty self-explanatory,
project (SUB) sets project variables like ${SUB_SOURCE_DIR} and ${SUB_BINARY_DIR},
add_subdirectory, tells CMake to go and process CMakeLists.txt in the following directories
src/CMakeLists.txt
add_library (Sub
main.cpp
Converter.cpp)
target_include_directories (Sub PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
# Executable
add_executable (converter
Converter.cpp)
target_link_libraries (converter Sub)
add_library, creates library called "Sub" from two source files,
target_include_directories, tells the compiler where are the header files for "Sub" library (is that "PUBLIC" really needed here?),
add_executable, creates "converter" executable from Converter.cpp (why main.cpp is not needed here?),
target_link_libraries, links "Sub" library with "converter" executable
tests/CMakeLists.txt
# GMOCK
set (GMOCK_DIR "../thirdparty/gmock-1.7.0")
add_subdirectory(${GMOCK_DIR} ${CMAKE_BINARY_DIR}/gmock)
include_directories(SYSTEM ${GMOCK_DIR}/include ${GMOCK_DIR}/gtest/include)
# Executable
add_executable (tests
Converter_ut.cpp)
target_link_libraries (tests gmock_main Sub)
set (GMOCK_DIR ...), sets local variable "GMOCK_DIR" with my gmock folder location,
add_subdirectory, tells CMake to jump into gmock location and run their CMakeLists.txt, what is the second argument? {CMAKE_BINARY_DIR}/gmock?
add_executable, creates second executable file
target_link_libraries, links gmock_main library with second executable, "Sub" library is needed here because Converter_ut.cpp
needs to include "Converter.hpp" from src directory
Thank you in advance. I have read plenty of sites / tutorials already but I am still not sure about that.
One more thing - I cannot really imagine project with plenty of source files. Isn't there a better way to add source files to add_library and add_executable functions than listing it manually? Something like "take all *.cpp files from current directory"?
Thanks.
Cmake is not properly a programming language supporting a full paradigm, so use it, but if possible never start creating "a framework with it" (it would be cumbersome without proper syntactic sugar), it is intended to make small scripts not to write thousand lines of code (and despite few good frameworks exists, I tend to not use them: "If I cannot code it in few lines, then it's not job for CMAKE").
The important parts are (not that it is slightly different, I copy-pasted the improved version i still have to commit):
cmake_minimum_required( VERSION 2.8)
project( Infectorpp2)
# find additional cmake scripts (I'm driving away from this)
set( CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# create list of files from a glob
file( GLOB INFECTOR_SOURCE_FILES
"include/Infectorpp/priv/*.cpp")
# create list of files from a glob
file( GLOB INFECTOR_HEADER_FILES
"include/Infectorpp/priv/*.hpp"
"include/Infectorpp/*.hpp")
# or just "add_executable" the dollar "${}" just expand the list
add_library( libInfectorpp2 STATIC
${INFECTOR_SOURCE_FILES}
${INFECTOR_HEADER_FILES})
If you are not using 3rd party libraries, then you do not need to add target_include_directories because for your own application relative paths suffice.
For the testing part you are mostly ok to me, but I would do:
enable_testing()
## details omitted...
# create list of files from a glob
file( GLOB GMOCK_TESTS_SOURCE_FILES
"locationToTestFiles/*.cpp")
# Executable
add_executable (tests
${GMOCK_TESTS_SOURCE_FILES})
target_link_libraries (tests gmock_main Sub)
add_test(tests tests)
Also note that CMAKE is the only reason why I find useful having different extensions for C++ files, because of GLOBS, if you want to exclude some file you have to change its extension (to cc, c++, cxx or what your prefer).
You can do mostly anything following the same pattern, note that with GLOB you have to re-configure CMake to detect newly added files, however still better than adding them manually to build script (and anyway that will not cause a whole recompilation, CMake keep track of data and will avoid to re-compile old files)
Some people find useful adding files manually to CMake scripts because "I can keep old file there". Don't do that, move old files into an "old" folder, or just let your subversion system keep memory of them for you.
You will catch most errors earlier, and you will have a "ready to ship" project (you won't accidentally left wrong files that users will attempt to compile)
Another important point:
Do out of source builds, from your script I guess you are still not doing that.

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.