c++buildcmakestatic-librariestarget

How to use find_package on a package added from top level add_subdirectory?


This might be an x y problem, so here's my situation.

Background


I have the following project structure:

-project
    -examples
        -example_that_uses_mylib_1
            * CMakeLists.txt
            * main.cpp
        -example_that_uses_mylib_2
            * CMakeLists.txt
            * main.cpp
    -external
        -notmylib_a
            * CMakeLists.txt
            * ... (other stuff)
        -notmylib_b
            * CMakeLists.txt
            * ... (other stuff)
    -src
        -mylib_stuff
            * file1.cpp
            * file1.h
        *CMakeLists.txt
    CMakeLists.txt

I'm attempting to make a cmake file that does the following:

I was unsure of how to do this until I saw this project whos top level cmake does this:

add_subdirectory(lib/foo)
add_subdirectory(src/bar)
add_subdirectory(src/baz)

and bar and baz CMakeLists.txt do this:

#Bar
find_package(foo 0.1.2 CONFIG REQUIRED)

#Baz
find_package(bar CONFIG REQUIRED)

Which made me think I could do the same with my libraries. I couldn't.

Originally the single top level CMakeLists.txt built all targets, I wanted to move away from this, and split up building with add_subdirectories, starting with mylib.

Problem


Originally my top level CMakeLists.txt looked a lot like this (which previously worked):

add_subdirectory(external/notmylib_a)
add_library(mylib STATIC src/mylib_stuff/file1.cpp)
target_include_directories(mylib PUBLIC src/)
target_link_libraries(mylib PRIVATE notmylib_a::notmylib_a)

when I decided to split things up so originally I did this (which also works):

#CMakeLists.txt
add_subdirectory(external/notmylib_a)


#src/CMakeLists.txt
add_library(mylib STATIC src/mylib_stuff/file1.cpp)
target_include_directories(mylib PUBLIC src/)
target_link_libraries(mylib PRIVATE notmylib_a::notmylib_a)

Then to follow the other project I decided to do this:

#CMakeLists.txt
add_subdirectory(external/notmylib_a)


#src/CMakeLists.txt
find_package(notmylib_a CONFIG REQUIRED) #NEW LINE!!
add_library(mylib STATIC src/mylib_stuff/file1.cpp)
target_include_directories(mylib PUBLIC src/)
target_link_libraries(mylib PRIVATE notmylib_a::notmylib_a)

and I got an error in CMAKE

CMake Error at src/CMakeLists.txt:25 (find_package):
  Could not find a package configuration file provided by "notmylib_a"
  with any of the following names:

    notmylib_aConfig.cmake
    notmylib_a-config.cmake

  Add the installation prefix of "notmylib_a" to CMAKE_PREFIX_PATH or set
  "notmylib_a_DIR" to a directory containing one of the above files.  If
  "notmylib_a" provides a separate development package or SDK, be sure it
  has been installed.

How was the other project able to utilize find_package in such a way?


Solution

  • How was the other project able to utilize find_package in such a way?

    Config file for other foo project has these lines checking for the target's existence :

    if(NOT TARGET foo::foo)
        include("${foo_CMAKE_DIR}/foo-targets.cmake")
    endif()
    

    That is, when the foo is included with add_subdirectory approach or via another method, and creates foo::foo target, find_package(foo) actually ignores its configuration file.

    This is noted in the foo's CMakeLists.txt:

    # We also add an alias definition so that we shadow
    # the export namespace when using add_subdirectory() instead.
    add_library(foo::foo ALIAS foo)
    

    In other words, with given foo package included with add_subdirectory approach, using find_package(foo) is possible, but optional: One may directly use foo or foo::foo target without any find_package().