Search code examples
cmakehierarchysiblingsfind-package

How to link against a target found by find_package() in a sibling CMakeLists.txt?


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)

Solution

  • 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)