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