Building Boost on Windows

Boost Logo

From time to time I find myself building Boost on Windows. There's a number of small things that need to be done to make that happen. Having had to "rediscover" the build process each time, I recently decided to create a small Windows command script to automate most of the process.

As I find the build script extremely useful, I figured it would be worth posting it here to inspire others in similar circumstances.

Process Overview

The overall build process is simple:

  1. Download and install the necessary tools.
  2. Download the sources.
  3. Download the build script.
  4. Update paths and version numbers in the build script, as necessary.
  5. Run the build script.
The build script itself will, for each build type (release / debug, 32-bit / 64-bit):
  1. Extract the Boost source to a build sub-directory.
  2. Configure the Windows SDK for the appropriate build type, if necessary.
  3. Configure and build Boost.

External Tools

Tip: you can find direct links to most of the software listed below on the Boost Links page.

The build script requires a valid Visual C++ installation - Express editions are fine. If using an Express edition prior to 2012, then you should also install a recent (eg 7.1) Windows SDK for 64-bit support.

For Boost's MPI support, install a Microsoft HPC Pack - not 2012 though, that version does not include the required headers / libraries.

For Python support, install the official Python Windows binaries - install both 32-bit and 64-bit versions.

Oh, and the build script uses 7zip to extract the various sources, so install that too.

Sources

At the very least you need the relevant Boost source... naturally.

Additionally, you can (recommended) include bzip2 and zlib sources to enable Boost's support for those. Note, if downloading zlib, be sure to downoad the source, not the compiled DLL release for Windows - the latter is 32-bit only.

My Boost build script expects to find the above sources within a source directory in its current location. The directory layout should look like:

Note, the following script has been moved to github: https://github.com/pcolby/boost-win

So check there for the latest version.

The build script will create a build directory (if not already present) for the generated build files.

build.cmd

So, here's the build script:

@echo off
:: Script for building Boost C++ Libraries on Windows.
:: Writen by Paul Colby (https://colby.id.au), no rights reserved ;)
:: See https://colby.id.au/building-boost-on-windows

:: The following are all required; adjust to match your setup.
set BOOST_TOOLSET=msvc-11.0
set BOOST_VERSION=1_53_0
set ZIP7=%PROGRAMFILES%\7-zip\7z.exe

:: The following are all optional; comment out if not needed.
set BZIP_VERSION=1.0.6
set ZLIB_FILE_VERSION=127
set ZLIB_VERSION=1.2.7

:: Only define the Windows SDK version if standalone, ie for Express versions prior to 2012.
rem set WIN_SDK_VERSION=7.1
if "%WIN_SDK_VERSION%" NEQ "" set WIN_SDK=%PROGRAMFILES%\Microsoft SDKs\Windows\v%WIN_SDK_VERSION%
if "%WIN_SDK%" NEQ "" (
  if exist "%WIN_SDK%\Bin\SetEnv.cmd" set SET_ENV=%WIN_SDK%\Bin\SetEnv.cmd
  rem I like to copy %WIN_SDK%\Bin\SetEnv.cmd to %WIN_SDK%\Bin\SetEnvNc.cmd to
  rem remove the two "COLOR 0x" calls and the CLS call - just for nicer output.
  if exist "%WIN_SDK%\Bin\SetEnvNc.cmd" set SET_ENV=%WIN_SDK%\Bin\SetEnvNc.cmd
)
goto main

:: usage: call:extract input-file output-dir
:extract
@echo Extracting "%~1" to "%~2"
"%ZIP7%" x -o"%~2" "%~1" > nul
if errorlevel 1 (
  echo Failed to extract "%~1"
  pause
  exit errorlevel
)
goto :EOF

:: usage: call:configureWinSDK x86|x64|ia64 debug|release [/vista^|/xp^|/2003^|/2008^|/win7]
:configureWinSDK
if "%WIN_SDK%" EQU "" goto :EOF
set TARGET_ARCH=/%1
set MODE=/%2
if "%3" EQU "" ( set TARGET_OS=/xp ) else set TARGET_OS=%3
call "%SET_ENV%" %MODE% %TARGET_ARCH% %TARGET_OS%
goto :EOF

:: usage: call:extractsource build_dir
:extractSource
set SOURCE_DIR=%~dp0source
set SOURCE_FILE=%SOURCE_DIR%\boost_%BOOST_VERSION%.zip
if exist "%SOURCE_DIR%\boost_%BOOST_VERSION%.7z" (
  set SOURCE_FILE=%SOURCE_DIR%\boost_%BOOST_VERSION%.7z
)
if not exist "%~1" call:extract %SOURCE_FILE% %~1
goto :EOF

:: usage: call:bootstrap boost_dir
:bootstrap
@echo Bootstrapping %~1
pushd "%~1"
call bootstrap.bat
popd
set MPI_JAM=%~1\tools\build\v2\tools\mpi.jam
set MPI_TMP=%MPI_JAM%.tmp
if exist "%PROGRAMFILES%\Microsoft HPC Pack 2008 R2" (
  powershell -Command "get-content %MPI_JAM% | ForEach-Object {$_ -replace \"Microsoft Compute Cluster Pack\",\"Microsoft HPC Pack 2008 R2\"} | set-content %MPI_TMP%" && move /y "%MPI_TMP%" "%MPI_JAM%"
  if not exist "%PROGRAMFILES%\Microsoft HPC Pack 2008 R2\Include" (
    if  exist "%PROGRAMFILES%\Microsoft HPC Pack 2008 R2\Inc" (
      powershell -Command "get-content %MPI_JAM% | ForEach-Object {$_ -replace '(cluster_pack_path.*Inc)lude', '$1'} | set-content %MPI_TMP%" && move /y "%MPI_TMP%" "%MPI_JAM%"
    )
  )
  echo( >> "%~1\tools\build\v2\user-config.jam" && echo using mpi ; >> "%~1\tools\build\v2\user-config.jam"
)
goto :EOF

:: usage: call:buildBoost boost_dir install_dir x86|x64|ia64 debug|release
:buildBoost
if /I "%~3" EQU "ia64" ( set BOOST_ARCH=ia64 ) else set BOOST_ARCH=x86
if /I "%~3" EQU "x86" ( set BOOST_ADDR=32 ) else set BOOST_ADDR=64
if "%BZIP_VERSION%" NEQ "" set sBZIP2=-sBZIP2_SOURCE="%~dp0source\bzip2-%BZIP_VERSION%"
if "%ZLIB_FILE_VERSION%" NEQ "" set sZLIB=-sZLIB_SOURCE="%~dp0source\zlib-%ZLIB_VERSION%"
pushd "%~1"
b2.exe --build-type=complete -d0 -j %NUMBER_OF_PROCESSORS% --prefix="%~2" -q %sBZIP2% %sZLIB% architecture=%BOOST_ARCH% address-model=%BOOST_ADDR% toolset=%BOOST_TOOLSET% variant=%~4 install
popd
goto :EOF

:: usage: call:build x86|x64|ia64 debug|release
:build
@echo ==== Building %~1 %~2 ====
call:configureWinSDK %~1 %~2
set BUILD_DIR=%~dp0build\boost_%BOOST_VERSION%-%~1-%~2
if not exist "%BUILD_DIR%" call:extractSource %BUILD_DIR%
set BOOST_DIR=%BUILD_DIR%\boost_%BOOST_VERSION%
if not exist "%BOOST_DIR%\b2.exe" call:bootstrap %BOOST_DIR%
set INSTALL_DIR=%BUILD_DIR%\install
if not exist "%INSTALL_DIR%" call:buildBoost %BOOST_DIR% %INSTALL_DIR% %~1 %~2
goto :EOF

:main
if "%BZIP_VERSION%" NEQ "" (
  if not exist "%~dp0source\bzip2-%BZIP_VERSION%.tar" call:extract %~dp0source\bzip2-%BZIP_VERSION%.tar.gz %~dp0source
  if not exist "%~dp0source\bzip2-%BZIP_VERSION%" call:extract %~dp0source\bzip2-%BZIP_VERSION%.tar %~dp0source
)
if "%ZLIB_FILE_VERSION%" NEQ "" (
  if not exist "%~dp0source\zlib-%ZLIB_VERSION%" call:extract %~dp0source\zlib%ZLIB_FILE_VERSION%.zip %~dp0source
)
if not exist "%~dp0build" md "%~dp0build"
call:build x64 debug
call:build x64 release
call:build x86 debug
call:build x86 release
pause

I've tested this script with:

These all build cleanly (actually some libs are skipped by Boost when using Python 3+), but I certainly haven't tested all of Boost's features, so there probably will be a few issues yet to be sorted out. And no doubt other versions of the tools / sources will bring their own issues too.

What's Next

The next step is packaging... I've already created a basic set of NSIS install scripts for generating installers for the generated Boost files. I'll finalise, and post those scripts in another blog post soon.

After that, I plan on putting together a short screencast to show the entire process, from a clean Windows install to a Boost Windows installer.

I might also look for somewhere to host the generated installers publically... if there's enough interest for that.

Attachments

comments powered by Disqus