Add a dependency not in a subdirectory using CMake - 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.

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.

How can I include a header-only library with 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.

CMake subdirectory install/uninstall targets

I've got a project with two subdirectory projects (added with add_subdirectory), each with their own libraries, binaries and install/uninstall targets. So:
main_project
|
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with binary target, install()
|
|--project_a
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with library, install())
|
|--project_b
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with library, install())
I'd like for the top-level project (main_project) to automatically install the libraries a and b (included in main_project from target_link_libraries()). So, I'd like to be able to go:
cd main_project/build
cmake ..
make
sudo make install
and have the main_project binary and project_a/b libraries installed automatically. I've tried this:
main_project/src/CMakeLists.txt
...
install(FILES main project_a project_b DESTINATION bin
LIBRARY DESTINATION lib)
but a cmake .. results in
install TARGETS given target "project_a" which does not exist in this directory.
as expected.
I've also tried specifying a path:
main_project/src/CMakeLists.txt
...
install(FILES main ${CMAKE_SOURCE_DIR}/project_a/ ${CMAKE_SOURCE_DIR}/project_b DESTINATION bin
LIBRARY DESTINATION lib)
which also complains that project_a/b are not in this directory (also expected, I guess?)
I've also tried installing the libraries "manually" with the FILES option in install(), and that works just fine, but that seems very kludgy considering there are perfectly good install()s in the subprojects.
One additional issue: since project_a and project_b also have uninstall() custom targets, I can't add an uninstall target to the main_project without CMake complaining about the custom target already existing. When I try adding an uninstall directive to the top dir CMakeLists:
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
But, since my project_a has an uninstall directive, I get:
CMake Error at CMakeLists.txt:37 (add_custom_target):
add_custom_target cannot create target "uninstall" because another
target with the same name already exists. The existing target is a
custom target created in source directory "/main_project/project_a".
See documentation for policy CMP0002 for more details.
So, how do I install and uninstall the necessary library files from my subproject alongside my main_project?
I found the problem. I am adding the subdirectory I want to install with EXCLUDE_FROM_ALL such that it doesn't build everything in the subdirectory, only the library I need. That flag seems to prevent the subdirectory install() from happening. Perhaps ExternalProject_Add is indeed the best way to go here...
Also, RE overriding custom targets, this worked for me: http://public.kitware.com/pipermail/cmake/2011-July/045269.html

Build multiple cmake project at once

I've a directory and different subfolders, like this:
home
|
|-library1
|-library2
|
|-libraryn
Every subfolder contains a complete library that can compile by itself (every library has a different mantainer). In every subfolder there's a CMakeLists.txt that allows to compile the project.
I want to find a way to create a CMakeLists.txt on home folder, that calls compilation of every project, so after this I can simply call make on home folder (or wherever I call cmake) in order to have all libraries ready at once.
I'd like to avoid to put in CMakeLists.txt manually every project folder, because they are a lot.
How can I do it?
EDIT:
Simply using add_subdirectory does not work: as I've said, these are indipendent project. Some of them have same targets (like Example, doc etc) and when I add them with this command cmake returns an error saying that different CMakeFiles.txt's cannot have same targets. I'd like something like
for every folder
create build/projec folder
cd into that folder
call cmake for specific folder project.
Maybe it's more simple using a bash script, but I'd like to use cmake in order to compile these libraries also on other platforms rather than Linux.

CMake : Add subdirectories to custom target and adding custom target to VS solution

Using CMake, I am trying to this:
I need a custom build target (I know, I it can create it with custom_target), but I want it to get added to the visual studio solution. Now when I create a custom target I see the project file in the folder but it is not shown/added in the VS solution, when I open the VS solution in VS IDE.
I need to add subdirectories (which has CMakeLists.txt in them) to the custom target, so that these projects will get added to the custom target and when the custom target is build these projects will get build.
Basically another line of build like ALL_BUILD. When ALL_BUILD is build, only the projects (subdirectories) added to it will get build. When the custom target is build only the projects (subdirectories) added to the custom target will get build.
Is it possible to do something like this?
Thank you so much for your time and help!
--RC
You should be able to do that using add_custom_target and add_dependencies.
Say you have the following directory structure:
root
|--CMakeLists.txt
|--main.cc
|
|--one
| |--CMakeLists.txt
| |--main_one.cc
|
|--two
|--CMakeLists.txt
|--main_two.cc
Assuming you want the subdirectories "one" and "two" as the targets not included in ALL_BUILD, then the following should work:
Top-level CMakeLists.txt:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(test)
add_executable(primary main.cc)
add_subdirectory(one)
add_subdirectory(two)
add_custom_target(SecondaryAllBuild)
add_dependencies(SecondaryAllBuild one two)
CMakeLists.txt in "root/one" (for the CMakeLists.txt in "root/two", swap "one" for "two"):
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(secondary_one)
add_executable(one EXCLUDE_FROM_ALL main_one.cc)