Is it possible to build Boost with CMake? [closed]

Rather than include static libraries in my source tree in a cross-compiled project I'd like to add boost directly into cmake and build it. Is this available?


Solution 1:

We've struggled with this a fair bit too at my workplace. While I certainly can't claim to know the "best" way, I can offer the following thoughts on my experiences.

We initially just required devs to install boost separately and had CMake do its normal checks in the form of a find_package(Boost...) call. This was easy, but not automated, and caused problems for devs with older versions of boost already installed.

We then changed tack and added a copy of the boost sources which we cloned from one of the projects you mentioned above. I can't recall the specifics, but I think it was a precursor to the one currently being worked on in the Ryppl project. The main point was that it already had support for CMake; the boost libraries were actual CMake targets added via add_library calls, which made them easier to work with in the CMake code.

While this solved the previous problems by automating the use of boost in our project, it ultimately became a maintenance nightmare. The boost project we had cloned from changed radically and is now very dependent on Ryppl-specific CMake functions. We didn't want to add Ryppl as a dependency, so we changed tack again!

We looked at the projects you mentioned in your question, and likewise found none of them to be usable.

Our current setup makes use of CMake's ExternalProject module. This allows us to download and build boost to our build tree.

Advantages:

  • Low maintenance
  • Automated, so all devs use the same version built with the same flags
  • Keeps our own source tree free from third-party code
  • Multiple copies of boost can happily co-exist (so no chance of accidentally linking to a copy built with a different compiler/stdlib combination)

Disadvantages

  • Deleting your build tree means having to download and build boost from scratch. This could be ameliorated by e.g. downloading to a fixed location (say, system temp dir), so the download/unzip step could be skipped if an existing copy of the boost sources is found.
  • The boost libraries are not proper CMake targets (i.e. they haven't been added via add_library calls)

Here's a link to our CMake code. There are a few ways in which this needs improved, but it currently works reasonably well for us.

I hope that soon this answer becomes out of date and a decent, modularised, CMake-compatible solution becomes available.

Solution 2:

I found Fraser's answer above to be a good starting point, but ran into some issues using Boost 1.55.0 on our system.

First we wanted to have a self-contained source code package for our applications, so preferred not to use the CMake ExternalProject. We were only using the thread and date_time libraries from Boost, so we used bcp to create a subset of Boost with the build tools, thread and other dependent libraries:

$ bcp tools/build thread system date_time ../boost_1_55_0_threads_only

and checked this into our svn repository.

Next, I was able to adapt Fraser's CMake file to build on Linux, but ran into problems running the bootstrap.bat file on Windows with CMake's execute_process command. To run bootstrap.bat we first needed to run the relevant Visual Studio vcvarsall.bat script to set environment variables (we could probably figure out which individual variables need to be set, but it was easier to run the whole script). To run two .bat files in the same shell using execult_process, we used cmd /c and listed the files separated by a & as the argument.

Also bootstrap.bat did not set the exit code to non-zero in case of failure, so using the execute_process RESULT_VARIABLE to check for success didn't work. Instead we checked that the b2.exe executable had been created after the command was run.

One last issue: bootstrap.sh supports the --prefix= option, which bootstrap.bat does not. I also found that specifying the --prefix option for b2.exe on windows worked, but using the --prefix option for b2 on Linux, without specifying it for bootstrap.sh gave errors. (I haven't understood why yet).

So the relevant part of our CMake file looks like:

  #
  # run bootstrap
  #
  if(WIN32)
    if(MSVC10)
      set(VCVARS_CMD "C:\\Program^ Files^ ^(x86^)\\Microsoft^ Visual^ Studio^ 10.0\\VC\\vcvarsall.bat")
    elseif(MSVC11)
      set(VCVARS_CMD "C:\\Program^ Files^ ^(x86^)\\Microsoft^ Visual^ Studio^ 11.0\\VC\\vcvarsall.bat")
    elseif(MSVC12)
      set(VCVARS_CMD "C:\\Program^ Files^ ^(x86^)\\Microsoft^ Visual^ Studio^ 12.0\\VC\\vcvarsall.bat")
    # elseif(...)
     # add more options here
    endif(MSVC10)
    set(BOOTSTRAP_CMD "${VCVARS_CMD} & bootstrap.bat")
    message("Executing command: ${BOOTSTRAP_CMD}")
    execute_process(COMMAND cmd /c "${BOOTSTRAP_CMD}" WORKING_DIRECTORY ${APT_BOOST_SRC}
                  RESULT_VARIABLE BS_RESULT OUTPUT_VARIABLE BS_OUTPUT ERROR_VARIABLE BS_ERROR)
    if(NOT EXISTS ${APT_BOOST_SRC}/b2.exe)
      message(FATAL_ERROR "Failed running cmd /c ${BOOTSTRAP_CMD} in ${APT_BOOST_SRC}:\n${BS_OUTPUT}\n${BS_ERROR}\n")
    else(NOT EXISTS ${APT_BOOST_SRC}/b2.exe)
      message("bootstrap output:\n${BS_OUTPUT}")
    endif(NOT EXISTS ${APT_BOOST_SRC}/b2.exe)
  else(WIN32)
    set(BOOTSTRAP_CMD "./bootstrap.sh")
    set(BOOTSTRAP_ARGS "--prefix=${APT_BOOST_BIN}")
    message("Executing command: ${BOOTSTRAP_CMD} ${BOOTSTRAP_ARGS}")
    execute_process(COMMAND "${BOOTSTRAP_CMD}" ${BOOTSTRAP_ARGS} WORKING_DIRECTORY ${APT_BOOST_SRC}
                  RESULT_VARIABLE BS_RESULT OUTPUT_VARIABLE BS_OUTPUT ERROR_VARIABLE BS_ERROR)
    if(NOT BS_RESULT EQUAL 0)
      message(FATAL_ERROR "Failed running ${BOOTSTRAP_CMD} ${BOOTSTRAP_ARGS} in ${APT_BOOST_SRC}:\n${BS_OUTPUT}\n${BS_ERROR}\n")
    endif()
  endif(WIN32)
  #
  # run b2
  #
  set(B2_ARGS "link=static" "threading=multi" "runtime-link=static" "variant=release")
  foreach(COMP IN LISTS APT_BOOST_COMPONENTS)
    set(B2_ARGS "--with-${COMP}" ${B2_ARGS})
  endforeach(COMP IN LISTS APT_BOOST_COMPONENTS)
  if(WIN32)
    if(MSVC11)
      set(B2_ARGS "--toolset=msvc-11.0" ${B2_ARGS})
    elseif(MSVC12)
      set(B2_ARGS "--toolset=msvc-12.0" ${B2_ARGS})
    endif(MSVC11)
    file(TO_NATIVE_PATH ${APT_BOOST_BIN} APT_BOOST_BIN_WIN)
    set(B2_ARGS "--prefix=${APT_BOOST_BIN_WIN}" ${B2_ARGS} "architecture=x86" "address-model=64")
  endif(WIN32)
  set(B2_ARGS ${B2_ARGS} install)
  set(B2_CMD "./b2")
  message("Executing command: ${B2_CMD} ${B2_ARGS}")
  execute_process(COMMAND ${B2_CMD} ${B2_ARGS} WORKING_DIRECTORY ${APT_BOOST_SRC}
                  RESULT_VARIABLE B2_RESULT OUTPUT_VARIABLE B2_OUTPUT ERROR_VARIABLE B2_ERROR)
  if(NOT B2_RESULT EQUAL 0)
    message(FATAL_ERROR "Failed running ${B2_CMD} in ${APT_BOOST_SRC}:\n${B2_OUTPUT}\n${B2_ERROR}\n")
  endif()

In the above APT_BOOST_SRC is the location of the Boost subdirectory in our source directory, APT_BOOST_BIN is the location we use to store the libraries in our CMake build directory, and APT_BOOST_COMPONENTS is a list of the Boost libraries we are using.