How do I set up CMake to generate header-only projects?
Solution 1
Update: CMake will soon include a library target called INTERFACE that is ideal for header-only projects. This feature is currently in the master branch. Reference.
Using the command add_custom_target
as you propose works for me (VS2010). The files are neatly listed within my project but it has the drawback that you can't define any "Additional Include Directories" with a custom target. Instead, I now use the following:
add_library(HEADER_ONLY_TARGET STATIC test1.hpp test2.hpp)
set_target_properties(HEADER_ONLY_TARGET PROPERTIES LINKER_LANGUAGE CXX)
This sets up your header-only project as a dummy archive target. Don't worry, no actual binaries will be generated if you should try and build it (at least not in VS2010 and Xcode 4). The command set_target_properties
is there because CMake will otherwise complain that it cannot infer the target language from .hpp files only.
Solution 2
You can do this using the recent Interface Library feature:
add_library(mylib INTERFACE)
target_include_directories(mylib INTERFACE my_include_dir1 my_include_dir2)
This creates a library target without any source files, and adds the include directories to the INTERFACE_INCLUDE_DIRECTORIES property of the target. This means that any target that links to this library will get these directories as include paths (-I
) when built.
For instance, to use the library with an executable target, just do:
add_executable(myexec ${MY_SOURCES})
target_link_libraries(myexec mylib)
Solution 3
I think what you are looking for is just adding an include directory using the "include_directories" command for cmake.
When doing this, if it is a third party tool that you don't have control over, I would also add the "SYSTEM" flag.
So you command would look like something like this:
include_directories(SYSTEM ${GTEST_INCLUDE_DIRS})
Klaim
Updated on June 06, 2022Comments
-
Klaim about 2 years
I want to set up header-only C++ (or C) library projects, but can't find a clean way.
After some searches I've found that you can't set up a normal library using
add_library
to do this because it requires a compilable source file. A way to do this would be to useadd_custom_target
instead, this way:# Get all headers (using search instead of explicit filenames for the example) file( GLOB_RECURSE XSD_HEADERS *.hxx ) add_custom_target( libsxsd SOURCES ${XSD_HEADERS} )
But that doesn't seem to work completely here as I can't see the sources in the project generated in VS2010. I don't know if it's a bug or if I'm doing it wrong or if there is a preferred way to do this.
-
Klaim over 12 yearsThats not exactly what I want: I want to see the files inside the generated solution/project.
-
ComicSansMS almost 11 yearsThis is not portable and will fail at compile time with make (error
ar: no archive members specified
). -
Frederik Aalund almost 11 years@ComicSansMS Thanks for pointing that out! I didn't test this with make myself. Since you didn't post an answer of your own, I figure that there is no portable alternative. Someone should make a feature request to the CMake team.
-
ComicSansMS almost 11 yearsThe best way I could figure out so far is to add a
dummy.cpp
to the library just to keep CMake and the compilers happy. Apart from the noise of creating unnecessarily creating an intermediate static library file for the header-only libs, it works quite well. -
Trass3r over 10 yearsThat workaround is fine for the header-only library itself, but as soon as you try target_link_libraries(main hdr) it fails because there's no .lib
-
Trass3r over 10 yearsAlso for the INTERFACE libraries I haven't found a way yet to add files. You can't add include dirs and link to other libs conveniently either.
-
Frederik Aalund over 10 yearsAgreeably, it would be nice to have
target_link_libraries(TARGET HEADER_ONLY_TARGET)
link everything together as you propose. It's unfortunate that this approach doesn't work. You can useinclude_directories(TARGET HEADER_FILES)
instead as a work-around. Here,HEADER_FILES
is an array of the header files used to generate theHEADER_ONLY_TARGET
. -
Erik Sjölund almost 10 yearsThe newly released CMake 3.0.0 supports INTERFACE libraries see add_library documentation Unfortunately I haven't learned how to use them yet.
-
IdeaHat over 9 years@ErikSjölund old post I know but INTERFACE libraries don't have source dependencies and thus the headers don't show up in an IDE.
-
Erik Sjölund about 9 yearstarget_sources() might be helpful to get the headers to show up in an IDE. That CMake command was introduced in CMake 3.1. See also stackoverflow.com/a/29218394
-
vk-code over 5 yearsI just started using CMake and unfortunately i am stuck with old version of CMake which does not support INTERFACE and your solution works for me. I have no IDE requirement, working on Linux, VIM.