I have a project A that uses some targets defined in project B. Hence I did add_subdirectory(<PATH_TO B> EXCLUDE_FROM_ALL) to include the subdirectory. Now, I create install targets using components and there are some install components in A that require targets from B too. But, due to EXCLUDE_FROM_ALL, the cmake_install.cmake for A does not include that of B. How should I approach this?
You can install specific targets defined in subdirectory CMakeLists.txt after cmake 3.13.
Before 3.13, user may use
add_subdirectory(path/to/sub_dir EXCLUDE_FROM_ALL)
target_link_libraries(your_target PRIVATE your_sub_dir_target)
...
install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/path/to/sub_dir/cmake_install.cmake)
with EXCLUDE_FROM_ALL, the your_sub_dir_target will not be included in the ALL target, then the install command will not be called for your sub_dir, you'll need to manually do it.
Related
I want anyone who cloned the repository can build it immediately, and don't need to install the dependencies.
Therefore, I found several ways:
Use git submodule and add_subdirectory.
Use find_package to find the built libraries and the headers.
The first one takes much time to build, so I think the second might be better. To make people be able to build the project instantly, I put the the files in the project, but it saied it doesn't know the linker language. What's this? And how to solve?
Direstories:
Project Root
lib
SDL2
(generated files when install)
include
(headers)
src
(sources)
CMakeLists.txt
CMakeLists.txt:
# ...
list(APPEND CMAKE_PREFIX_PATH lib)
find_package(SDL2)
# ...
My top-level CMake project depends on some-library, which I include into my project using
add_subdirectory (some-library)
and then link against it using
target_link_libraries (my-project PRIVATE some-library)
I also want to add install (TARGETS my-rpoject ...) directives so that my project can be installed to the system via whatever build system is generated (e.g. via sudo ninja install if using the -GNinja generator).
However, if some-library also defines some install (TARGETS some-library ...) directives, they get lumped in with the installation of my project's targets, which given a few subdirectory dependencies creates a bunch of extra, needless cruft in the system's installation directories which I'd like to avoid.
How can I get CMake to exclude any install (...) targets from submodules/dependency projects added with add_subdirectory () and keep only the ones in my top-level project?
At least as of CMake 3.0, add_subdirectory () has the EXCLUDE_FROM_ALL flag that can be added to the end of the call.
add_subdirectory (some-library EXCLUDE_FROM_ALL)
This removes all targets (including installation targets) from being evaluated at build time by the default rule, meaning they won't be built unless they are explicitly specified on the command line or are otherwise depended upon by a target that is included in the default rule.
Since your top-level project's targets are inherently included in the default rule (unless you create a custom target that also specifies EXCLUDE_FROM_ALL, for example), then passing EXCLUDE_FROM_ALL to add_subdirectory () and then linking against the dependency targets will automatically build any dependencies your project needs as you'd expect but omits install targets from the default install rule.
Therefore, all that remain are your own install() targets - none of your subdirectories'.
I use the ExtrenalProject cmake module to add 3rd party or internal dependencies to my build. I then use the CPack module with components to install only components from the current code base in the following manner.
set(CPACK_COMPONENTS_ALL
common-lib
common-include
common-depends
)
An example of one of these components declared in CMake is:
install(TARGETS common
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
COMPONENT common-lib
)
However, other projects added using add_subdirectory such as google test or other internal libraries also declare install targets. When I run
make package
and then list the contents of the .deb or .tar generated, I see the contents of other components not set in the CPACK_COMPONENTS_ALL variable.
What is the proper way to get CMake and CPack to only install the components requested?
You can just add the argument EXCLUDE_FROM_ALL to the end of the add_subdirectory() call. This will essentially disable all of the include() calls made in the added subdirectories.
I am facing the current problem while using CMake:
I have libA, which I build using CMake and install it (in a custom directory, ~/install, using CMAKE_PREFIX_PATH) together with its exported targets and config (generated by CMake). The installed files look more or less like this:
~/install/lib/libA.so
~/install/lib/cmake/AConfig.cmake
~/install/lib/cmake/ATargets.cmake
I have libB, which links (privately) against libA:
find_package(A CONFIG REQUIRED)
add_library(B b.c)
target_link_libraries(B PRIVATE A)
I also install it together with its exported targets and config (generated by CMake).
Finally, I have an application which uses libB:
find_package(B CONFIG REQUIRED)
add_executable(app app.c)
target_link_libraries(app B)
The problem is that when the linker is executed, it will link against libB using the full path (~/install/lib/libB.so), but libA is only linked with -lA. As the libraries are not installed in any "standard" folder, it is not found (unless I manually add the folder using link_directories).
Am I doing anything wrong? What is the best solution to handle this case?
Thanks,
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