2.13.5 Special Topic: Portability of MathLink Programs
The Mathematica side of a MathLink connection is set up to work exactly the same on all computer systems. But inevitably there are differences between external programs on different computer systems.
For a start, different computer systems almost always require different executable binaries. When you call Install["prog"], therefore, you must be sure that prog corresponds to a program that can be executed on your particular computer system.
Installing programs on different computer systems.
|Install["file"] ||try to execute file directly |
|use the specified protocol for low-level data transport |
|$SystemID ||identify the type of computer system being used |
|Install["dir"] ||try to execute a file with a name of the form dir/$SystemID/dir |
Mathematica follows the convention that if prog is an ordinary file, then Install["prog"] will just try to execute it. But if prog is a directory, then Mathematica will look for a subdirectory of that directory whose name agrees with the current value of $SystemID, and will then try to execute a file named prog within that subdirectory.
Typical Unix commands for compiling external programs.
|mcc -o prog ... ||put compiled code in the file prog in the current directory |
|mcc -xo prog ... ||put compiled code in prog/$SystemID/prog |
Even though the executable binary of an external program is inevitably different on different computer systems, it can still be the case that the source code in a language such as C from which this binary is obtained can be essentially the same.
But to achieve portability in your C source code there are several points that you need to watch.
For a start, you should never make use of extra features of the C language or C run-time libraries that happen to be provided on a particular system, but are not part of standard C. In addition, you should try to avoid dealing with segmented or otherwise special memory models.
The include file mathlink.h contains standard C prototypes for all the functions in the MathLink library. If your compiler does not support such prototypes, you can ignore them by giving the directive #define MLPROTOTYPES 0 before #include "mathlink.h". But assuming that it does support prototypes, your compiler will always be able to check that the calls you make to functions in the MathLink library have arguments of appropriate types.
MathLink functions that use specific C types.
|MLPutInteger() ||MLGetInteger() ||default integer of type int; sometimes 16 bits, sometimes 32 bits |
|MLPutShortInteger() ||MLGetShortInteger() ||short integer of type short; usually 16 bits |
|MLPutLongInteger() ||MLGetLongInteger() ||long integer of type long; usually 32 bits |
|MLPutReal() ||MLGetReal() ||default real number of type double; usually at least 64 bits |
|MLPutFloat() ||MLGetFloat() ||single-precision floating-point number of type float; often 32 bits |
|MLPutDouble() ||MLGetDouble() ||double-precision floating-point number of type double; usually at least 64 bits |
On some computer systems and with some compilers, a C language int may be equivalent to a long. But the standard for the C language equally well allows int to be equivalent to short. And if you are going to call MathLink library functions in a portable way, it is essential that you use the same types as they do.
Once you have passed your data into the MathLink library functions, these functions then take care of all further issues associated with differences between data representations on different computer systems. Thus, for example, MathLink automatically swaps bytes when it sends data between big and little endian machines, and converts floating-point formats losing as little precision as possible.
Manipulating general strings.
|MLPutString(stdlink, char *s) ||put a string without special characters |
MLPutUnicodeString(stdlink, unsigned short *s, long n)
|put a string encoded in terms of 16-bit Unicode characters |
MLPutByteString(stdlink, unsigned char *s, long n)
|put a string containing only 8-bit character codes |
|MLGetString(stdlink, char **s) ||get a string without special characters |
MLGetUnicodeString(stdlink, unsigned short **s, long *n)
|get a string encoded in terms of 16-bit Unicode characters |
MLGetByteString(stdlink, unsigned char **s, long *n, long spec)
|get a string containing only 8-bit character codes, using spec as the code for all 16-bit characters |
In simple C programs, it is typical to use strings that contain only ordinary ASCII characters. But in Mathematica it is possible to have strings containing all sorts of special characters. These characters are specified within Mathematica using Unicode character codes, as discussed in Section 2.8.9.
C language char * strings typically use only 8 bits to store the code for each character. Unicode character codes, however, require 16 bits. As a result, the functions MLPutUnicodeString() and MLGetUnicodeString() work with arrays of unsigned short integers.
If you know that your program will not have to handle special characters, then you may find it convenient to use MLPutByteString() and MLGetByteString(). These functions represent all characters directly using 8-bit character codes. If a special character is sent from Mathematica, then it will be converted by MLGetByteString() to a fixed code that you specify.
A point to watch in creating portable MathLink programs.
|• main() may need to be different on different computer systems |
Computer systems and compilers that have C run-time libraries based on the Unix model allow MathLink programs to have a main program of the form main(argc, argv) which simply calls MLMain(argc, argv).
Some computer systems or compilers may however require main programs of a different form. You should realize that you can do whatever initialization you want inside main() before calling MLMain(). Once you have called MLMain(), however, your program will effectively go into an infinite loop, responding to requests from Mathematica until the link to it is closed.