Using Boost with CreateLibrary

I managed to get something going:

Needs["CCompilerDriver`"]

src = "
  #include \"WolframLibrary.h\"
  #include <boost/date_time/gregorian/gregorian.hpp>

  EXTERN_C DLLEXPORT int dow(WolframLibraryData libData,
        mint Argc, MArgument *Args, MArgument Res) {
    mint year = MArgument_getInteger(Args[0]);
    mint month = MArgument_getInteger(Args[1]);
    mint day = MArgument_getInteger(Args[2]);
    boost::gregorian::date date(year, month, day);
    MArgument_setInteger(Res, date.day_of_week().as_number());
    return LIBRARY_NO_ERROR;
  }
";

dowlib = CreateLibrary[src, "dow",
  "Language" -> "C++", 
  "IncludeDirectories" -> {Environment["BOOSTDIR"]}, 
  "LibraryDirectories" -> {Environment["BOOSTLIBDIR"]},
  "CompileOptions" -> {"/EHsc"}]

A few notes:

  • EXTERN_C is required to stop C++ mangling the name
  • The compile option /EHsc is required to enable C++ exceptions.
  • Your environment variables / boost directories will vary.

Load it up:

dow = LibraryFunctionLoad[dowlib, "dow", {Integer, Integer, Integer}, Integer]

Test it out:

dow[2012, 6, 22]

5

RandomDateList[] := {RandomInteger[{1800, 2100}], RandomInteger[{1, 12}],
   RandomInteger[{1, 28}], RandomInteger[{0, 23}], RandomInteger[{0, 59}], 
   RandomInteger[{0, 59}]};
RandomDates[n_] := Table[RandomDateList[], {n}]

d = RandomDates[100000];

dow[Sequence @@ #[[;; 3]]] & /@ d // AbsoluteTiming // Short

{0.6562500,{6,6,1,2,5,3,4,0,0,3,0,<<99978>>,6,6,3,1,4,5,6,5,4,4,4}}

Huzzah!

Don't forget to unload it if you want to recompile:

LibraryFunctionUnload[dow]

FYI:

CCompilers[]
(* -> {{Name->Visual Studio,
  Compiler->CCompilerDriver`VisualStudioCompiler`VisualStudioCompiler,
  CompilerInstallation->c:\Program Files\Microsoft Visual Studio 9.0,
  CompilerName->Automatic}} *)

Further to the excellent answer from @wxffles:

This answer works for:

  • Mathematica 12
  • Boost v1.63
  • Visual Studio 2017

First compile the static libraries with Boost. Open a Visual Studio 2017 x64 command prompt in the Boost directory, and run:

bootstrap.bat
.\b2 runtime-link=static

If one omits the option for static, then Mathematica requires a static library, and it might fail with this error:

CreateLibrary::cmperr: Compile error: LINK : fatal error LNK1104: cannot open file 'libboost_date_time-vc140-mt-s-1_63.lib'

Also see my answer here: Boost compiling with MSVC 11 (VS 2012).

This is the code that worked for me, without the need to set up any environment variables.

Needs["CCompilerDriver`"]

src = "
    #include \"WolframLibrary.h\"
    #include <Boost/date_time/gregorian/gregorian.hpp>

    EXTERN_C DLLEXPORT int dow(WolframLibraryData libData,
          mint Argc, MArgument *Args, MArgument Res) {
      mint year = MArgument_getInteger(Args[0]);
      mint month = MArgument_getInteger(Args[1]);
      mint day = MArgument_getInteger(Args[2]);
      boost::gregorian::date date(year, month, day);
      MArgument_setInteger(Res, date.day_of_week().as_number());
      return LIBRARY_NO_ERROR;
    }
  ";
dowlib = CreateLibrary[src, "dow", "Language" -> "C++", 
  "IncludeDirectories" -> "C:\\local\\boost_1_63_0\\", 
  "LibraryDirectories" -> "C:\\local\\boost_1_63_0\\stage\\lib\\", 
  "CompileOptions" -> {"/EHsc"}]
dow = LibraryFunctionLoad[dowlib, "dow", {Integer, Integer, Integer}, 
   Integer];
dow[2012, 6, 22]
>> 5