previous next top contents index framed top this page unframed
10.1. FLI Compilers
The Foreign Call Compiler (FCC) is used to call foreign procedures from
MAINSAIL. The MAINSAIL Entry Compiler (MEC) is used to call MAINSAIL
PROCEDUREs from a foreign language.
Under UNIX, the FCC interfaces to C
and is available on all available flavors of UNIX. The MEC also
interfaces to C and is available for the flavors listed in
Appendix A. If the foreign language to be called does
not conform to the C calling conventions, then the standard FLI
compilers cannot be used. Contact XIDAK if you wish an interface between
such a language and UNIX MAINSAIL.
The compiler subcommands required to specify the FLIs to and from C are FLI TC and FLI FC, except as documented in Appendix A.
The default output file name for the MAINSAIL FLI compilers is:
module name, converted to lower case.s
For older code that does not use the C data type macros, and for data types not listed in Appendix L of the MAINSAIL Language Manual, Table 10–1 shows how C data types are mapped to MAINSAIL data types on UNIX operating systems. The byte sizes shown are usual for C implementations on byte-addressable machines, although it is possible that users may encounter a dialect of C with data types of sizes other than those shown in Table 10–1; if so, the following discussion must be modified accordingly.
Table 10–1. MAINSAIL and C Parameter Data Types
| C Type | MAINSAIL Type | Representation Passed |
|---|---|---|
| short | BOOLEAN, INTEGER, BITS | 2 bytes |
| long | LONG INTEGER, LONG BITS | same size as POINTER or ADDRESS |
| pointer | POINTER, ADDRESS | 4 bytes on 32-bit platform; 8 bytes on 64-bit platform |
| float | REAL | 4 bytes |
| double | LONG REAL | 8 bytes |
| char array | STRING, CHARADR | address of first character (STRING passed to C must be explicitly NUL-terminated) |
| array (passed from MAINSAIL to C) | ARRAY | address of first element |
| dataType * (passed from C to MAINSAIL) | ADDRESS | address of first element |
USES parameters are passed by value. MODIFIES and PRODUCES parameters are passed by reference. The C * operator may be used when declaring MODIFIES and PRODUCES parameters.
USES parameters of MAINSAIL types STRING and POINTER can be passed from MAINSAIL to C. Parameters of MAINSAIL types POINTER and STRING cannot be passed from C to MAINSAIL. MODIFIES and PRODUCES parameters of MAINSAIL types STRING and POINTER are not allowed.
MAINSAIL STRINGs can be directly passed to C, i.e., the parameter is declared using the MAINSAIL STRING data type. C expects strings to be terminated with a NUL byte; cWrite(s,0) or s := $cStr(s) can be used to append a NUL byte to the MAINSAIL STRING s.
When a MAINSAIL POINTER is passed to C, the C structure and the MAINSAIL CLASS must be declared such that the data in the structure are accessed correctly by both languages. Some flavors of UNIX have data alignment requirements that affect the location of members in C structures; see Appendix A for more information.
The MAINSAIL representation of a BOOLEAN should be translated into C as a short, with 0 representing MAINSAIL FALSE and 1 representing MAINSAIL TRUE.
A MAINSAIL NULLARRAY is passed to C as a Zero address.
C must check that
the address is non-Zero before accessing any
array elements if there is
a possibility that a MAINSAIL NULLARRAY has been passed.
An ARRAY field of a MAINSAIL class is
represented as a POINTER to the
ARRAY data, but a C array member of
a struct is included inline in the
struct.
Consequently, a POINTER to a MAINSAIL
CLASS containing ARRAY fields
cannot be mapped to a C struct containing array members.
For example, consider the MAINSAIL CLASS and C struct
declarations:
In memory, records of these types might look like Figure 10–2.
In order to get the address of the first element of a MAINSAIL
ARRAY that is not a parameter, but rather
a field or element of a data structure passed to
C, you must use the C function xiAdrOfFirstElement;
see Section 7.9 of the MAINSAIL Compiler User's Guide.
To prevent data that would normally be collectable from being moved
by the MAINSAIL memory manager, it may be useful to put those data
in an anchored area, as described in Section 25.4 of the MAINSAIL Language Manual.
Appendix A lists other restrictions and caveats for
specific UNIX flavors.
10.2.1. MAINSAIL and C Arrays
ARRAY parameters are passed to C by passing the
address of the first
element of the ARRAY. The Foreign Call Compiler generates code to
convert each MAINSAIL ARRAY parameter to the address of its first
element. MAINSAIL stores ARRAYs in row-major form. If your C
implementation
does not follow this convention, care must be taken with the
indices.
MAINSAIL
C CLASS c (
INTEGER field1;
REAL ARRAY(1 TO 3) field2;
LONG INTEGER field3,field4;
INTEGER ARRAY(1 TO 4) field5;
REAL field6;
);struct c {
short field1;
float field2[3];
long field3,field4;
short field5[4];
float field6;
}
10.3. Caveat: Beware of Overwriting Data
When dealing with collectable MAINSAIL
data types (STRINGs, POINTERs, and
ARRAYs), care must be taken not to violate the data boundaries.
Overwriting the wrong parts of these structures may cause MAINSAIL to
crash in ways that are difficult to trace. If, for example, a garbage
collection link is destroyed, MAINSAIL may run until a collection is
triggered, at which point the results are unpredictable.
10.4. ANSI C FLI Caveat
Currently, each UNIX FLI code generator follows the K & R C argument
passing conventions, which are:
Such conversions are typically not performed for arguments and results of functions declared with ANSI function prototypes. Thus, ANSI function prototypes should not be used to declare the C functions that correspond to FLI PROCEDUREs if the C functions have either short or float arguments passed by value or short or float results.
This restriction does not imply that only K & R C compilers may be used to compile C functions that correspond to FLI PROCEDUREs; ANSI C compilers may be used as well. It implies only that C functions must be declared using the K & R C syntax.
For example, corresponding to the following MAINSAIL PROCEDURE header:
$CFLOAT PROCEDURE p ($CSHORT i; $CLFOAT r);
you should declare the C function p as:
float p (i, r)
short i;
float r;
instead of:
float p (short i, float r)
Figure 10–3. MAINSAIL MODULE CALLC That Calls C Procedure proc1
| MODULE CALLC (in file callc.msl):
BEGIN "callC" |
Figure 10–4. C Procedure proc1
| C procedure proc1 (in file cproc.c):
proc1 (i,j,k,c,p,s,ary) |
Figure 10–5. MAINSAIL Foreign Language Interface MODULE MSTOC
| MAINSAIL MODULE MSTOC (in file mstoc.msl):
BEGIN "msToC" |
Example 10–6. MAINSAIL to C Example
|
Suppose that the C procedure callms is to call the MAINSAIL PROCEDURE proc1. Figures 10–7, 10–8, 10–9, and 10–10 show the C procedure callms, the MAINSAIL MODULE MSMOD that contains the PROCEDURE proc1, the MAINSAIL FLI MODULE MSTOC, and the MAINSAIL MODULE CALLC that calls the C procedure callms, respectively. Example 10–11 shows how to compile and run callms.
Figure 10–7. C Procedure That Calls MAINSAIL PROCEDURE proc1
| C program (in file callms.c):
callms () |
Figure 10–8. MAINSAIL MODULE MSMOD Called by C Procedure callms
| MAINSAIL MODULE MSMOD (in file msmod.msl):
BEGIN "msMod" |
Figure 10–9. MAINSAIL Foreign Language Interface MODULE MSTOC
| MAINSAIL MODULE MSTOC (in file mstoc.msl):
BEGIN "msToC" |
Figure 10–10. MAINSAIL MODULE CALLC That Calls C Procedure callms
| MAINSAIL MODULE CALLC (in file callc.msl):
BEGIN "callC" |
Example 10–11. C to MAINSAIL Example
|
In order for foreign code to start execution, you must build the bootstrap slightly differently from the way shown in Example 10–11:
For example, assume that the function callms in the file callms.c of Figure 10–7 is renamed to main, and the file itself is renamed to main.c, as shown in Figure 10–12.
Figure 10–12. C Program with Function main That Calls MAINSAIL PROCEDURE proc1
| C program (in file main.c):
main () |
To link a bootstrap named main that calls proc1 in the MODULE MSMOD of Figure 10–8, follow the example shown in Example 10–13 (adapting the example as necessary for your platform; see Appendix A).
Example 10–13. C to MAINSAIL Example When Foreign Code Starts Execution
|
The problem is that when MAINSAIL reads from standard input, it never reads more than one line (up to the next newline character), regardless of whether standard input is a terminal or a disk file. The implementation of gets and fgets, however, reads only a single line of input from a terminal, but reads enough to fill up a fixed-size buffer when reading from a disk file. This buffer is inaccessible to MAINSAIL. After C does a gets or fgets on stdin, MAINSAIL acts as if the unprocessed text up to the end of C's buffer is missing from the file.
A solution to the problem is to use something like the following function mygets instead of gets to read from standard input:
#include <stdio.h>
#define cr 13
#define fdStdin 0
#define fdStdout 1
char *mygets(buf) char *buf;
{
char c;
int i, n;
char *b = buf;
if (isatty(fdStdin)) return gets(buf); /* gets works for tty */
/* Simulate reading a line from the input file or pipe by
* reading one character at-a-time.
*/
for (n = 0; ;) {
if ((i = read(fdStdin,&c,1)) < 0 )
return NULL; /* documented gets() behavior */
if (!i) break;
n++;
if ( c == '\n' ) break; /* discard newline */
*b++ = c;
}
if (!n) return NULL; /* documented gets() behavior */
*b++ = '\0'; /* NUL-terminate the result */
return buf;
}
It is possible to link C or C++ code that calls X with a MAINSAIL bootstrap that also calls X. In order to do this, you need to make some changes to your C code, and you need to link in an additional file from the MAINSAIL directory.
10.9.1. Changes to C Code
If you wish to link C or C++ code that calls X routines with a MAINSAIL
bootstrap that may also call X routines, then to avoid initializing X
twice (which the X routines do not expect and do not handle correctly),
your C/C++ program should call:
#include <xinit1ce.h>
...
xtAppInitializeJustOnce(...);
(note the initial lowercase x in xtAppInitializeJustOnce) instead of the standard X Toolkit initialization function XtAppInitialize (or any other X Toolkit initialization function, e.g., XtToolkitInitialize). xtAppInitializeJustOnce takes exactly the same parameters as XtAppInitialize, but if it has already been called, it returns the same value (and sets app_context_return to the same value) as when it was called the first time. Later calls to xtAppInitializeJustOnce do not parse or modify the argv_in_out, fallback_resources, or args arguments.
MAINSAIL always initializes the X Toolkit using xtAppInitializeJustOnce instead of XtAppInitialize.
The include file xinit1ce.h resides on the MAINSAIL directory. To compile a file that includes it, include the -I switch on the command line to the C compiler, specifying the MAINSAIL directory as an argument, e.g.:
-I/usr/mainsail/16.20.1
xinit1ce.h includes some additional .h files on the MAINSAIL directory; you cannot copy just the file xinit1ce.h to some other directory and expect the instructions to work.
You may use xtAppInitializeJustOnce
in applications that are not linked
with MAINSAIL.
The file xinit1ce.c on the MAINSAIL directory contains the
implementation of xtAppInitializeJustOnce;
just link the output from
this file in with your C program.
10.9.2. Building a MAINSAIL Bootstrap That Calls X Routines from
MAINSAIL
When you build a MAINSAIL bootstrap
that calls X routines from MAINSAIL
(e.g., to run the MAINSAIL Motif-based tools),
then when you run CONF,
you need to restore from the CONF parameters
file that contains the appropriate FOREIGNMODULES command.
This file is located on the MAINSAIL directory; its file name is:
platformAbbreviationm.cnf
e.g., sun4m.cnf.
When you link such a bootstrap, you need to include the file x.o (also located on the MAINSAIL directory) in your final cc or ld command line in addition to the usual m.o or f.o file.
If you link in the x.o file, you do not need to compile xinit1ce.c explicitly as part of your bootstrap, since x.o includes the output from xinit1ce.c.
On all platforms, you will need to link the standard X and Motif C libraries with your bootstrap; the usual cc switches to do this are:
-lXm -lXt -lX11
On some platforms, you must specify additional cc switches to link in additional C libraries when you build an X bootstrap (these are in addition to the libraries usually specified when you build a MAINSAIL bootstrap for that platform):
| Platform | cc Switches for X |
|---|---|
| hppa | -lPW |
| hppa64 | -lXp -lICE -lSM -lXext |
On the HP-UX system XIDAK used to develop the HPPA64 port,
the /usr/lib directory (where many of the 32-bit libraries are
stored) contained links to the
appropriate X and Motif libraries on other
directories, but there were no corresponding links in
/usr/lib/pa20_64,
the directory for 64-bit libraries. XIDAK therefore set up links
in /usr/lib/pa20_64 that point to the 64-bit X and Motif libraries
needed by the MAINSAIL Motif-based tools.
If you wish to use the MAINSAIL Motif-based tools on HPPA64,
we recommend that you set up links in /usr/lib/pa20_64 as follows,
if such links are not already present:
If you do not set up the links, the standard MAINSAIL installation
script ihppa64.com will fail to find the X/Motif libraries needed
to build the mainsam bootstrap.
(You may set up the links in some directory other then
/usr/lib/pa20_64, but then you will need to use the
-xl, -xtl, or -xml switch to ihppa64.com;
see the installation notes for HPPA64 for details.)
In each case, the “actual library” listed above is the
library that had the
highest-numbered suffix on the HPPA64 development machine used by
XIDAK;
if newer versions of the same libraries come out, you will probably
want to substitute them for the names shown above.
10.9.2.1. Setup of X/Motif Libraries on HPPA64
On HPPA64, file system links for
the libraries for X and Motif may need to be set up before
you install MAINSAIL, if you plan to use the Motif-based
MAINSAIL tools or create MAINSAIL bootstraps that make X calls.
Link Name Actual Library libXt.a /usr/lib/X11R6/pa20_64/libXt.3 libX11.a /usr/lib/X11R6/pa20_64/libX11.3 libXp.a /usr/lib/X11R6/pa20_64/libXp.2 libICE.a /usr/lib/X11R6/pa20_64/libICE.2 libSM.a /usr/lib/X11R6/pa20_64/libSM.2 libXext.a /usr/lib/X11R6/pa20_64/libXext.3 libXm.a /usr/lib/Motif2.1/pa20_64/libXm.4
10.9.2.2. X/Motif on Linux
MAINSAIL in conjunction with X and Motif has not been tested on
LINIA64 or LINPN, so Motif-related facilities
and Motif-based tools are not available on those platforms.
10.10. Passing Command Line Arguments from C
to MAINSAIL When Foreign Code Starts Execution:
UNIX-Specific Function xiSetArgvForMainsail
On UNIX, the C function xiSetArgvForMainsail allows you to pass command line arguments from C to MAINSAIL in bootstraps where foreign code starts execution.
The UNIX-specific function xiSetArgvForMainsail takes a single char** argument:
void xiSetArgvForMainsail (char **argv)
xiSetArgvForMainsail passes the argv argument (e.g., as passed to the C main function) to MAINSAIL. argv is terminated by a zero char pointer.
When C starts execution in a MAINSAIL bootstrap, MAINSAIL has no way to get a hold of argv unless you call xiSetArgvForMainsail to pass the argv value to MAINSAIL. If argv is not set, MAINSAIL will not have a value for $programName or be able to see the operating system's command line arguments.
Calling xiSetArgvForMainsail is not useful when MAINSAIL starts execution.
In C source files that call xiSetArgvForMainsail, include the header file ximslargv.h on the MAINSAIL directory with:
#include <ximslargv.h>
To compile a file that includes ximslargv.h, include the -I switch on the command line to the C compiler, specifying the MAINSAIL directory as an argument, e.g.:
-I/usr/mainsail/16.20.1
ximslargv.h includes some additional .h files on the MAINSAIL directory; you cannot copy just the file ximslargv.h to some other directory and expect the instructions to work.
MAINSAIL System-Specific User's Guides, Chapter 10