How can I include a header-only library with CMake? - cmake

How can I add a header-only library outside the directory?
Previously I was using add_subdirectory(HEADERLIBRARY) only when the directory HEADERLIBRARY was inside the project directory. However, now I want to use the library for multiple projects, so I made a directory like this:
OUT
|----HEADERLIBRARY // of course contains CMakeLists.txt
|
|----project1
|----project2
|...
Is there a way to get the same effect as when I use add_subdirectory?
EDIT : HEADERLIBRARY = https://github.com/taocpp/PEGTL/blob/master/doc/Installing-and-Using.md#add_subdirectory

Yes, you still just use add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL]).
Because source_dir is not within the source directory tree of the top-level project you have to specify the [binary_dir] folder that is going to be used. By default binary_dir is the same as source_dir within the binary directory tree and it is handled automatically.

Related

Install a target defined in an included directory [duplicate]

Consider the following CMakeLists.txt file:
add_subdirectory(execA)
add_subdirectory(libB)
install(TARGETS execA libB
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
I get the following error:
install TARGETS given target "execA" which does not exist in this
directory
execA and libB have their own CMakeList.txt files and are located under project directory, as well as the build directory I'm running cmake (cmake ..):
project
|------ CMakeList.txt (the one with the code)
|----execA
| \- .cpp, .hpp and CMakelist.txt
|----libB
| \- .cpp, .hpp and CMakelist.txt
|---- lib
|---- bin
\---- build (where I´m commanding: $ cmake ..
How do I fix this error?
According to this bugreport, install(TARGETS) command flow accepts only targets created within the same directory.
So you need either move the add_library() call into the top-level directory, or split install(TARGETS) call into per-target ones, and move each of them into the corresponding subdirectory.
Since CMake 3.13 install(TARGETS) can work even with targets created in other directories.
install(TARGETS) can install targets that were created in other directories. When using such cross-directory install rules, running make install (or similar) from a subdirectory will not guarantee that targets from other directories are up-to-date.
Even though it would help seeing the CMakeLists.txt files contained in the subdirectories, I guess they contain add_executable and/or add_library statements to create your stuff.
Also, because of your example, I guess you are using the same name of your directories for your targets.
That said, you should know that symbols defined in a CMakeLists.txt file in a subdirectory are not visible by default within the context of the CMakeLists.txt file in the parent directory. Because of that, you should rather move your install statements within the CMakeLists.txt files within your subdirectories.
This should solve the problem, if my thoughts were right. Otherwise, I strongly suggest you to post in your question also the content of the other files above mentioned.
Anyway, the error is quite clear.
The file that contains the install statement for the target named X does not contain a target creation statement (add_executable and the others) that gives birth to that target, so it goes on saying that that target does not exist in that directory.
This still seems to be a pain point in CMake 3.11.
In our codebase, we have many targets defined in subdirectories and need to create an assortment of installers with different configurations and (potentially overlapping) combinations of targets.
Here's my solution:
Before calling add_subdirectory in your root CMakeLists.txt file, create a GLOBAL property with the names of the target(s) you want to include in your installer.
Wrap target creation functions (add_executable, etc.) in your own custom functions. Within those functions check if the target is present in the global property, and invoke install accordingly.
That approach allows you to centralize installer configuration.
Also: To support creation of multiple installers, we populate our global list along with other installer properties in separate .cmake files. When we invoke cmake, we pass the name of the installer configuration CMake file as a command-line argument. Our root CMakeLists.txt file simply calls include with that file.

CMake. Include another cmake project using its CMakeLists.txt

I have a third_party directory with another cmake project in it. How can I add includes and sources of that project into my project? I tried to use include third_party/project/CMakeLists.txt but it gives me error something like 'can't find directory "X"'. I thing its because when I use include() it doesn't change working directory to third_party/project but uses my root project's one. Directory "X" exists in that project I want to add. What can I do in that case?

CMake generated include directory

How to tell CMake that directory is generated so that it doesn't complain before building process that directory doesn't exist?
My library project is used by many clients and for every client I have client-specific configuration generated by scripts and placed into generated/[client-name]/generated.h header. So for every client there's is folder generated. But parent project source files (*.cpp) include just generated.h. I wanted to add generated/[client-name] interface include directory for my library by using:
set_target_properties(mylib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "generated/myclient" ...)
but CMake complains even before starting compilation - Imported target "xxx" includes non-existent path. So I guess CMake doesn't like that include directory is missing when it starts building process although target depends on other targets which should create correct directory & header file within it.
You can create the directory first with CMake:
file(MAKE_DIRECTORY "generated/myclient")
This will have no effect if the directory exists already.

Cmake - how to inject source file into subdirectory project

I have a cmake project leveraging another cmake library project, the dir looks like this:
/CMakeList.txt
/main.c
/.gitmodules
/patch/patch.c
/vendor/CMakeList.txt
/vendor/vendor.c
/vendor/...
In /CMakeList.txt, I used add_subdirectory(vendor) to include/link vendor library to my own project.
In /vendor/CMakeList.txt, source file is added by FILE(GLOB SRC_VEN vendor.c ...)
I want to inject /patch/patch.c into vendor library without touching /vendor directory, which is a git submodule
Is it possible to use cmake to achieve this in my root CMakeList.txt?
Thanks!
Turning my comment into an answer
If you want to inject sources into an existing target you can use target_sources() (introduced with CMake version 3.1).
In your case this would look something like:
/CMakeLists.txt
...
add_subdirectory(vendor)
target_sources(vendor_target PRIVATE "patch/patch.c")
I put vendor_target as a placeholder. Please replace it with the real name for the target you want to inject the sources into.
For more details see e.g. here.

Add a dependency not in a subdirectory using CMake

Let's say there's following directory structure:
root
|
+--projects
| |
| +-test
| |
| +-CMakeFiles.txt
|
+--libs
|
+-testlib
|
+-CMakeFiles.txt
test contains CMakeFiles.txt and testlib also contains CMakeFiles.txt. "test" produces an executable and "testlib" produces a static library.
I want "test" to link with "testlib" without using symlinks and without moving "testlib" library into a subdirectory within "test".
Because "testlib" isn't a subdirectory of "test", I can't do
add_subdirectory("../../libs/testlib")
In test's CMakeFiles.txt - CMake will complain about "testlib" not being in the "test" subdirectory.
Also, because system has several different compilers, I can't simply install "testlib" libraries into some kind of central directory, so I want test to compile a local copy of testlib and link with it (i.e. as if testlib was a subdirectory). I also want the "test" project to automatically rebuild "testlib" if it has been changed.
So, how can I deal with it? I am using CMake 2.8.4 on Windows XP SP3.
You could either provide a top-level CMakeLists.txt in root, or provide a binary directory to the add_subdirectory command; e.g.
add_subdirectory("../../libs/testlib" "${CMAKE_CURRENT_BINARY_DIR}/testlib_build")
This creates a subdirectory called testlib_build in your current build directory which contains the generated project files for testlib, but not the source.
For further info, run
cmake --help-command ADD_SUBDIRECTORY
The only way I see to do this - create CMakeLists.txt in root and put the following code there:
add_subdirectory(projects/test)
add_subdirectory(lib/testlib)
When you have done this, you can do target_link_libraries(test testlib) in test/CMakeLists.txt, and it will be automatically rebuilt if you change something in testlib.