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.
Related
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
I'm trying to download externally the mongo-cxx-driver on Windows from the given github repositories, but unfortunately my knowledge of cmake is less to none. I found the next given script in one of the stackoverflow questions: Building mongo-cxx-driver using CMake ExternalProject_Add, but even when it seems to work, it doesn't work. It does make the given project but without the libraries. May someone help with creating those libraries through cmake, externally or internally after downloading the mongo-c-driver and the mongo-cxx-driver from the github repositories.
If someone could go through the needed steps I'd be delighted.
Also if boost could be removed from this equation, it would be good.
The CMakeLists.txt file:
cmake_minimum_required(VERSION 3.12)
set(CMAKE_CXX_STANDARD 11)
project(Test)
option(${PROJECT_NAME}_SUPERBUILD "Build ${PROJECT_NAME} and the projects it depends on." ON)
if(${PROJECT_NAME}_SUPERBUILD)
include(ExternalProject)
set(common_cmake_cache_args
-DCMAKE_CXX_COMPILER:PATH=${CMAKE_CXX_COMPILER}
)
if(NOT DEFINED CMAKE_CONFIGURATION_TYPES)
list(APPEND common_cmake_cache_args
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
)
endif()
ExternalProject_Add(libmongoc
GIT_REPOSITORY "https://github.com/mongodb/mongo-c-driver.git"
GIT_TAG "1.16.2"
GIT_PROGRESS 1
GIT_SHALLOW 1
SOURCE_DIR "${CMAKE_BINARY_DIR}/libmongoc"
BINARY_DIR "${CMAKE_BINARY_DIR}/libmongoc-build"
INSTALL_DIR "${CMAKE_BINARY_DIR}/libmongoc-install"
CMAKE_CACHE_ARGS
${common_cmake_cache_args}
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/libmongoc-install
-DENABLE_TESTS:BOOL=OFF
-DENABLE_STATIC:BOOL=OFF
-DENABLE_EXAMPLES:BOOL=OFF
-DENABLE_EXTRA_ALIGNMENT:BOOL=OFF
#INSTALL_COMMAND ""
)
set(libmongoc-1.0_DIR "${CMAKE_BINARY_DIR}/libmongoc-install/lib/cmake/libmongoc-1.0/")
set(libbson-1.0_DIR "${CMAKE_BINARY_DIR}/libmongoc-install/lib/cmake/libbson-1.0/")
ExternalProject_Add(libmongocxx
GIT_REPOSITORY "https://github.com/mongodb/mongo-cxx-driver.git"
GIT_TAG "r3.4.2"
GIT_PROGRESS 1
GIT_SHALLOW 1
SOURCE_DIR "${CMAKE_BINARY_DIR}/libmongocxx"
BINARY_DIR "${CMAKE_BINARY_DIR}/libmongocxx-build"
INSTALL_DIR "${CMAKE_BINARY_DIR}/libmongocxx-install"
CMAKE_CACHE_ARGS
${common_cmake_cache_args}
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/libmongocxx-install
-DBUILD_SHARED_LIBS:BOOL=ON
-DENABLE_TESTS:BOOL=OFF
-DENABLE_EXAMPLES:BOOL=OFF
-DBSONCXX_POLY_USE_BOOST:BOOL=OFF
-DBSONCXX_POLY_USE_MNMLSTC:BOOL=ON
-DBSONCXX_POLY_USE_STD:BOOL=OFF
-Dlibmongoc-1.0_DIR:PATH=${libmongoc-1.0_DIR}
-Dlibbson-1.0_DIR:PATH=${libbson-1.0_DIR}
DEPENDS
libmongoc
)
set(libmongocxx_DIR "${CMAKE_BINARY_DIR}/libmongocxx-install/lib/cmake/libmongocxx-3.4.2/")
set(libbsoncxx_DIR "${CMAKE_BINARY_DIR}/libmongocxx-install//lib/cmake/libbsoncxx-3.4.2/")
function(ExternalProject_AlwaysConfigure proj)
# This custom external project step forces the configure and later
# steps to run.
_ep_get_step_stampfile(${proj} "configure" stampfile)
ExternalProject_Add_Step(${proj} forceconfigure
COMMAND ${CMAKE_COMMAND} -E remove ${stampfile}
COMMENT "Forcing configure step for '${proj}'"
DEPENDEES build
ALWAYS 1
)
endfunction()
ExternalProject_Add(${PROJECT_NAME}
SOURCE_DIR "${CMAKE_SOURCE_DIR}"
BINARY_DIR "${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build"
DOWNLOAD_COMMAND ""
UPDATE_COMMAND ""
CMAKE_CACHE_ARGS
${common_cmake_cache_args}
-D${PROJECT_NAME}_SUPERBUILD:BOOL=OFF
-Dlibbsoncxx_DIR:PATH=${libbsoncxx_DIR}
-Dlibmongocxx_DIR:PATH=${libmongocxx_DIR}
INSTALL_COMMAND ""
DEPENDS
libmongocxx
)
ExternalProject_AlwaysConfigure(${PROJECT_NAME})
return()
endif()
message(STATUS "Configuring inner-build")
find_package(libmongocxx REQUIRED)
add_executable(test_mongocxx test.cpp)
target_link_libraries(test_mongocxx PUBLIC ${LIBMONGOCXX_LIBRARIES})
target_include_directories(test_mongocxx PUBLIC ${LIBMONGOCXX_INCLUDE_DIRS})
target_compile_definitions(test_mongocxx PUBLIC ${LIBMONGOCXX_DEFINITIONS})
I am trying to build mongo-cxx-driver in a CMake based project. This project is supposed to build on Windows, macOS and in an ubuntu container and I want to ensure that my software on all these platforms will use the same driver version so I cannot afford installing the driver and its dependencies via apt-get, brew etc. So I am left with one option: ExternalProject_Add. But I am having difficulty making that work given how libmongoc is setup.
Below is the CMake module I currently have.
include(ExternalProject)
set(libmongoc_CMAKE_ARGS
"-DCMAKE_BUILD_TYPE:STRIING=${CMAKE_BUILD_TYPE}"
"-DENABLE_TESTS:BOOL=OFF"
"-DENABLE_STATIC:BOOL=OFF"
"-DENABLE_EXAMPLES:BOOL=OFF"
"-DENABLE_EXTRA_ALIGNMENT:BOOL=OFF"
)
set(mongocxx_CMAKE_ARGS
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_BUILD_TYPE:STRIING=${CMAKE_BUILD_TYPE}"
"-DBUILD_SHARED_LIBS:BOOL=ON"
"-DENABLE_TESTS:BOOL=OFF"
"-DENABLE_EXAMPLES:BOOL=OFF"
"-DBSONCXX_POLY_USE_BOOST:BOOL=ON"
"-DBSONCXX_POLY_USE_MNMLSTC:BOOL=OFF"
"-Dlibbson-1.0_DIR:PATH=${OTS_DEPDENDENCIES_DIR}/libmongoc/src/libbson"
)
if (NOT TARGET libmongoc)
ExternalProject_Add(
libmongoc
GIT_REPOSITORY "https://github.com/mongodb/mongo-c-driver.git"
GIT_TAG "1.12.0"
SOURCE_DIR "${OTS_DEPDENDENCIES_DIR}/libmongoc"
BINARY_DIR "${OTS_DEPDENDENCIES_DIR}/libmongoc"
CMAKE_ARGS "${libmongoc_CMAKE_ARGS}"
INSTALL_COMMAND ""
)
endif()
if (NOT TARGET mongocxx)
ExternalProject_Add(
mongocxx
GIT_REPOSITORY "https://github.com/mongodb/mongo-cxx-driver.git"
GIT_TAG "r3.3.1"
SOURCE_DIR "${OTS_DEPDENDENCIES_DIR}/mongocxx"
BINARY_DIR "${OTS_DEPDENDENCIES_DIR}/mongocxx"
CMAKE_ARGS "${mongocxx_CMAKE_ARGS}"
INSTALL_COMMAND ""
DEPENDS libmongoc
)
endif()
Note the CMAKE option libbson-1.0_DIR given as one of the CMAKE_ARGS for mongo-cxx-driver. I am skeptic about it and I believe that may be the culprit. With it I get the following error:
CMake Error at ${OTS_DEPENDENCIES_DIR}/libmongoc/src/libbson/libbson-1.0-config.cmake:30 (message):
File or directory
${OTS_DEPENDENCIES_DIR}/include/libbson-1.0
referenced by variable BSON_INCLUDE_DIRS does not exist !
Call Stack (most recent call first):
${OTS_DEPENDENCIES_DIR}/libmongoc/src/libbson/libbson-1.0-config.cmake:46 (set_and_check)
src/bsoncxx/CMakeLists.txt:81 (find_package)
which kind of makes sense because src/bsoncxx/CMakeLists.txt:81 reads:
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
set_and_check (BSON_INCLUDE_DIRS "${PACKAGE_PREFIX_DIR}/include/libbson-1.0")
which makes CMake end up looking for libbson-1.0 in ${OTS_DEPDENDENCIES_DIR}/include that does not exist. If only, I could tell cmake, "hey don't run this find_package" I can give you the path to INCLUDE_DIR, LIBRARIES and DEFINITIONS myself.
If I remove this option, I get the following error:
CMake Error at src/bsoncxx/CMakeLists.txt:81 (find_package):
By not providing "Findlibbson-1.0.cmake" in CMAKE_MODULE_PATH this project
has asked CMake to find a package configuration file provided by
"libbson-1.0", but CMake did not find one.
Could not find a package configuration file provided by "libbson-1.0"
(requested version 1.10.0) with any of the following names:
libbson-1.0Config.cmake
libbson-1.0-config.cmake
Add the installation prefix of "libbson-1.0" to CMAKE_PREFIX_PATH or set
"libbson-1.0_DIR" to a directory containing one of the above files. If
"libbson-1.0" provides a separate development package or SDK, be sure it
has been installed.
which is not very odd either because CMake tries to find_package libbson-1.0 but cannot figure out where it is installed.
preliminary remarks
While looking at the details, here are few preliminary comments:
Use different directory for SOURCE_DIR and BINARY_DIR
Instead of CMAKE_ARG, prefer CMAKE_CACHE_ARGS
libbson-1.0_DIR should NOT be set to a source directory, instead if should be set to a build directory containing a config-file package (link below provide more details about this concept)
Make sure to always specify the type of CMake argument (-DCMAKE_CXX_COMPILER:PATH=${CMAKE_CXX_COMPILER} instead of -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
Do not set CMAKE_BUILD_TYPE for multi-configuration generator
Regarding this last point, this means that you should do the following:
set(EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS)
if(NOT DEFINED CMAKE_CONFIGURATION_TYPES)
list(APPEND EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
)
endif()
In this post, you can learn how you could structure your project: Correct way to use third-party libraries in cmake project
working project allowing to compile the mongocxx "test.cpp"
Below is the content of CMakeLists.txt and test.cpp allowing to build an executable named <build-dir>/Test-build/test_mongocxx :
CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
set(CMAKE_CXX_STANDARD 11)
project(Test)
option(${PROJECT_NAME}_SUPERBUILD "Build ${PROJECT_NAME} and the projects it depends on." ON)
if(${PROJECT_NAME}_SUPERBUILD)
include(ExternalProject)
set(common_cmake_cache_args
-DCMAKE_CXX_COMPILER:PATH=${CMAKE_CXX_COMPILER}
)
if(NOT DEFINED CMAKE_CONFIGURATION_TYPES)
list(APPEND common_cmake_cache_args
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
)
endif()
ExternalProject_Add(libmongoc
GIT_REPOSITORY "https://github.com/mongodb/mongo-c-driver.git"
GIT_TAG "1.12.0"
GIT_PROGRESS 1
GIT_SHALLOW 1
SOURCE_DIR "${CMAKE_BINARY_DIR}/libmongoc"
BINARY_DIR "${CMAKE_BINARY_DIR}/libmongoc-build"
INSTALL_DIR "${CMAKE_BINARY_DIR}/libmongoc-install"
CMAKE_CACHE_ARGS
${common_cmake_cache_args}
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/libmongoc-install
-DENABLE_TESTS:BOOL=OFF
-DENABLE_STATIC:BOOL=OFF
-DENABLE_EXAMPLES:BOOL=OFF
-DENABLE_EXTRA_ALIGNMENT:BOOL=OFF
#INSTALL_COMMAND ""
)
set(libmongoc-1.0_DIR "${CMAKE_BINARY_DIR}/libmongoc-install/lib/cmake/libmongoc-1.0/")
set(libbson-1.0_DIR "${CMAKE_BINARY_DIR}/libmongoc-install/lib/cmake/libbson-1.0/")
ExternalProject_Add(libmongocxx
GIT_REPOSITORY "https://github.com/mongodb/mongo-cxx-driver.git"
GIT_TAG "r3.3.1"
GIT_PROGRESS 1
GIT_SHALLOW 1
SOURCE_DIR "${CMAKE_BINARY_DIR}/libmongocxx"
BINARY_DIR "${CMAKE_BINARY_DIR}/libmongocxx-build"
INSTALL_DIR "${CMAKE_BINARY_DIR}/libmongocxx-install"
CMAKE_CACHE_ARGS
${common_cmake_cache_args}
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/libmongocxx-install
-DBUILD_SHARED_LIBS:BOOL=ON
-DENABLE_TESTS:BOOL=OFF
-DENABLE_EXAMPLES:BOOL=OFF
-DBSONCXX_POLY_USE_BOOST:BOOL=OFF
-DBSONCXX_POLY_USE_MNMLSTC:BOOL=ON
-DBSONCXX_POLY_USE_STD:BOOL=OFF
-Dlibmongoc-1.0_DIR:PATH=${libmongoc-1.0_DIR}
-Dlibbson-1.0_DIR:PATH=${libbson-1.0_DIR}
DEPENDS
libmongoc
)
set(libmongocxx_DIR "${CMAKE_BINARY_DIR}/libmongocxx-install/lib/cmake/libmongocxx-3.3.1/")
set(libbsoncxx_DIR "${CMAKE_BINARY_DIR}/libmongocxx-install//lib/cmake/libbsoncxx-3.3.1/")
function(ExternalProject_AlwaysConfigure proj)
# This custom external project step forces the configure and later
# steps to run.
_ep_get_step_stampfile(${proj} "configure" stampfile)
ExternalProject_Add_Step(${proj} forceconfigure
COMMAND ${CMAKE_COMMAND} -E remove ${stampfile}
COMMENT "Forcing configure step for '${proj}'"
DEPENDEES build
ALWAYS 1
)
endfunction()
ExternalProject_Add(${PROJECT_NAME}
SOURCE_DIR "${CMAKE_SOURCE_DIR}"
BINARY_DIR "${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build"
DOWNLOAD_COMMAND ""
UPDATE_COMMAND ""
CMAKE_CACHE_ARGS
${common_cmake_cache_args}
-D${PROJECT_NAME}_SUPERBUILD:BOOL=OFF
-Dlibbsoncxx_DIR:PATH=${libbsoncxx_DIR}
-Dlibmongocxx_DIR:PATH=${libmongocxx_DIR}
INSTALL_COMMAND ""
DEPENDS
libmongocxx
)
ExternalProject_AlwaysConfigure(${PROJECT_NAME})
return()
endif()
message(STATUS "Configuring inner-build")
find_package(libmongocxx REQUIRED)
add_executable(test_mongocxx test.cpp)
target_link_libraries(test_mongocxx PUBLIC ${LIBMONGOCXX_LIBRARIES})
target_include_directories(test_mongocxx PUBLIC ${LIBMONGOCXX_INCLUDE_DIRS})
target_compile_definitions(test_mongocxx PUBLIC ${LIBMONGOCXX_DEFINITIONS})
test.cpp (copied from https://mongodb.github.io/mongo-cxx-driver/mongocxx-v3/installation/#step-6-test-your-installation):
#include <iostream>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
int main(int, char**) {
mongocxx::instance inst{};
mongocxx::client conn{mongocxx::uri{}};
bsoncxx::builder::stream::document document{};
auto collection = conn["testdb"]["testcollection"];
document << "hello" << "world";
collection.insert_one(document.view());
auto cursor = collection.find({});
for (auto&& doc : cursor) {
std::cout << bsoncxx::to_json(doc) << std::endl;
}
}
I'm trying to create a superbuild to compile the dependencies (zlib, nifticlib and boost) and then compile my project, depending on all these libraries.
Here is my CMakeLists:
cmake_minimum_required(VERSION 3.6)
project(CMakeTest)
#-----------------------------------------------------------------------------
# Build options
#-----------------------------------------------------------------------------
option(BUILD_MYPROJECT "Build MYPROJECT." ON)
#-----------------------------------------------------------------------------
# Git protocole option
#-----------------------------------------------------------------------------
option(USE_GIT_PROTOCOL "If behind a firewall turn this off to use http instead." OFF)
set(git_protocol "git")
if(NOT USE_GIT_PROTOCOL)
set(git_protocol "https")
endif()
#-----------------------------------------------------------------------------
# Enable and setup External project global properties
#-----------------------------------------------------------------------------
include(ExternalProject)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
#-----------------------------------------------------------------------------
# Zlib
#-----------------------------------------------------------------------------
message(STATUS "Installing Zlib library.")
ExternalProject_Add(Zlib
SOURCE_DIR "${PROJECT_BINARY_DIR}/deps/zlib"
BINARY_DIR "${PROJECT_BINARY_DIR}/deps/zlib-build"
INSTALL_DIR "${PROJECT_BINARY_DIR}/deps/zlib-install"
GIT_REPOSITORY "${git_protocol}://github.com/madler/zlib.git"
GIT_TAG "50893291621658f355bc5b4d450a8d06a563053d"
CMAKE_ARGS
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DCMAKE_BIN_DIR:PATH=<INSTALL_DIR>/bin
-DINSTALL_INC_DIR:PATH=<INSTALL_DIR>/include
-DINSTALL_LIB_DIR:PATH=<INSTALL_DIR>/lib
-DINSTALL_MAN_DIR:PATH=<INSTALL_DIR>/share/man
-DINSTALL_PKGCONFIG_DIR:PATH=<INSTALL_DIR>/share/pkgconfig)
if(WIN32)
set(ZLIB_LIB_BASE_NAME "zlibstatic")
set(ZLIB_LIB_NAME_RELEASE "${CMAKE_STATIC_LIBRARY_PREFIX}${ZLIB_LIB_BASE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(ZLIB_LIB_NAME_DEBUG "${CMAKE_STATIC_LIBRARY_PREFIX}${ZLIB_LIB_BASE_NAME}d${CMAKE_STATIC_LIBRARY_SUFFIX}")
elseif(UNIX)
set(ZLIB_LIB_BASE_NAME "z")
set(ZLIB_LIB_NAME_RELEASE "${CMAKE_STATIC_LIBRARY_PREFIX}${ZLIB_LIB_BASE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(ZLIB_LIB_NAME_DEBUG "${CMAKE_STATIC_LIBRARY_PREFIX}${ZLIB_LIB_BASE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
else()
# MacOSX
endif()
ExternalProject_Get_Property(Zlib install_dir)
set(ZLIB_LIBRARY_DIR ${install_dir}/lib)
set(ZLIB_INCLUDE_DIR ${install_dir}/include)
set(ZLIB_BINARY_DIR ${install_dir}/bin)
add_library(zlib STATIC IMPORTED)
set_target_properties(zlib PROPERTIES IMPORTED_LOCATION_DEBUG "${ZLIB_LIBRARY_DIR}/${ZLIB_LIB_NAME_DEBUG}")
set_target_properties(zlib PROPERTIES IMPORTED_LOCATION_RELEASE "${ZLIB_LIBRARY_DIR}/${ZLIB_LIB_NAME_RELEASE}")
#-----------------------------------------------------------------------------
# Niftilib
#-----------------------------------------------------------------------------
message(STATUS "Installing Nifti library.")
ExternalProject_Add(Nifticlib
SOURCE_DIR "${PROJECT_BINARY_DIR}/deps/nifticlib"
BINARY_DIR "${PROJECT_BINARY_DIR}/deps/nifticlib-build"
INSTALL_DIR "${PROJECT_BINARY_DIR}/deps/nifticlib-install"
GIT_REPOSITORY "${git_protocol}://gitlab.com/slckr/nifticlib.git"
GIT_TAG "e26a94e947c210104223f9f49737392c742c1c5b"
CMAKE_ARGS
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DZLIB_INCLUDE_DIR:PATH=${ZLIB_INCLUDE_DIR}
-DZLIB_LIBRARY_DEBUG:PATH=${ZLIB_LIBRARY_DIR}/${ZLIB_LIB_NAME_DEBUG}
-DZLIB_LIBRARY_RELEASE:PATH=${ZLIB_LIBRARY_DIR}/${ZLIB_LIB_NAME_RELEASE}
DEPENDS Zlib)
set(NIFTIIO_LIB_BASE_NAME "niftiio")
set(NIFTIIO_LIB_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}${NIFTIIO_LIB_BASE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(NIFTICDF_LIB_BASE_NAME "nifticdf")
set(NIFTICDF_LIB_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}${NIFTICDF_LIB_BASE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(ZNZ_LIB_BASE_NAME "znz")
set(ZNZ_LIB_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}${ZNZ_LIB_BASE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
ExternalProject_Get_Property(Nifticlib install_dir)
set(NIFTI_LIBRARY_DIR ${install_dir}/lib)
set(NIFTI_INCLUDE_DIR ${install_dir}/include/nifti)
set(NIFTI_BINARY_DIR ${install_dir}/bin)
add_library(niftiio STATIC IMPORTED)
set_target_properties(niftiio PROPERTIES IMPORTED_LOCATION "${NIFTI_LIBRARY_DIR}/${NIFTIIO_LIB_NAME}")
add_library(nifticdf STATIC IMPORTED)
set_target_properties(nifticdf PROPERTIES IMPORTED_LOCATION "${NIFTI_LIBRARY_DIR}/${NIFTICDF_LIB_NAME}")
add_library(znz STATIC IMPORTED)
set_target_properties(znz PROPERTIES IMPORTED_LOCATION "${NIFTI_LIBRARY_DIR}/${ZNZ_LIB_NAME}")
#-----------------------------------------------------------------------------
# Boost
#-----------------------------------------------------------------------------
message(STATUS "Installing Boost library.")
set(BOOST_BOOTSTRAP_COMMAND)
if(WIN32)
set(BOOST_BOOTSTRAP_COMMAND bootstrap.bat)
set(BOOST_B2_COMMAND b2.exe)
elseif(UNIX )
set(BOOST_BOOTSTRAP_COMMAND ./bootstrap.sh)
set(BOOST_B2_COMMAND ./b2)
else()
# MacOSX
set(BOOST_BOOTSTRAP_COMMAND ./bootstrap.sh)
set(BOOST_B2_COMMAND ./b2)
endif()
set(BOOST_BUILD_TYPE variant=release)
if (${CMAKE_BUILD_TYPE} MATCHES Debug)
set(BOOST_BUILD_TYPE variant=debug)
endif(${CMAKE_BUILD_TYPE} MATCHES Debug)
set(BOOST_INSTALL_DIR ${PROJECT_BINARY_DIR}/deps/boost-install)
ExternalProject_Add(boost
SOURCE_DIR "${PROJECT_BINARY_DIR}/deps/boost"
BUILD_IN_SOURCE 1
GIT_REPOSITORY "${git_protocol}://github.com/boostorg/boost"
GIT_TAG "5ec478a570bdc71c5d4854e7165a8b3f4fa82ad9"
CONFIGURE_COMMAND ${BOOST_BOOTSTRAP_COMMAND}
BUILD_COMMAND ${BOOST_B2_COMMAND} headers COMMAND ${BOOST_B2_COMMAND} install
link=static
${BOOST_BUILD_TYPE}
--prefix=${BOOST_INSTALL_DIR}
--with-filesystem
--with-program_options
--with-system
--with-thread
-j8
INSTALL_COMMAND ""
)
if(WIN32)
set(BOOST_LIBRARY_DIR ${BOOST_INSTALL_DIR}/lib/boost)
set(BOOST_INCLUDE_DIR ${BOOST_INSTALL_DIR}/include/boost-1_65)
else()
set(BOOST_LIBRARY_DIR ${BOOST_INSTALL_DIR}/lib/boost)
set(BOOST_INCLUDE_DIR ${BOOST_INSTALL_DIR}/include)
endif()
set(BOOST_SUBMODULES system;filesystem;program_options;thread)
#-----------------------------------------------------------------------------
# MyProject
#-----------------------------------------------------------------------------
message(STATUS "Installing MyProject library.")
if(BUILD_MYPROJECT)
set(MYPROJECT_LIBS zlib;znz;nifticdf;niftiio)
ExternalProject_Add(MYPROJECT
SOURCE_DIR "${PROJECT_BINARY_DIR}/MyProject"
BINARY_DIR "${PROJECT_BINARY_DIR}/MyProject-build"
INSTALL_DIR "${PROJECT_BINARY_DIR}/MyProject-install"
GIT_REPOSITORY "${git_protocol}://gitlab.com/slckr/MyProject.git"
GIT_TAG "origin/multithread2"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DZLIB_INC_DIR:PATH=${ZLIB_INCLUDE_DIR}
-DZLIB_LIB_DIR:PATH=${ZLIB_LIBRARY_DIR}
-DNIFTI_INC_DIR:PATH=${NIFTI_INCLUDE_DIR}
-DNIFTI_LIB_DIR:PATH=${NIFTI_LIBRARY_DIR}
-DBOOST_INC_DIR:PATH=${BOOST_INCLUDE_DIR}
-DBOOST_LIB_DIR:PATH=${BOOST_LIBRARY_DIR}
-DBOOST_SUBMODULES:STRING=${BOOST_SUBMODULES}
-DMYPROJECT_LIBS:STRING=${MYPROJECT_LIBS}
DEPENDS Nifticlib boost)
endif()
The problem is when I try to link MyProject to nifticlib or boost, because the library name is different based on the platform (which I handled when importing libraries) the linking fails.
I pass the library directory and in MyProject CMakeLists, I do:
include_directories(${ZLIB_INC_DIR} ${NIFTI_INC_DIR} ${BOOST_INC_DIR})
link_directories(${ZLIB_LIB_DIR} ${NIFTI_LIB_DIR} ${BOOST_LIB_DIR})
target_link_libraries(MyProject zlib znz niftiio nifticdf)
but target_link_libraries fails, because zlib is not found (but I imported it in my superbuild). How can I tell MyProject to use the imported library of my superbuild?
Thank you.
I think this https://crascit.com/2015/07/25/cmake-gtest/ could help you.
The main point of the method in the link is to build the external project during configuration time. This integrates the external project completly in your build and gives access to the targets.
Unfortunaly the example uses gtest to demonstrate the use but it is possible to use it for other dependencies.
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.