FetchContent vs ExternalProject

4.9k views Asked by At

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).

1

There are 1 answers

0
WEEnch On

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