find_package
will not automatically succeed if the project was added using add_subdirectory
.
If one of your third-party libraries relies on a find_package
call to find its dependencies, you will likely have to provide some help in the surrounding build script to ensure it will succeed.
Here is what happens in detail: When a project is pulled in via add_subdirectory
, its targets will become visible to the enclosing projects. That is, if subproject A
does add_library(a ...)
, then subproject B
can do target_link_libraries(b PUBLIC a)
to make use of library a
as a dependency for its own executable b
.
However, if both libraries are usually don't being built together as part of an enclosing project (which is almost always true for third party code), this is probably not what B
will be doing. Instead B
will probably do a find_package(A)
call and then use as a dependency whatever that find script provides. If you're lucky, the find script will provide an imported target, so you will find a call of the form target_link_libraries(b PUBLIC a)
somewhere in B
's CMakeLists.txt
. If it's an older find script, it may instead provide a bunch of variables and you will find calls like target_link_libraries(b ${A_LIBRARIES})
(and others for include directories and whatever else) instead.
So making this work really all depends on how B
's build scripts look like. If you're not at liberty to patch the build script, you might even end up in a situation where what you are asking for cannot be done.
Now, for the particular problem of the find_package
call: Find package is used to find a library that has already been built. That is, at the time that CMake runs, either a CMake config script or the library binaries are already on disk. In your scenario, neither of them have been generated, as you are still in the process of configuring the project, and those files won't get generated until you start building. So the find_package
call will almost certainly fail out of the box.
You have two options how to potentially resolve this:
- Have the enclosing project manually
set
all of the cache variables that the find_package
call is trying to fill in. That way any find_*
calls inside B
's package find script will turn into no-ops, simply reusing the values that you set.
- Provide your own find script and ensure that
B
's find_package
call will find that one instead of the one it would use in a standalone build.
Again, the specifics are highly project dependent, neither of these is guaranteed to be easy or to work at all. Also, ensuring that a build structured in this way remains portable across generators can be very challenging.
Bottom line: Unless you really have strong reasons for using add_subdirectory
, don't do this.
Instead have the enclosing project use a bunch of execute_process
calls to build each of the dependencies in isolation1. This will always work and is much easier to set up correctly. Main downside is that all the dependency building happens during the initial CMake configure run of the enclosing project and changes to the dependency's sources will not be tracked and trigger an automatic rebuild.
1: That is: First call cmake
and cmake --build
(and probably cmake --install
) on project A
; only then do the same for project B
. When configuring B
, provide the location information required for finding A
on the configure command line: cmake -DA_ROOT=...