16
$\begingroup$

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

$\endgroup$
  • $\begingroup$ 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.) $\endgroup$ – rcollyer Jun 21 '12 at 13:48
  • $\begingroup$ As an added comment, I have successfully used boost in a mathlink program, so it is likely not compiled with the correct options. $\endgroup$ – rcollyer Jun 21 '12 at 13:51
  • $\begingroup$ What compiler and OS are you using? $\endgroup$ – Szabolcs Jun 21 '12 at 13:51
  • $\begingroup$ 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. $\endgroup$ – Leonid Shifrin Jun 21 '12 at 13:54
  • $\begingroup$ @LeonidShifrin I agree with you, but usually getting one example work is the hardest part, that's what I'm trying. $\endgroup$ – faysou Jun 21 '12 at 14:03
16
$\begingroup$

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}} *)
$\endgroup$
  • $\begingroup$ Thank you very much for your answer. $\endgroup$ – faysou Jun 22 '12 at 5:42
2
$\begingroup$

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
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.