Collect all header files when compiling static library - c++

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).

Related

Automatically only link source with included header in CMake (simple project structure)

I have the following simple c++ project structure:
include/ contains header files
src/ contains the source files
cli/ contains source files with a main method
Currently, I build the whole source into a single static library and then compile each file in cli/ individually and link that static library. I do this with just one CMakeLists.txt in the root directory that basically looks like this:
include_directories(include)
set(HEADERS
include/file1.hpp
include/file2.hpp
include/sub1/file3.hpp
include/sub2/file4.hpp
)
set(SOURCE_FILES
src/file1.cpp
src/file2.cpp
src/sub1/file3.cpp
src/sub2/file4.cpp
)
set(EXECUTABLE_FILES
cli/app1.cpp
cli/app2.cpp
cli/app3.cpp
)
add_library(code STATIC ${SOURCE_FILES} ${HEADERS})
foreach (file ${EXECUTABLE_FILES})
get_filename_component(executable ${file} NAME_WE)
add_executable(${executable} ${file})
target_link_libraries(${executable} code)
endforeach ()
When I add a new file, I just add it to the appropriate list of files (headers, source, or executable).
Advantage: Simple work-flow with little overhead for maintaining the CMakeLists.txt.
Disadvantage: For each executable, the one big library is linked, even if the executable only uses the stuff in one of the source files (right now, there are about 15 executables using different subsets of the 25 source files).
My Question: Can I fix the disadvantage while keeping the advantage?
The only solution for fixing the disadvantage I could find is to manually specify for each executable which source files it needs. This is too tedious and error prone for my use case, as I will certainly forget to update the dependencies.
This is a bit unsatisfactory, as there is a very simple rule to which sources need to be linked: Every source file has a corresponding header file and I need to link src/file.cpp if and only if include/file.hpp is included. Is there any good way to tell CMake about this rule? Or do I need to write my own script that generates the CMakeLists.txt (which feels a bit like writing my own build system, which I would like to avoid)?

Cmake project with multiple executables

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.

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

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.

How can I build a C++ project with multiple interdependent subdirectories?

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).