5

I basically ask the same question as has been ask here. The question has however not been answered.

I want to use googletest in my project. For this I'm using ExternalProject_Add() which clones the testsuite with git. After that, I like to use add_subdirectory().

This is also what is described in the official repository. The nice thing about this approach is, that the build scripts in googletest handle the building process themself.

The problem is however, that add_subdirectory() can not find the source folder, since it does not exists from the start. Therefore, add_subdirectory() should depend on the completion of ExternalProject_Add().

Is is possible to make add_subdirectory() dependent of ExternalProject_Add(), like add_dependencies() does for targets?

PS. I can make it all compile if I comment add_subdirectory() out, build it (which ends with an error because the googletest library is missing), uncomment it and build it again (success).

ExternalProject_Add(
    googletest
    GIT_REPOSITORY  https://github.com/google/googletest.git
    GIT_TAG         master
    CONFIGURE_COMMAND ""
    BUILD_COMMAND     ""
    INSTALL_COMMAND   ""
    TEST_COMMAND      ""
    )

ExternalProject_Get_Property(googletest source_dir binary_dir)
set(GTEST_INCLUDE_DIR ${source_dir}/googletest/include)
set(GMOCK_INCLUDE_DIR ${source_dir}/googlemock/include)


add_subdirectory(${source_dir}
                 ${binary_dir})
RAM
  • 2,257
  • 2
  • 19
  • 41
dani
  • 3,677
  • 4
  • 26
  • 60
  • Projects added using `ExternalProject_Add()` are only downloaded at build time, IIRC. – tambre Jul 31 '17 at 12:06
  • 1
    [Here is](https://github.com/Gluttton/munkres-cpp/blob/devel/tests/CMakeLists.txt) complete work example with dependencies. – Gluttton Jul 31 '17 at 13:31
  • 2
    I don't feel comfortable making this an answer until I've tried it, but [FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) seems to be the CMake command you really want. It is new in 3.11. – John Sep 07 '18 at 16:16
  • @John, I think this is exactly the answer that deserves to be accepted. – dani Sep 07 '18 at 20:49
  • @John, I wonder if you could provide this as an answer, took me a while to find this solution. Thanks. – Bikineev Jul 24 '20 at 21:40
  • 1
    @dani and @Bikineev, I expanded my original answer to include more discussion and `FetchContent`. – John Jul 27 '20 at 11:49

2 Answers2

4

I used this tutorial to accomplish that. Just put your ExternalProject code in a separate file, say "CMakeLists.txt.dependencies" and then launch another cmake with execute_process. I use configure_file first to inject configuration information into the external project and to copy it into the build tree.

configure_file(CMakeLists.txt.dependency.in dependency/CMakeLists.txt)
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/dependency" )
execute_process(COMMAND "${CMAKE_COMMAND}" --build .
        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/dependency" )

Notice that the tutorial has the ExternalProject code in a separate CMakeLists.txt file. So does gtest official documentation. That is because ExternalProject runs at build-time, not configure time. This is a hack to use ExternalProject at configure time by putting it in a third project and executing a separate CMake+build run in the middle of your main CMake configuration step.

With version 3.11 CMake added a FetchContent command. I haven't used it, but the documentation makes it look like a configuration-time replacement for ExternalProject. That would fetch the content at configuration time, making it available for a later add_subdirectory command.

The ExternalProject and FetchContent commands will work fine for a small number of small and/or obscure dependencies. If your dependencies are more than 2, large, and/or popular, I recommend you look at a dependency manager like Conan. It partners with CMake quite well.

John
  • 7,301
  • 2
  • 16
  • 23
-2

You are not following the method correctly. There should only be ExternalProject_Add() as the final command in the CMakeLists.txt.in file.

The CMakeLists.txt.in file is called by the outer CMakeLists.txt file so that the subproject processing happens at configure time via execute_process(). CMakeLists.txt.in is acting as just a glorified downloader.

So, all other commands like add_subdirectory() are added to the outer CMakeLists.txt file.

utopia
  • 1,477
  • 8
  • 7