Here are three very simple examples to show how to call a Fortran subroutine using LibraryLink. First the subroutine is compiled into object file. Then a wrapper is used to call the Fortran subroutine and compiled into dynamic library. At the end, the library is loaded into Mathematica and run. In the examples Mathematica Version 8 is used.
FIRST EXAMPLE
add two integers
Fortran subroutine
!fadd.f90 subroutine add(a,b,sum) implicit none integer a,b,sum sum=a+b return end subroutine
C Wrapper
//MMA.cc //Link directly to fortran object file #include "WolframLibrary.h" DLLEXPORT mint WolframLibrary_getVersion(){ return WolframLibraryVersion;} DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData){ return 0;} extern "C" { void add_(mint* a, mint* b, mint* sum);} //declare fortran subroutine EXTERN_C DLLEXPORT int add(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){ mint I0; mint I1; mint sum; I0=MArgument_getInteger(Args[0]); I1=MArgument_getInteger(Args[1]); add_(&I0,&I1,&sum);//call fortran subroutine MArgument_setInteger(Res,sum); return LIBRARY_NO_ERROR; }
Compile and Run
First compile fortran subroutine:
gfortran -c fadd.f90
Then create dynamic library using the CCompilerDriver package:
Needs["CCompilerDriver`"]; CreateLibrary[{"MMA.cc", "fadd.o"}, "myadd", "Debug" -> True, "TargetDirectory" -> "."]
Load and run:
add = LibraryFunctionLoad["./myadd", "add", {Integer, Integer}, Integer] add[2, 2] (*LibraryFunction[<>,add,{Integer,Integer},Integer]*) (*4*)
SECOND EXAMPLE
add two vectors (code modified from similar question at here).
Fortran subroutine
!addvec.f90 subroutine addVec(a,b,n) implicit none integer n real(8),dimension(n)::a,b a(:)=a(:)+b(:) return end subroutine addVec
C Wrapper
//MMA.cc #include "WolframLibrary.h" #include "WolframCompileLibrary.h" DLLEXPORT mint WolframLibrary_getVersion(){ return WolframLibraryVersion; } DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData){ return 0; } extern "C" { void addvec_(mreal a[], mreal b[], mint* n); } EXTERN_C DLLEXPORT int addvec(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){ MTensor ta; MTensor tb; ta=MArgument_getMTensor(Args[0]); tb=MArgument_getMTensor(Args[1]); addvec_(MTensor_getRealDataMacro(ta),MTensor_getRealDataMacro(tb),MTensor_getDimensionsMacro(ta)); MArgument_setMTensor(Res,ta); return LIBRARY_NO_ERROR; }
Compile and Run
Needs["CCompilerDriver`"] CreateLibrary[{"MMA.cc", "addvec.o"}, "myadd", "Debug" -> True, "TargetDirectory" -> "."] addVec = LibraryFunctionLoad["./myadd", "addvec", {{Real, 1}, {Real, 1}}, {Real, 1}] addVec[{1.4, 2.7, 3.9}, {5.2, 6.7, 7.1}] addVec[{1.1, 2.2, 3.2, 2.2}, {4.4, 2.2, 3.3, 5.5}] (*{6.6, 9.4, 11.}*) (*{5.5, 4.4, 6.5, 7.7}*)
Third EXAMPLE
invoke Lapack to inverse a general matrix (code modified from here).
C Wrapper
//MMA.cc #include "WolframLibrary.h" #include "WolframCompileLibrary.h" DLLEXPORT mint WolframLibrary_getVersion(){ return WolframLibraryVersion; } DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData){ return 0; } extern "C" { // LU decomoposition of a general matrix void dgetrf_(mint* M, mint *N, double* A, mint* lda, mint* IPIV, mint* INFO); // generate inverse of a matrix given its LU decomposition void dgetri_(mint* N, double* A, mint* lda, mint* IPIV, double* WORK, mint* lwork, mint* INFO); } EXTERN_C DLLEXPORT int lpkInverse(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){ MTensor ta=MArgument_getMTensor(Args[0]); mint N=*MTensor_getDimensionsMacro(ta); double* A=MTensor_getRealDataMacro(ta); mint IPIV[N+1]; mint LWORK = N*N; double WORK[LWORK]; mint INFO; dgetrf_(&N,&N,A,&N,IPIV,&INFO); dgetri_(&N,A,&N,IPIV,WORK,&LWORK,&INFO); MArgument_setMTensor(Res,ta); return LIBRARY_NO_ERROR; }
Compile and Run
Needs["CCompilerDriver`"] $CCompiler = {"Name" -> "g++", "Compiler" -> CCompilerDriver`GenericCCompiler`GenericCCompiler, "CompilerInstallation" -> "/usr/bin", "CompilerName" -> "g++"}; CreateLibrary[{"MMA.cc"}, "myadd", "Debug" -> True, "TargetDirectory" -> ".", "CompileOptions" -> "-llapack"] inverse = LibraryFunctionLoad["./myadd", "lpkInverse", {{Real, 2}}, {Real, 2}] inverse[{{1, 2}, {3, 4}}] Inverse[{{1, 2}, {3, 4}}] // N (*{{-2., 1.}, {1.5, -0.5}}*) (*{{-2., 1.}, {1.5, -0.5}}*) a = Table[Table[RandomReal[{0., 10.}], {10}, {10}], {100}]; bM = Inverse /@ a; // AbsoluteTiming bl = inverse /@ a; // AbsoluteTiming (*{0.005429, Null}*) (*{0.001198, Null}*) bM - bl // Abs // Max (*1.30562*10^-13*)
I'm still in learning LibraryLink so if there are any mistakes please don't hesitate to point them out. Hope it will help.