How to use the library exported from FunctionCompileExportLibrary outside of Mathematic (e.g., in Visual Studio)?

This is a quick example of calling the exported compiled function from a standalone executable on Windows.

A few things to note which are currently undocumented and that can definitely be subject to change (and improvement) in the future:

  • the function is named Main by default and the example uses an explicit prototype rather than including a header file;

  • the Wolfram Runtime Library is linked statically for convenience (of course, the dynamic WolframRTL.dll could be used instead provided the executable can find it);

  • CreateExecutable is also used for convenience here, however the test executable could be compiled in any other way;

  • while the Windows import library (function.lib) is created, currently it is not placed next to the DLL. I expect this will be corrected in a paclet update.

    lib = FunctionCompileExportLibrary["function.dll",
              Function[Typed[arg, "MachineInteger"], arg + 1], 
               "CompilerOptions" -> "CreateLibraryOptions" -> 
                  {"SystemLibraries" -> {"WolframRTL_Static_Minimal"}}];
    
    Needs["CCompilerDriver`"]
    
    test = CreateExecutable["
       #include <stdio.h>
       #include <inttypes.h>
       int64_t Main(int64_t);
       int main() {
          printf(\"%\" PRId64, Main(10));
       }", 
       "test", "Libraries" -> {FileNameJoin[{$CCompilerDefaultDirectory, "function.lib"}]}];
    
    RunProcess[test, "StandardOutput"]
    
    (* "11" *)
    

Regarding the follow-up question in the edit: I think the linker is looking for the C++ mangled name. Try declaring Main with C linkage, i.e. extern "C". Also make sure the prototype is using the correct integer type.


As the ilian's answer, I make a note for Visual Studio user here to supplement:

source.cpp file

#include<iostream>
using namespace std;
extern "C" int Main(int);
int main() {
    cout << Main(3) << endl;
    return 0;
}

configure Visual Studio

  1. In Configuration Properties/Debugging/Environment add

PATH=C:\Program Files\Wolfram Research\Mathematica\12.0en\SystemFiles\Kernel\Binaries\Windows-x86-64;%appdata%\Mathematica\SystemFiles\LibraryResources\Windows-x86-64;C:\Program Files\Wolfram Research\Mathematica\12.0en\SystemFiles\Libraries\Windows-x86-64

The first directory has some necessary .dll file. The second and the three directory have function.dll and WolframRTL.dll respectively. Of course, your can don't set the PATH evironment if you copy all those .dll file into the direcotry with source.cpp or the Configuration Properties/Output Directory.

  1. In Configuration Properties/VC++ Directories/Library Directories add

%appdata%\Mathematica\SystemFiles\LibraryResources\Windows-x86-64

This directory include function.lib

  1. In Configuration Properties/Linker/Input/Additional Dependencies add

function.lib

Then you can run the c++ project now. I think this is a small step for Wolframer, but a giant leap for those men who hope to use Mathematica in his work.


This is a follow-up of @ilian's answer, which doesn't work under macOS but provides a promising basis.

The error reported by @happy fish that dyld: Library not loaded: @rpath/function.dylib Referenced from: ... Reason: image not found Abort trap: 6 suggests the linking was not correct. Then I tried to correct the @rpath issue (which seems to be a bug but I'm not quite sure; this needs further investigation) and still got other linking issues which clearly indicated libWolframRTL_Static_Minimal.a was not statically linked (which is a well-known pain on macOS).

So below I provide a workaround for macOS, which used the FunctionCompileExport instead of FunctionCompileExportLibrary due to possible linking bug in it:

pathStaticLib="/Applications/Mathematica.app/Contents/SystemFiles/Libraries/MacOSX-x86-64/libWolframRTL_Static_Minimal.a";
lib=FunctionCompileExport["function.o",Function[Typed[arg,"MachineInteger"],arg+1];

Needs["CCompilerDriver`"]

test=CreateExecutable["
   #include <stdio.h>
   #include <inttypes.h>
   int64_t Main(int64_t);
   int main() {
      printf(\"%\" PRId64, Main(10));
   }","test","CompileOptions"->pathStaticLib,"ExtraObjectFiles"->{lib}];

RunProcess[test]

(*<|"ExitCode"->0,"StandardOutput"->"11","StandardError"->""|>*)