I have a hierarchy like this:
CMakeLists.txt # calls add_subdirectory() for subdirs in the listed order
+-deps
| +-CMakeLists.txt # calls find_package(Vulkan), a 3rd party lib, present on my system
+-mylib
| +-CMakeLists.txt # depends on Vulkan::Vulkan
| +-mylib.cpp
+-example
+-CMakeLists.txt # depends on Vulkan::Vulkan
+-example.cpp
The problem is that in mylib/CMakeLists.txt and example/CMakeLists.txt for the following command:
target_link_libraries(mylib PRIVATE Vulkan::Vulkan)
I got the following error:
CMake Error at mylib/CMakeLists.txt:2 (target_link_libraries):
Target "mylib" links to:
Vulkan::Vulkan
but the target was not found. Possible reasons include:
* There is a typo in the target name.
* A find_package call is missing for an IMPORTED target.
* An ALIAS target is missing.
And the same goes for example/CMakeLists.txt.
My question: How can I make those CMakeLists.txt files see the targets found by find_package() in their sibling CMakeLists.txt files?
What I tried:
I moved the find_package()
to the root CMakeLists.txt, and then everything worked. But I want to neatly organize my files. This is a strongly simplified version. The real hierarchy is much more complicated.
I found set(PARENT_SCOPE)
and was able to propagate the TRUE
value of ${Vulkan_FOUND}
from deps to root and then to example. Maybe something similar is needed but for targets instead of variables?
Details:
./CMakeLists.txt:
cmake_minimum_required(VERSION 3.6...3.22)
project(mylib VERSION 0.0.1)
add_subdirectory(deps)
add_subdirectory(mylib)
add_subdirectory(example)
./deps/CMakeLists.txt:
find_package(Vulkan)
./mylib/CMakeLists.txt:
add_library(mylib mylib.cpp)
target_link_libraries(mylib PUBLIC Vulkan::Vulkan)
./example/CMakeLists.txt:
add_executable(example example.cpp)
target_link_libraries(example PUBLIC mylib Vulkan::Vulkan)
In CMake find_package
usage is expected to be local to the directory and its descendants. If some other directory (from other hierarchy) needs the same package, then it should repeat find_package
call.
Concerning specifically "deps" functionality, I saw many projects which move this functionality into a separate .cmake
script, and include that script via include()
command in the root CMakeLists.txt
. Wherever the included .cmake
script is located, the include
command does NOT introduce a directory scope.
So, every find_package
call from that script is scoped to the root CMakeLists.txt
, so its results can be used in any subdirectory.
./cmake/deps.cmake
:
find_package(Vulkan)
./CMakeLists.txt
:
cmake_minimum_required(VERSION 3.6...3.22)
project(mylib VERSION 0.0.1)
# Specify directory where included scripts will be searched.
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(deps)
add_subdirectory(mylib)
add_subdirectory(example)