I’ve run into this issue I don’t quite understand and was hoping someone could help clarify.
I have a simple header-only library (LibA) which is used by a static library (LibB) via FetchContent. I would like to install LibB and the have an application (App) bring it in via find_package.
The problem I’ve run into is App can find LibB, but it complains that:
Found package configuration file:
<path>/<to>/install/lib/cmake/LibB/LibB-config.cmake
but it set LibB_FOUND to FALSE so package "LibB" is
considered to be NOT FOUND. Reason given by package:
The following imported targets are referenced, but are missing: LibA::LibA.
When I run the install command it does look like the files for LibA are installed as well, so I’m not sure what I’m missing to get this to work as expected.
LibB references LibA in its target_link_libraries command (so it can be built on its own) but it seems this isn’t exported (whereas if it had also been brought in by find_package it would have been propagated as expected).
Is there an extra step I’m missing somewhere or is this simply not possible?
Thank you very much for your time,
Tom
Here’s an approximation of the CMakeLists.txt files for reference
Using your export file directly as your <projName>-config.cmake file is a common trap. It is fine for very simple projects that have no dependencies, but as you’ve discovered, once you have dependencies this no longer works. The pattern I normally recommend is to manually write your package’s config file and have it include() the export file(s) that you generate. You can then pull in your dependencies in your manually written package config file. For example:
The install command in your LibB project then installs to the name used above instead of to the config file directly (you also have to install the above file too):
(Since I think you’ve mentioned that you have my book previously, see Section 26.7.1: Config Files For CMake Projects which talks about this topic. For those who don’t have the book, you can download the slides from my CppCon 2019 talk which covers aspects of this and there are some bonus slides at the end which sketch out the steps in CMake code)
Note also how the above shows that using ${PROJECT_NAME} for something whose name can’t actually change without breaking things is a bit of an ant-pattern. The manually written libb-config.cmake file can’t use ${PROJECT_NAME} and anyone depending on your package is going to expect the package name to never change. It’s usually clearer to just use that name directly in the places you’ve used it in your example (your code will be more readable too).
Thank you so much for your detailed response! I really appreciate it I think I understand now (I’m going to have to re-read it a couple of times and map things back to my concrete use case). Hopefully I should be able to get things working by adding a new -config.cmake file as you suggest.
I do have your excellent book yes, I’ll make sure to check out the section you recommend (I’d re-read the FetchContent section and sections after but hadn’t been able to find what I was after unfortunately )
Thanks again and I’ll report back when things are working, hopefully with a link to the projects (might be tomorrow now as I’m on UK time).
@craig.scott One thing I wanted to clarify is should libb-config.cmake appear at the root of the project alongside CMakeLists.txt? I’ve just tried hooking things up now but when I run the install command I see…
My example is slightly more complicated than the example (the dependency chain contains a few more FetchContent commands) so I might need to fix things for earlier projects too…
Hmm I’m afraid I’m having real trouble getting that to work, it seems like the installed file ends with _Targets not -config if I do that so App can’t find the dependency LibB at all. Is there something else I need to do with a -config.in file? I don’t see any reference to _Targets in your book either. If you have any other suggestions I’d be very grateful to hear. Thank you!
I updated my previous reply - you have to install the libb-config.cmake file too. The book uses examples that have two export sets, not just one, so the exports to look for there are MyProj_Runtime and MyProj_Development. The book also uses the ProjNameConfig.cmake convention rather than projname-config.cmake, but either would be fine.
Thank you very much for the updated example @craig.scott, I’ve now got things working using this approach
One alternative approach I found is instead of writing and installing the libb-config.cmake file it’s possible to add find_dependency (or just find_package) with the name of the missing dependency (in this case LibA) to the AppCMakeLists.txt file and things also work (example below).
From a consumer (application developer) standpoint the version you outline is better as you just have to use find_package on the library you want, and it must have its dependencies exported correctly. But from a producer (library developer) standpoint having to write the additional -config.cmake file is a little bit of a pain. I’m curious if there’s a way to essentially ‘export’ the dependency directly from the CMakeLists.txt file itself of LibB? No worries if not I was just wondering
Thank you again very much for your help! I’ll aim to get things tidied up and will include a link to the libraries as an example when they’re done
All the best,
Tom
Update: Also I wanted to check this is also not technically required if everything in the dependency chain is found using find_package as opposed to FetchContent (or using add_submodule directly). I think that’s where my main confusion came from where it felt like it should work the same… but things are a bit different. Is that assumption correct? Thanks!
cmake_minimum_required(VERSION 3.15)
project(App LANGUAGES CXX)
include(CMakeFindDependencyMacro)
find_dependency(LibA) # this also works
find_package(LibB REQUIRED CONFIG)
add_executable(${PROJECT_NAME})
target_sources(
${PROJECT_NAME} PRIVATE main.cpp)
target_link_libraries(
${PROJECT_NAME} PRIVATE LibB::LibB)
I wanted to send an update with a link to the real-world projects I was having this issue with (which are now all working thanks to your help @craig.scott! )
This is the base project (a header-only library with no dependencies - a simple little toy math library of mine):
I’ve provided the ability for a user to pass the project name and the config name separately per your recommendation. It’s probably not perfect but it cuts out a ton of boilerplate from my projects for now which is nice!
I’ll see if I can write this up soon as a reference for others who might run into the same issue in future.
Also on one last somewhat unrelated note… why in the CMake docs does it say that using CMAKE_INSTALL_PREFIX with INSTALL_INTERFACE is wrong (it says it will not be relocatable - I might need to update my code if this is the case).
CMAKE_INSTALL_PREFIX is expected to be an absolute path, so if you force this to be your install location, it means you are hard-coding an absolute path for the install, which by definition makes it not relocatable. If you want your package to be relocatable, its install location should be a relative path and it will be treated as relative to whatever the install location is selected to be at install time (that will be CMAKE_INSTALL_PREFIX by default, but it can also be redirected by the user or whatever is driving the install - CPack explicitly overrides the install location when creating packages, for example).
I realized I was confusing CMAKE_INSTALL_INCLUDEDIR (and other CMAKE_INSTALL_<dir> variants) with CMAKE_INSTALL_PREFIX (More info here and here so I do think my install scripts are correct