0

Some time ago I was looking for a solution on SO how to automatically build BOOST library at CMake configure time. I didn't find a complete solution, but I did find useful part about FetchContent. I wrote a CMake script to do this. But this script created a complete library. Then I extended this script to use the "bcp" tool from BOOST to create only the necessary libraries.

So, How to automatically build the necessary BOOST libraries at CMake configure time?

WEEnch
  • 41
  • 1
  • 7

1 Answers1

1

Here is my solution to build and install only the circular_buffer library (with dependencies) from BOOST:

cmake_minimum_required(VERSION 3.20)

# set common paths
set(EXTERNAL_PROJECTS_DIR   "${CMAKE_SOURCE_DIR}/.external")
set(EXEC_INSTALL_DIR        "${CMAKE_INSTALL_PREFIX}/EXEC")

# set paths
set(BOOST_LIB_ROOT_DIR      "${EXTERNAL_PROJECTS_DIR}/boost")
set(BOOST_LIB_REPOS_DIR     "${BOOST_LIB_ROOT_DIR}/repos")
set(BOOST_LIB_REPOS_MIN_DIR "${BOOST_LIB_ROOT_DIR}/repos-minimal")
set(BOOST_LIB_BUILD_DIR     "${BOOST_LIB_ROOT_DIR}/build")
set(BOOST_LIB_FCSTUFF_DIR   "${BOOST_LIB_ROOT_DIR}/cmake-fetchcontent-stuff")
cmake_path(GET CMAKE_BINARY_DIR FILENAME CONFIG_NAME)
if (CONFIG_NAME)
  set(BOOST_LIB_INSTALL_DIR "${BOOST_LIB_ROOT_DIR}-install/${CONFIG_NAME}")
else()
  set(BOOST_LIB_INSTALL_DIR "${BOOST_LIB_ROOT_DIR}-install")
endif()

set(BOOST_LIB_INCLUDE_DIR   "${BOOST_LIB_INSTALL_DIR}/include")
set(BOOST_LIB_LIB_DIR       "${BOOST_LIB_INSTALL_DIR}/lib")

# set script options and commands for the build
set(BOOST_LIB_BUILD_OPTIONS         "--includedir=${BOOST_LIB_INCLUDE_DIR}")
list(APPEND BOOST_LIB_BUILD_OPTIONS "--libdir=${BOOST_LIB_LIB_DIR}")
list(APPEND BOOST_LIB_BUILD_OPTIONS "--build-dir=${BOOST_LIB_BUILD_DIR}")
list(APPEND BOOST_LIB_BUILD_OPTIONS "--build-type=minimal")
list(APPEND BOOST_LIB_BUILD_OPTIONS "--no-cmake-config")

set(BOOST_LIB_BUILD_PROPERTIES            "address-model=64")
list(APPEND BOOST_LIB_BUILD_PROPERTIES    "link=static")
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
  list(APPEND BOOST_LIB_BUILD_PROPERTIES  "variant=debug")
else()
  list(APPEND BOOST_LIB_BUILD_PROPERTIES  "variant=release")
endif()

# set bcp module-list
# vvv required modules vvv
set(BCP_MODULE_LIST         "build")
list(APPEND BCP_MODULE_LIST "bootstrap.bat")
list(APPEND BCP_MODULE_LIST "bootstrap.sh")
list(APPEND BCP_MODULE_LIST "boostcpp.jam")
list(APPEND BCP_MODULE_LIST "boost-build.jam")
list(APPEND BCP_MODULE_LIST "config")
# ^^^ required modules ^^^
# vvv optional modules vvv
list(APPEND BCP_MODULE_LIST "circular_buffer")
# ^^^ optional modules ^^^

# download and unpack BOOST library
include(FetchContent)
FetchContent_Declare(
  boost
  GIT_REPOSITORY  https://github.com/boostorg/boost.git
  GIT_TAG         "boost-1.81.0"
  PREFIX          ${BOOST_LIB_FCSTUFF_DIR}
  SOURCE_DIR      ${BOOST_LIB_REPOS_DIR}
)
set(FETCHCONTENT_QUIET OFF CACHE BOOL "" FORCE)

FetchContent_GetProperties(boost)
if(NOT boost_POPULATED)
  FetchContent_Populate(boost)
endif()

# run build and installation
if(${boost_POPULATED})
  if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
    file(GLOB_RECURSE VCVARSALL_LIST "C:/Program Files*/vcvarsall.bat")
    list(POP_BACK VCVARSALL_LIST VCVARSALL_FILE)
  endif()

  file(GLOB B2_EXE_PATH "${BOOST_LIB_REPOS_DIR}/b2*")
  list(LENGTH B2_EXE_PATH B2_EXE_PATH_LENGTH)
  if (B2_EXE_PATH_LENGTH EQUAL 0)
    if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
      set(EXECUTE_PROCESS_COMMAND ${VCVARSALL_FILE} "x64" "&&" ".\\bootstrap.bat" "msvc")
    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU AND WIN32)
      set(EXECUTE_PROCESS_COMMAND ".\\bootstrap.bat" "gcc")
    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU AND LINUX)
      set(EXECUTE_PROCESS_COMMAND "./bootstrap.sh" "gcc")
    endif()
    execute_process(
      COMMAND           ${EXECUTE_PROCESS_COMMAND}
      WORKING_DIRECTORY ${BOOST_LIB_REPOS_DIR}
      COMMAND_ECHO      STDOUT
    )
  endif()


  file(GLOB BCP_EXE_PATH "${BOOST_LIB_REPOS_DIR}/dist/bin/bcp*")
  list(LENGTH BCP_EXE_PATH BCP_EXE_PATH_LENGTH)
  if (BCP_EXE_PATH_LENGTH EQUAL 0)
    if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
      set(EXECUTE_PROCESS_COMMAND ${VCVARSALL_FILE} "x64" "&&" ".\\b2" "tools/bcp" "toolset=msvc")
    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU AND WIN32)
      set(EXECUTE_PROCESS_COMMAND ".\\b2" "tools/bcp" "toolset=gcc")
    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU AND LINUX)
      set(EXECUTE_PROCESS_COMMAND "./b2" "tools/bcp" "toolset=gcc")
    endif()
    execute_process(
      COMMAND           ${EXECUTE_PROCESS_COMMAND}
      WORKING_DIRECTORY ${BOOST_LIB_REPOS_DIR}
      COMMAND_ECHO      STDOUT
    )
  endif()


  # check bcp module-list for changes
  set(BCP_MODULE_LIST_HASH_FILENAME "bcp-module-list-hash")
  string(SHA256 BCP_MODULE_LIST_HASH_NEW "${BCP_MODULE_LIST}")
  file(MAKE_DIRECTORY ${BOOST_LIB_REPOS_MIN_DIR})
  file(TOUCH "${BOOST_LIB_REPOS_MIN_DIR}/${BCP_MODULE_LIST_HASH_FILENAME}")
  file(READ "${BOOST_LIB_REPOS_MIN_DIR}/${BCP_MODULE_LIST_HASH_FILENAME}" BCP_MODULE_LIST_HASH_OLD)
  string(COMPARE EQUAL "${BCP_MODULE_LIST_HASH_NEW}" "${BCP_MODULE_LIST_HASH_OLD}" BCP_MODULE_LIST_HASHES_ARE_EQUAL)
  if (NOT ${BCP_MODULE_LIST_HASHES_ARE_EQUAL})
    file(REMOVE_RECURSE ${BOOST_LIB_REPOS_MIN_DIR})
    file(MAKE_DIRECTORY ${BOOST_LIB_REPOS_MIN_DIR})
    file(WRITE "${BOOST_LIB_REPOS_MIN_DIR}/${BCP_MODULE_LIST_HASH_FILENAME}" "${BCP_MODULE_LIST_HASH_NEW}")
    if(WIN32)
      set(EXECUTE_PROCESS_COMMAND ".\\bcp" "--boost=${BOOST_LIB_REPOS_DIR}" ${BCP_MODULE_LIST} "${BOOST_LIB_REPOS_MIN_DIR}")
    elseif(LINUX)
      set(EXECUTE_PROCESS_COMMAND "./bcp" "--boost=${BOOST_LIB_REPOS_DIR}" ${BCP_MODULE_LIST} "${BOOST_LIB_REPOS_MIN_DIR}")
    endif()
    execute_process(
      COMMAND           ${EXECUTE_PROCESS_COMMAND}
      WORKING_DIRECTORY "${BOOST_LIB_REPOS_DIR}/dist/bin"
      COMMAND_ECHO      STDOUT
    )
  endif()


  file(MAKE_DIRECTORY ${BOOST_LIB_INSTALL_DIR})
  file(TOUCH "${BOOST_LIB_INSTALL_DIR}/${BCP_MODULE_LIST_HASH_FILENAME}")
  file(READ "${BOOST_LIB_INSTALL_DIR}/${BCP_MODULE_LIST_HASH_FILENAME}" BCP_MODULE_LIST_HASH_OLD)
  string(COMPARE EQUAL "${BCP_MODULE_LIST_HASH_NEW}" "${BCP_MODULE_LIST_HASH_OLD}" BCP_MODULE_LIST_HASHES_ARE_EQUAL)
  if(NOT ${BCP_MODULE_LIST_HASHES_ARE_EQUAL})
    file(REMOVE_RECURSE ${BOOST_LIB_INSTALL_DIR})
    file(MAKE_DIRECTORY ${BOOST_LIB_INSTALL_DIR})
    file(WRITE "${BOOST_LIB_INSTALL_DIR}/${BCP_MODULE_LIST_HASH_FILENAME}" "${BCP_MODULE_LIST_HASH_NEW}")
    if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
      set(EXECUTE_PROCESS_COMMAND_1 ${VCVARSALL_FILE} "x64" "&&" "bootstrap.bat" "msvc")
      set(EXECUTE_PROCESS_COMMAND_2 ${VCVARSALL_FILE} "x64" "&&" "bootstrap.bat" "msvc")
      set(EXECUTE_PROCESS_COMMAND_3 ${VCVARSALL_FILE} "x64" "&&" ".\\b2" "toolset=msvc" ${BOOST_LIB_BUILD_OPTIONS} ${BOOST_LIB_BUILD_PROPERTIES} "install")
    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU AND WIN32)
      set(EXECUTE_PROCESS_COMMAND_1 ".\\bootstrap.bat" "gcc")
      set(EXECUTE_PROCESS_COMMAND_2 ".\\bootstrap.bat" "gcc")
      set(EXECUTE_PROCESS_COMMAND_3 ".\\b2" "toolset=gcc" ${BOOST_LIB_BUILD_OPTIONS} ${BOOST_LIB_BUILD_PROPERTIES} "install")
    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU AND LINUX)
      set(EXECUTE_PROCESS_COMMAND_1 "./bootstrap.sh" "gcc")
      set(EXECUTE_PROCESS_COMMAND_2 "./bootstrap.sh" "gcc")
      set(EXECUTE_PROCESS_COMMAND_3 "./b2" "toolset=gcc" ${BOOST_LIB_BUILD_OPTIONS} ${BOOST_LIB_BUILD_PROPERTIES} "install")
    endif()
    execute_process(
      COMMAND           ${EXECUTE_PROCESS_COMMAND_1}
      WORKING_DIRECTORY "${BOOST_LIB_REPOS_MIN_DIR}/tools/build"
      COMMAND_ECHO      STDOUT
    )
    execute_process(
      COMMAND           ${EXECUTE_PROCESS_COMMAND_2}
      WORKING_DIRECTORY ${BOOST_LIB_REPOS_MIN_DIR}
      COMMAND_ECHO      STDOUT
    )
    execute_process(
      COMMAND           ${EXECUTE_PROCESS_COMMAND_3}
      WORKING_DIRECTORY ${BOOST_LIB_REPOS_MIN_DIR}
      COMMAND_ECHO      STDOUT
    )
  endif()
endif()

set(BOOST_INCLUDES "${BOOST_LIB_INCLUDE_DIR}")
if(WIN32)
  string(APPEND BOOST_INCLUDES "/boost-1_81")
endif()
file(GLOB_RECURSE BOOST_LIBS "${BOOST_LIB_LIB_DIR}")

Steps taken:

  1. Set variables
  2. Set "bcp" module-list
  3. Download BOOST (using FetchContent)
  4. Build "b2" (Boost.Build)
  5. Build "bcp" tool
  6. Install the library sources from the "bcp" module-list in a separate directory
  7. Build and install these libraries

Here is the full version: https://github.com/weenchvd/cmake-build-boost-lib

WEEnch
  • 41
  • 1
  • 7