Friday, 16 September 2011

Calling FORTRAN Code with MathLink

This post will explain how to use MathLink to call FORTRAN code.  I forsee three reasons this may be interesting.  One, people still use FORTRAN code!  Two, it will demonstrate how to interface Mathematica, through MathLink, with any programming language that C can call.  Thirdly, the blog will explain more about how MathLink works and will allow users to accomplish more sophisticated implementations.  I will rely on ideas developed in previous blog entries.

Here I will outline calling a simple program, adding two numbers together.  A FORTRAN (95) subroutine that achieves this is,

subroutine addtwof(i,j,k)
implicit none

This subroutine is saved in a text file, which I have called addtwof.f95.  It is possible to write C code that calls this subroutine.  Notice the FORTRAN code should not be a complete program, but needs to be a subroutine.  The C code to call a FORTRAN subroutine is compiler dependent.  However there are two common syntax.  Using the GCC compiler the syntax is,

addtwof_(&i, &j, &result);

Omitting the underscore, so just addtwof(&i, &j, &result);, is the other common syntax.  Information on what to use should be available in your C compilers documentation.  One technical difference between the C and FORTRAN languages is the use of pointers.  Basically C and FORTRAN have different data structures, a variable x, in C is a pointer.  It points to a location in the memory whereas in FORTRAN a variable is directly the location of that value in the memory.  As a result the ampersand (&) is used to tell C send FORTRAN the number itself, not just a memory location!  As a result you will see &i not just i etc.  There is a second important difference.  FORTRAN is not a case-sensitive language whilst C is.  Be very careful about using mixed case names, better yet, just don't do it and only use lower case letters for example.  The important lesson here is that calling a language from another requires to think carefully about the differences in the languages and carefully tread around them.

Now it is possible to write a simple C program that is usable by MathLink.  The code I will use is,

#include "mathlink.h"

int f(int i, int j) {
    int result;
    addtwof_(&i, &j, &result);
    return result;

int main(int argc, char *argv[]) {
    return MLMain(argc, argv);

From my previous blog you should recognise the mathlink header file and the MLMain call at the bottom.  In the function f one can see the FORTRAN call, complete with ampersands. 

In general, if a language can be called by C, and you can make it all happen, then you will just need an analogous program to the one here and MathLink will work.  Whilst the example here is dealing with FORTRAN there are many other languages that C call call directly.

There is one more file that is needed, a template file.  As the program adds two integers the template is the same as the C only implementation.  For completeness here it is again,

:Function:      f
:Pattern:       f[x_Integer, y_Integer]
:Arguments:     {x, y}
:ArgumentTypes: {Integer, Integer}
:ReturnType:    Integer

I have called this file  (Again, the .tm extension is important.)

At this point the three files, addtwo.f95, f. tm and the C program, f.c, must be compiled and linked.  Previously the program mcc was used.  It is not possible to use mcc here because we need to link the FORTRAN code to the C.

Linking FORTRAN with C, or any language with C for that matter, is done through object files.  All the files in a project are converted to object files, with a compiler, and are usually given .o extensions.  I will follow this convention.  A C compiler then links all the individual object files together into one executable.  Firstly I will outline how to generate the object files, I will use the GNU compilers.

In the case of the FORTRAN subroutine, type into a terminal,

terminal $ gfortran -c addtwof.f95 -o addtwof.o

This will compile the FORTRAN code in to an object file.  It is the flag -c which ensures this.  I have opted to name the output addtwof.o.  Next the C program must be converted to an object file.  Type in to a terminal,

terminal $ gcc -c f.c -o f.o

All of the same comments for the gfortran call apply.  The -c flag provides an object file, here named f.o.  Now the tricky object file, the one from the template file.  To do this requires the Mathematica program mprep.  This will convert the .tm template file into C code.  The C code is passed to gcc to give an object file and we have three object files.

I found the mprep program in the SystemFiles directory of my Mathematica installation.  Specifically it is in .../SystemFiles/Links/MathLink/Developerkit/architecture/CompilerAdditions directory, where architecture is either the 32-bit of 64-bit sub-directory, depending on your installation and OS.  In the folder you will find several useful things.  Firstly the program mprep, the script mcc (I have referred to it as a program before but it actually is a script) and some libraries.

To use mprep you have several options.  One is to type in to a terminal the location of mprep and the location of the template file.  This would look something like,

terminal $ /usr/local/Wolfram/.../CompilerAdditions/mprep /home/user/.../ -o

which would convert the .tm template file in to a C code file.  Or, if this is too unweildy, copy mprep and the libraries into the location where the template file is.  Then one can just type in to a terminal,

terminal $ ./mprep -o

Finally you could copy the template file to the mprep directory but that could get messy if many MathLink projects are undertaken.  Now we can use gcc to generate an object file from the template C code,  This is done like before,

terminal $ gcc -c -o

Now we have three objects files, one from the FORTRAN code, one from the C code and one from the template file.  To link them all together use gcc again but with a specific set of libraries.  Into a terminal type,

terminal $ gcc f.o addtwof.o libML64i3.a -lm -lpthread -lrt -lstdc++ -o program

This will output an executable, here called program.  The library calls are quite complicated.  Of the 5 calls, 4 are normal enough and all begin with -l.  The final one is a Mathematica one, there are two libraries.  The above code calls the 64-bit version, there is a 32-bit version called libML32o3.a.  Both of which are in the same location as the mprep file.  The code I have given assumes the libraries have been moved to the directory where all the object files are.  You will need to tweak the terminal commands or copy files around, as is appropriate.

The above procedure is the details of the mcc script.  Passing the template file and C code to the mcc script causes several things.  Firstly mcc works out where the mprep program and all the libraries it needs are, which architecture it is running on and what C compile it has to use.  Then it starts mprep and the C compiler as we have done.  In fact, if you can not find certain files, you can open the mcc script (it is easier to find because it is also in a file with the other Mathematica executables) and read where files are and generally how mcc works.

If you have got this far then it is easy to use your executable in Mathematica with the Install command as before.

By studying this tutorial and changing the relevant code it should be simple to have Mathematica call a C program that calls a very large range of languages.  It should be possible to produce very powerful tools using this method.

No comments:

Post a Comment