CMake ExternalProject_Add and parallel builds - c++

With the following CMakeLists.txt build script:
include( ExternalProject )
ExternalProject_Add( framework SOURCE_DIR ${framework_SOURCE}
PREFIX framework_build
INSTALL_DIR ${framework_DISTRIBUTION} )
...
add_library( ${PROJECT_NAME} SHARED ${BUILD_MANIFEST} )
add_dependencies( ${PROJECT_NAME} framework )
When I attempt to perform a parallel build (make -j5) it will occasionally fail due to a build artefact from the framework not being present. The order of the build, fixed by add_dependencies, is not being adhered to.
Have I misunderstood the documentation around add_dependencies?
Output from cmake --graphviz=graph.dot

Ok, so an updated version of CMake has warned me that the framework dependency is not present. ExternalProject_Add and add_dependencies can not be used with each other, as ExternalProject_Add has not actually built and therefore registered the framework as a high-level target.
Note:
Anyone encountering this problem in future. I've found another SO post by #matiu that resolved my issue.

Maybe ExternalProject_Add_StepDependencies could solve that and create a dependency between the externalproject_add and the imported target?

This is a minimal working example adding Google test as a dependency.
cmake_minimum_required(VERSION 2.8)
project(ExampleProject)
# Set the build type if it isn't already
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
include(ExternalProject)
set(GOOGLE_TEST GoogleTest)
set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/${GOOGLE_TEST}")
ExternalProject_Add(${GOOGLE_TEST}
GIT_REPOSITORY https://chromium.googlesource.com/external/googletest
PREFIX ${GTEST_PREFIX}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
INSTALL_COMMAND ""
)
# Specify include directory
ExternalProject_Get_Property(${GOOGLE_TEST} source_dir)
include_directories(${source_dir}/include)
set(LIBPREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}")
set(LIBSUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GTEST_LOCATION "${GTEST_PREFIX}/src/${GOOGLE_TEST}-build")
set(GTEST_LIBRARY "${GTEST_LOCATION}/${LIBPREFIX}gtest${LIBSUFFIX}")
set(EXECUTABLE_NAME ${CMAKE_PROJECT_NAME})
add_executable(${EXECUTABLE_NAME} main.cpp)
add_dependencies(${EXECUTABLE_NAME} ${GOOGLE_TEST})
target_link_libraries(
${EXECUTABLE_NAME}
${GTEST_LIBRARY}
-lpthread
)
enable_testing()
set(TEST_NAME ${EXECUTABLE_NAME})
add_test(${EXECUTABLE_NAME} ${TEST_NAME})
And this is the dependency graph:
In this case without add_dependencies a parallel build will always fail, because of missing the dependency.

Related

How to add Eigen library to a cmake c++ project via FetchContent

Adding Eigen via
FetchContent_Declare(
eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG 3.3.9
)
FetchContent_GetProperties(eigen)
if(NOT eigen_POPULATED)
FetchContent_Populate(eigen)
add_subdirectory(${eigen_SOURCE_DIR} ${eigen_BINARY_DIR})
endif()
find_package (Eigen3 3.3 REQUIRED NO_MODULE)
gives me the error
CMake Error at o/b/x64-Debug/_deps/eigen-build/Eigen3Config.cmake:20 (include):
The file
D:/XXX/o/b/x64-Debug/_deps/eigen-build/Eigen3Targets.cmake
was generated by the export() command. It may not be used as the argument
to the include() command. Use ALIAS targets instead to refer to targets by
alternative names. D:\XXX\o/b/x64-Debug/_deps/eigen-build/Eigen3Config.cmake 20
But downloading Eigen manually and adding it works fine
add_subdirectory("${PROJECT_SOURCE_DIR}/extern/eigen")
find_package (Eigen3 3.3 REQUIRED NO_MODULE)
Any ideas ?
In any order:
Eigen only provide ALIAS target on master
ref: https://gitlab.com/libeigen/eigen/-/commit/cf0b5b0344a3bfcf410e95bf22289015a2daf34b#9a2aa4db38d3115ed60da621e012c0efc0172aae_671_599
FetchContent usage could be
include(FetchContent)
FetchContent_Declare(
Eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG master
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE)
set(EIGEN_BUILD_DOC OFF)
# note: To disable eigen tests,
# you should put this code in a add_subdirectory to avoid to change
# BUILD_TESTING for your own project too since variables are directory
# scoped
set(BUILD_TESTING OFF)
set(EIGEN_BUILD_PKGCONFIG OFF)
set( OFF)
FetchContent_MakeAvailable(Eigen)
...
target_link_libraries(YourTarget PRIVATE Eigen3::Eigen)
For find_package() and FetchContent()/add_subdirectory() please see
https://gitlab.kitware.com/cmake/cmake/-/issues/17735
Alright i gave up on FetchContent, i also tried this Local install Eigen in CMAKE not finding target but this didn't work for me either.
I use ExternalProject now (https://github.com/qulacs/qulacs/blob/master/CMakeLists.txt) for fetching and linking eigen
include(ExternalProject)
set(EIGEN_BUILD_DIR ${CMAKE_BINARY_DIR}/eigen)
set(EIGEN_INSTALL_DIR ${CMAKE_SOURCE_DIR}/include/eigen3)
set(EIGEN_INCLUDE_DIR ${EIGEN_INSTALL_DIR})
ExternalProject_Add(
eigen
URL https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz
PREFIX ${EIGEN_BUILD_DIR}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND
${CMAKE_COMMAND} -E copy_directory ${EIGEN_BUILD_DIR}/src/eigen/Eigen ${EIGEN_INCLUDE_DIR}/Eigen
&& ${CMAKE_COMMAND} -E copy_directory ${EIGEN_BUILD_DIR}/src/eigen/unsupported ${EIGEN_INCLUDE_DIR}/unsupported
TEST_COMMAND ""
)
include_directories(SYSTEM ${EIGEN_INCLUDE_DIR})
Additionally add_dependencies has to be used
add_executable(test1 "test1.cpp")
add_dependencies(test1 eigen)
Fetchcontent is great, but it has the unwanted side-effect that your workspace becomes cluttered by all targets of your dependency. If you don't like this then ExternalProject_Add seems to be a reasonable solution. In your case the following should work:
include(ExternalProject)
set(EIGEN_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/eigen-install/")
ExternalProject_Add(
eigen
URL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/eigen-src"
BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/eigen-build"
INSTALL_DIR "${EIGEN_INSTALL_DIR}"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DCMAKE_BUILD_TYPE=Release
)
file(MAKE_DIRECTORY ${EIGEN_INSTALL_DIR}/include) # avoid race condition
add_library(eigenlib INTERFACE IMPORTED GLOBAL)
add_dependencies(eigenlib eigen)
target_compile_features(eigenlib INTERFACE cxx_std_14)
set_target_properties(eigenlib PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${EIGEN_INSTALL_DIR}/include/eigen3
)
Note that the dependecy is linked to an interface library eigenlib that you can subsequenly link to your own targets as follows:
add_library(linalg INTERFACE)
target_include_directories(linalg
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
target_link_libraries(linalg INTERFACE eigenlib)
I would like to expand on #Mizux's answer.
In their comment, there is a set( OFF) statement that does nothing. Also, to remove a CMake warning, you might need to do:
include(FetchContent)
FetchContent_Declare(
Eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG master
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(EIGEN_BUILD_DOC OFF)
set(EIGEN_BUILD_PKGCONFIG OFF)
FetchContent_MakeAvailable(Eigen)
This removes the warning for this policy change.

FetchContent vs ExternalProject

I am building a project with Cmake and use FetchContent to manage dependencies. For several reasons I cannot depend on system-wide installed packages, so this package helps a lot. It allows me to do things like this:
cmake_minimum_required(VERSION 3.14)
project(dummy LANGUAGES C CXX)
include(FetchContent)
FetchContent_Declare(nlohmann
GIT_REPOSITORY https://github.com/onavratil-monetplus/json
GIT_TAG v3.7.3
)
FetchContent_MakeAvailable(nlohmann)
add_executable(dummy main.cpp)
target_link_libraries(dummy PUBLIC nlohmann_json::nlohmann_json)
Now this works nicely as long as the repo is a cmake project with CMakeLists.txt. I would love to use similar approach for non-cmake projects, such as Botan library. Apparently
FetchContent_Declare(botan
GIT_REPOSITORY https://github.com/onavratil-monetplus/botan
GIT_TAG 2.17.2
)
FetchContent_MakeAvailable(botan)
does not really do the job, the build doesnt run since its not a cmake project. One would consider adding
CONFIGURE_COMMAND "<SOURCE_DIR>/configure.py --prefix=<BINARY_DIR>"
BUILD_COMMAND "cd <SOURCE_DIR> && make"
or something similar to the declare command, yet the FetchContent docs explicitly says that these particular arguments are ignored when passed to FetchContent.
Now the struggle is obvious - how to properly use FetchContent in this scenario? I was considering using ExternalProject_Add after the fetchcontent, yet then fetchcontent seems useless (ExternalProject can download git repo as well). Moreover, I would like to use some of the targets of botan at config time (if it makes sense).
I'm facing the same problem. Since the Botan library does not use the CMake build system internally, we cannot use the Botan "targets". But it is possible to build the Botan library at CMake configure time and use library and header files. Here is my solution (minimal configuration, works only for MS Visual Studio):
cmake_minimum_required (VERSION 3.20)
if(WIN32)
if(NOT (${CMAKE_BUILD_TYPE} STREQUAL "Release"))
message(FATAL_ERROR "This configuration only works for a Release build")
endif()
# set paths
set(BOTAN_LIB_ROOT_DIR "${CMAKE_SOURCE_DIR}/external/botan")
set(BOTAN_LIB_REPOS_DIR "${BOTAN_LIB_ROOT_DIR}/repos")
set(BOTAN_LIB_FCSTUFF_DIR "${BOTAN_LIB_ROOT_DIR}/cmake-fetchcontent-stuff")
set(BOTAN_LIB_INSTALL_DIR "${BOTAN_LIB_ROOT_DIR}-install")
# download and unpack Botan library
include(FetchContent)
FetchContent_Declare(
botan
GIT_REPOSITORY https://github.com/randombit/botan.git
GIT_TAG 2.19.1
PREFIX ${BOTAN_LIB_FCSTUFF_DIR}
SOURCE_DIR ${BOTAN_LIB_REPOS_DIR}
)
set(FETCHCONTENT_QUIET OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(botan)
# find Python3 Interpreter and run build, testing and installation
if(${botan_POPULATED} AND MSVC AND NOT EXISTS "${BOTAN_LIB_INSTALL_DIR}/lib/botan.lib")
find_package(Python3 COMPONENTS Interpreter)
if(NOT ${Python3_Interpreter_FOUND})
message(FATAL_ERROR "Python3 Interpreter NOT FOUND")
endif()
execute_process(
COMMAND ${Python3_EXECUTABLE} configure.py --cc=msvc --os=windows --prefix=${BOTAN_LIB_INSTALL_DIR}
WORKING_DIRECTORY ${BOTAN_LIB_REPOS_DIR}
COMMAND_ECHO STDOUT
)
execute_process(
COMMAND nmake
WORKING_DIRECTORY ${BOTAN_LIB_REPOS_DIR}
COMMAND_ECHO STDOUT
)
execute_process(
COMMAND nmake check
WORKING_DIRECTORY ${BOTAN_LIB_REPOS_DIR}
COMMAND_ECHO STDOUT
)
execute_process(
COMMAND nmake install
WORKING_DIRECTORY ${BOTAN_LIB_REPOS_DIR}
COMMAND_ECHO STDOUT
)
endif()
endif()
add_executable (main "main.cpp")
if(WIN32)
target_include_directories(main PUBLIC "${BOTAN_LIB_INSTALL_DIR}/include/botan-2")
target_link_libraries(main PUBLIC "${BOTAN_LIB_INSTALL_DIR}/lib/botan.lib")
configure_file("${BOTAN_LIB_INSTALL_DIR}/bin/botan.dll"
"${CMAKE_CURRENT_BINARY_DIR}/botan.dll"
COPYONLY
)
install(TARGETS main DESTINATION bin)
install(FILES "${BOTAN_LIB_INSTALL_DIR}/bin/botan.dll" DESTINATION bin)
endif()
Here is the full version: https://github.com/weenchvd/cmake-build-botan-lib

How to include cmake dependencies from source for static use

I'm currently writing an application which will make use of OpenCV and a few other dependencies using cmake. For the sake of the question only one dependency is relevant.
How can I construct a CmakeLists.txt file which downloads the OpenCV source from github and prepares it for static use within my application?
I have tried using ExternalProject_Add which looked promising until I realised the static libraries, etc are not available when they are needed (as far as i understand). I've had similar issues with FetchContent_Declare and related functions.
I understand I can build all my dependencies outside of the single CmakeLists.txt and use them with something like: find_package( OpenCV REQUIRED PATHS "${CMAKE_CURRENT_LIST_DIR}/../build/opencv" ). This works perfectly fine, however I'm hoping to have everything self contained within cmake so anyone that checks out my application wont have to do any special configuration or dependency fetching. Just cmake build and they would be ready to go.
Note:
I've tried many things and followed many blog posts over the past week to try and figure these things out. The post would be excruciatingly long if I were to document them all. At this point im very confused with how it should all work and im hoping someone can point out something obvious im missing.
I'm also aware i can use something like vcpkg instead of compiling these applications from source. Due to the dependencies not listed I am not going down this route.
Environment:
Windows 10
Visual Studio 2019
Cmake
CmakeLists.txt
cmake_minimum_required(VERSION 3.19)
# set the project name
project(test-depends)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set(CMAKE_DEBUG_POSTFIX d)
# Global settings
set(GLOBAL_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# dependencies
include(ExternalProject)
## other dependencies are here
# ......
## OpenCV contrib
ExternalProject_Add(opencv_contrib
GIT_REPOSITORY https://github.com/opencv/opencv_contrib.git
GIT_TAG 4.5.0
BUILD_COMMAND ""
CONFIGURE_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Get_Property(opencv_contrib SOURCE_DIR)
set(OPENCV_CONTRIB_SOURCE_DIR ${SOURCE_DIR})
# OpenCV
ExternalProject_Add(opencv
GIT_REPOSITORY https://github.com/opencv/opencv.git
GIT_TAG 4.5.0
DEPENDS opencv_contrib # other dependencies omitted
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${GLOBAL_OUTPUT_PATH}/opencv
-DBUILD_SHARED_LIBS=OFF
-DOPENCV_EXTRA_MODULES_PATH=${OPENCV_CONTRIB_SOURCE_DIR}/modules
-DINSTALL_CREATE_DISTRIB=ON
-DBUILD_EXAMPLES=OFF
-DWITH_CUDA=OFF
-DBUILD_DOCS=OFF
-DDENABLE_CXX11=ON
-DDBUILD_TESTS=OFF
-DBUILD_PERF_TESTS=OFF
)
ExternalProject_Get_Property(opencv SOURCE_DIR BINARY_DIR)
set(OPENCV_SOURCE_DIR ${SOURCE_DIR})
set(OPENCV_BINARY_DIR ${BINARY_DIR})
file(GLOB_RECURSE PROJECT_SOURCES "src/*.h" "src/*.cpp")
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
add_dependencies(${PROJECT_NAME} opencv)
include_directories(${GLOBAL_OUTPUT_PATH}/opencv/include)
target_link_directories( ${PROJECT_NAME}
PRIVATE ${OPENCV_BINARY_DIR}/lib
)
set(OpenCV_LIBS "ade;opencv_aruco450d;opencv_bgsegm450d;opencv_bioinspired450d;opencv_calib3d450d;opencv_ccalib450d;opencv_core450d;opencv_datasets450d;opencv_dnn450d;opencv_dnn_objdetect450d;opencv_dnn_superres450d;opencv_dpm450d;opencv_face450d;opencv_features2d450d;opencv_flann450d;opencv_fuzzy450d;opencv_gapi450d;opencv_hfs450d;opencv_highgui450d;opencv_imgcodecs450d;opencv_imgproc450d;opencv_img_hash450d;opencv_intensity_transform450d;opencv_line_descriptor450d;opencv_mcc450d;opencv_ml450d;opencv_objdetect450d;opencv_optflow450d;opencv_phase_unwrapping450d;opencv_photo450d;opencv_plot450d;opencv_quality450d;opencv_rapid450d;opencv_reg450d;opencv_rgbd450d;opencv_saliency450d;opencv_shape450d;opencv_stereo450d;opencv_stitching450d;opencv_structured_light450d;opencv_superres450d;opencv_surface_matching450d;opencv_text450d;opencv_tracking450d;opencv_video450d;opencv_videoio450d;opencv_videostab450d;opencv_xfeatures2d450d;opencv_ximgproc450d;opencv_xobjdetect450d;opencv_xphoto450d;")
target_link_libraries(
${PROJECT_NAME}
PRIVATE "${OpenCV_LIBS}"
)
src/main.cpp
#include <iostream>
#include "opencv2/opencv.hpp"
void main() {
cv::Mat testing;
std::cout << "hello" << std::endl;
}

Why does CMake not find GTest (Google Test)?

There is a ready project. In one of the cmake-files there is a source code:
find_package(GTest REQUIRED)
if (NOT GTest_FOUND)
message(FATAL_ERROR "Cannot find Google Test Framework!")
endif()
Gives an error: "Cannot find Google Test Framework!"
How to fix error?
The FindGTest.cmake file uses the environment variable GTEST_ROOT.
You can add this variable to your system or just add it to your CMakeLists.txt file:
set(GTEST_ROOT "c:/path/to/gtest/root" CACHE PATH "path to gtest").
This should solve your problem. It is of course possible to completely add gtest to a project (like Luis Miglietti suggested), but thats maybe not what you want to do as a first try.
This could be useful for you so you don't have to depend on a local google test install, this should work independently if you have google test installed in your machine
You can add this to your cmake file (you should take care of the proper linking / include depending on your project structure)
This will download google test, configure the installation and build it in vendor/gtm/gtest (you could always change this) inside your main build folder. Then you can link gtest to an executable so you can run your tests from there
include(ExternalProject)
find_package(Git REQUIRED)
# Build googletest
ExternalProject_Add(
googletest
PREFIX "vendor/gtm"
GIT_REPOSITORY "https://github.com/google/googletest.git"
GIT_TAG release-1.8.0
TIMEOUT 10
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
UPDATE_COMMAND ""
)
# Build gtest
ExternalProject_Add(
gtest_src
PREFIX "vendor/gtm"
SOURCE_DIR "vendor/gtm/src/googletest/googletest"
INSTALL_DIR "vendor/gtm/gtest"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/vendor/gtm/gtest
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
DOWNLOAD_COMMAND ""
UPDATE_COMMAND ""
)
# Prepare gtest
ExternalProject_Get_Property(gtest_src install_dir)
set(GTEST_INCLUDE_DIR ${install_dir}/include)
set(GTEST_LIBRARY_PATH ${install_dir}/lib/libgtest.a)
file(MAKE_DIRECTORY ${GTEST_INCLUDE_DIR})
add_library(gtest STATIC IMPORTED)
set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${GTEST_LIBRARY_PATH})
set_property(TARGET gtest APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIR})
add_dependencies(gtest_src googletest)
add_dependencies(gtest gtest_src)
Then you can link gtest to an executable with something like
add_executable(tester test/tester.cc)
target_link_libraries(tester gtest)
enable_testing()
add_test(<library> tester)
While CMake provides a FindGTest.cmake module since 2009...
I prefer to incorporate googletest in your CMake project like explaining in the googletest documentation.
https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
Note: a more detailed explanation http://crascit.com/2015/07/25/cmake-gtest/

How to clone and integrate external (from git) cmake project into local one

I faced with a problem when I was trying to use Google Test.
There are lot of manuals on how to use ExternalProject_Add for the adding gtest into the project, however most of these describe a method based on downloading zip archive with gtest and build it.
As we know gtest is github-hosted and cmake-based project. So I'd like to find native cmake way.
If this would be a header-only project, I'd write something like:
cmake_minimum_required(VERSION 2.8.8)
include(ExternalProject)
find_package(Git REQUIRED)
ExternalProject_Add(
gtest
PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/ext
GIT_REPOSITORY https://github.com/google/googletest.git
TIMEOUT 10
UPDATE_COMMAND ${GIT_EXECUTABLE} pull
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
ExternalProject_Get_Property(gtest source_dir)
set(GTEST_INCLUDE_DIR ${source_dir}/googletest/include CACHE INTERNAL "Path to include folder for GTest")
set(GTEST_ROOT_DIR ${source_dir}/googletest CACHE INTERNAL "Path to source folder for GTest")
include_directories(${INCLUDE_DIRECTORIES} ${GTEST_INCLUDE_DIR} ${GTEST_ROOT_DIR})
message(${GTEST_INCLUDE_DIR})
and add this script from my cmake project like:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/")
include(AddGTest)
....
add_dependencies(${PROJECT_NAME} gtest)
However this requires a build step.
How should this be implemented?
By adding BUILD_COMMAND into ExternaProject_Add and linking with produced libs?
Or by including gtest's cmakelists into my project, something like this:
add_subdirectory (${CMAKE_SOURCE_DIR}\ext\src\gtest\googletest\CMakeLists.txt)
this is not correct way because on the moment of the project load the folder does not exist.
Any other ways?
What is a correct/prefer way?
I would go with the first approach. You don't need to specify a build command because cmake is used by default. This could look like:
cmake_minimum_required(VERSION 3.0)
project(GTestProject)
include(ExternalProject)
set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/external)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION}
)
include_directories(${EXTERNAL_INSTALL_LOCATION}/include)
link_directories(${EXTERNAL_INSTALL_LOCATION}/lib)
add_executable(FirstTest main.cpp)
add_dependencies(FirstTest googletest)
target_link_libraries(FirstTest gtest gtest_main pthread)
I don't know if this is the correct/preferred way if there even is one. If you wanted to implement your second approach you would have to download the code with execute_process first.