[CMake] Ensuring an external project is built and installed before trying to call "find_package" on it

Craig Scott craig.scott at crascit.com
Sat Feb 23 02:32:07 EST 2019


On Sat, Feb 23, 2019 at 4:14 PM Timothy Wrona <tjwrona1992 at gmail.com> wrote:

> I am working on a CMake project that depends on a couple other projects I
> have previously written. I would like to include those other projects using
> "ExternalProject_Add", but I am having some issues.
>
> The basic layout of the project is this:
>
> cmake_minimum_required(VERSION 3.14.0)
>
> project(ProjectWithDependencies)
>
> include(ExternalProject)
> ExternalProject_Add(Dependency1
>     GIT_REPOSITORY <URL to git repo>
> )
> ExternalProject_Add(Dependency2
>     GIT_REPOSITORY <URL to git repo>
> )
>
> find_package(Dependency1 Required)
> find_package(Dependency2 Required)
>
> # Use targets
>
> I was under the assumption that "ExternalProject_Add" would automatically
> build and install the dependencies before getting to the "find_package"
> calls (they are CMake projects so the default build and install commands
> should be fine) but this doesn't seem to be how it works.
>
> When I get to "find_package" it fails because the dependency hasn't been
> installed yet.
>
> How can I ensure that the dependencies are fully compiled and installed
> before attempting to find them? (Note: FetchContent doesn't work here
> because the two projects "Dependency1" and "Dependency2" have targets with
> the same name which causes FetchContent to fail.)
>
> Any help is appreciated.
>

find_package() requires that the dependencies have been built already, as
you've noted. When CMake runs and processes your example CMakeLists.txt
file, it sets up the build rules for Dependency1 and Dependency2, but they
won't actually be configured, built and installed until you build the main
project. Since your find_package() calls will be processed during the
configure stage of the main project (i.e. before the build stage), it's too
early.

To address this, you need to make your main project a true superbuild where
it basically contains nothing more than a set of ExternalProject_Add()
calls. Rather than putting the find_package() calls and use of targets
directly in the main build, you can add it as another sub-build. Note that
this will mean that none of the targets you define in the mainBuild will be
visible as targets in your top level superbuild project. I'd also advise
you to override the default install location of your dependencies.
Otherwise they will typically try to install to a system-wide location,
which is not usually a good thing. Putting it together, the top level
superbuild project would look something like this:

cmake_minimum_required(VERSION 3.14.0)
project(ProjectWithDependencies)

set(installDir ${CMAKE_CURRENT_BINARY_DIR}/install)

include(ExternalProject)
ExternalProject_Add(Dependency1
    GIT_REPOSITORY <URL to git repo>
    INSTALL_DIR    ${installDir}
    CMAKE_ARGS     -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)
ExternalProject_Add(Dependency2
    GIT_REPOSITORY <URL to git repo>
    INSTALL_DIR    ${installDir}
    CMAKE_ARGS     -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)
ExternalProject_Add(mainBuild
    SOURCE_DIR  <path_to_some_subdir_in_this_repo>
    INSTALL_DIR ${installDir}
    DEPENDS     Dependency1 Dependency2
    CMAKE_ARGS  -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
                -DCMAKE_PREFIX_PATH:PATH=<INSTALL_DIR>
)

Or you could make the superbuild a completely separate repo and then use
GIT_REPOSITORY rather than SOURCE_DIR for the "mainBuild" part.

-- 
Craig Scott
Melbourne, Australia
https://crascit.com

Get the hand-book for every CMake user: Professional CMake: A Practical
Guide <https://crascit.com/professional-cmake/>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://cmake.org/pipermail/cmake/attachments/20190223/88fda536/attachment.html>


More information about the CMake mailing list