Using Boost with CreateLibrary

16

8

I was looking at the answer of Leonid of Faster alternatives for DayOfWeek and wanted to see how hard it would be to do something similar in C++ using an external library like Boost. I tried to include a Boost header in the example of the CreateLibrary help located here

http://reference.wolfram.com/mathematica/CCompilerDriver/ref/CreateLibrary.html

specifying also the path for the Boost files to include and Boost compiled libraries, like I would do in VisualStudio that I use, but the example didn't compile.

So before trying harder, has anyone already succesfully used Boost with the CreateLibrary function ? (new in Mathematica 8).

Thanks

faysou

Posted 2012-06-21T13:39:18.407

Reputation: 10 549

Since it is a c++ library, try setting "Language"->"c++". (I don't know if the language spec should be "c++", c++, "C++", or C++, as the docs are silent on that point. So, you'll have to try them until they don't give you errors.) – rcollyer – 2012-06-21T13:48:52.123

As an added comment, I have successfully used boost in a mathlink program, so it is likely not compiled with the correct options. – rcollyer – 2012-06-21T13:51:22.603

What compiler and OS are you using? – Szabolcs – 2012-06-21T13:51:35.473

Regarding getting an effect similar to what we have in Java (I mean the suability aspect): with Java, it is so easy because it has a Reflection API, and a very high-level JLink interface (which generates Mathematica boilerplate code behind the scenes), built on top of that. With C / LibraryLink, I expect that this would be harder - we need similar layers of automation. – Leonid Shifrin – 2012-06-21T13:54:23.600

@LeonidShifrin I agree with you, but usually getting one example work is the hardest part, that's what I'm trying. – faysou – 2012-06-21T14:03:53.820

@Szabolcs I use the compiler of VisualC++ under Windows (@ work) – faysou – 2012-06-21T14:05:37.017

rcollyer, the expected setting is Language->"C++" with a capital "C". – Joel Klein – 2012-11-29T22:17:27.923

Answers

16

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}} *)

wxffles

Posted 2012-06-21T13:39:18.407

Reputation: 13 711

Thank you very much for your answer. – faysou – 2012-06-22T05:42:10.223

2

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

Contango

Posted 2012-06-21T13:39:18.407

Reputation: 381