11

I have static library Foo, static library Bar that depends on Foo and executable Baz that depends on Bar.

Relevant sections from Foo CMakeLists.txt:

# Specifying files to copy during "make install" command.
install(TARGETS Foo EXPORT FooConfig
    INCLUDES DESTINATION include
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)

# Specifying config file that will be used to find a library using find_package().
install(EXPORT FooConfig
    FILE FooConfig.cmake
    NAMESPACE Foo::
    DESTINATION lib/cmake/Foo)
export(TARGETS Foo
    NAMESPACE Foo::
    FILE FooConfig.cmake)

Relevant sections from Bar CMakeLists.txt:

# Specifying libraries that are required for build.
find_package(Foo REQUIRED)

# Specifying libraries to link to for the users of the library.
target_link_libraries(Bar PUBLIC Foo::Foo)

# Specifying files to copy during "make install" command.
install(TARGETS Bar EXPORT BarConfig
    INCLUDES DESTINATION include
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)

# Specifying config file that will be used to find a library using find_package().
install(EXPORT BarConfig
    FILE BarConfig.cmake
    NAMESPACE Bar::
    DESTINATION lib/cmake/Bar)
export(TARGETS Bar
    NAMESPACE Bar::
    FILE BarConfig.cmake)

And finally Baz CmakeLists.txt:

find_package(Bar REQUIRED)

target_link_libraries(Baz PRIVATE Bar::Bar)

Now when building Baz I get:

CMake Error at CMakeLists.txt:19 (add_executable):
  Target "Baz" links to target "Foo::Foo" but the
  target was not found.  Perhaps a find_package() call is missing for an
  IMPORTED target, or an ALIAS target is missing?

So build finds Bar and correctly determines that it depends on Foo but can't find Foo. I have another test project that directly depends on Foo and it builds fine. How to fix this?

1 Answers1

10

Unfortunately, BarConfig.cmake generated like this does not handle finding dependencies, I had to modify Bar CMakeLists.txt to this:

# Specifying files to copy during "make install" command.
install(TARGETS Bar EXPORT BarTargets
    INCLUDES DESTINATION include
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)
install(FILES CMake/BarConfig.cmake DESTINATION lib/cmake/Bar)

# Specifying config file that will be used to find a library using find_package().
install(EXPORT BarTargets
    FILE BarTargets.cmake
    NAMESPACE Bar::
    DESTINATION lib/cmake/Bar)
export(TARGETS Bar
    NAMESPACE Bar::
    FILE BarTargets.cmake)

Then I created a file CMake/BarConfig.cmake with this:

include("${CMAKE_CURRENT_LIST_DIR}/BarTargets.cmake")

find_package(Foo REQUIRED)

Now this BarConfig.cmake gets installed globally and calls find_package that finds Foo.

  • Great self-answer! The comments are a bit confusing: The first one appears to only apply to `BarConfig.cmake`, not `BarTargets.cmake`, but applies to both; the second one appears to only apply to `BarTargets.cmake`, not `BarConfig.cmake`, but it's actually the other way round. – Arthur Tacca Jul 30 '18 at 15:31
  • Instead of `find_package()` rather `find_dependency()` should be used, this properly forwards the `QUIET` and `REQUIRED` keywords. See [this answer](https://stackoverflow.com/a/50277897/3519749) for details. Don't forget to `include(CMakeFindDependencyMacro)`. – bselu Apr 05 '22 at 12:25