Previous Home Contents Next

Chapter 19: Using Aldor with C

19.1 Using C code from Aldor

19.2 Using Aldor code from C

19.3 Data correspondence

Functions and data structures may be shared between programs written in Aldor and other languages. Here we give simple examples of sharing functions in a mixed Aldor and C programming environment.

Aldor has types corresponding to the primitive C types. These will be described in section 19.3.



19.1 : Using C code from Aldor

For the first example, we show how to call a C function from Aldor. The Aldor file ``arigato.as'' refers to the function ``nputs'', supplied by the C file ``nputs.c''. Figure 1 shows these files.

The commands to compile these two files and link them together, say on Unix, are:

% cc -c nputs.c
% aldor -Fx arigato.as nputs.o
% arigato

Arigato gozaimasu!
Arigato gozaimasu!
Arigato gozaimasu!

The first command produces the object file ``nputs.o''. The second command compiles the file ``arigato.as'' and links it with our other file to form an executable program. Finally, the third command runs the resulting program.

The Aldor compiler can make use of C-generated object files, whether they are kept loose or packaged with others in a library archive. The Aldor file using the code or data from C must declare it with the statement ``import ... from Foreign C'': this is the purpose of this statement in ```arigato.as''. When a function is imported from C, a declaration is placed at the head of the generated C file. This declaration is constructed using the data correspondence below.

To call a C function or macro (such as ``fputc'') defined in a header file (such as ``<stdio.h>'' or ``myfile.h'') an import of the following form should be used:

The filename indicates the file to include when generating C. No declaration for ``fputc'' or ``myfun'' is produced in the generated C -- it is assumed that all the imports are declared (or, in the case of macros, defined).

A ``#include'' line is produced for every header file mentioned in the source code, even when no imported function is used. This allows some of the definitions in ``foam_c.h'' to be over-ridden. For example, one could replace the memory management primitives with operations specifically optimized for the current application.

Figure 19.1: Aldor code using a C function

--
-- arigato.as: A main Aldor program calling the C function 'nputs'.
--
#include "aldor.as"

SI ==> SingleInteger;

import { nputs: (SI, String) -> SI } from Foreign C;
import from SI;

nputs(3, "Arigato gozaimasu!");
/*
 * nputs.c: A simple C function.
 */
void
nputs(int n, char *s)
{
        int     i;
        for (i = 0; i < n; i++) puts(s);
}


Figure 19.2: C code using Aldor function.
/*
 * cside.c:   A main C program calling the A# function 'lcm'.
 */
#include "foam_c.h"

extern FiSInt   lcm      (FiSInt, FiSInt);

int 
main()
{
        printf("The lcm of 6 and 4 is %d\n", lcm(6,4));
        return 0;
}
--
-- aside.as: An Aldor function made available to C.
--
#include "aldor.as"

SI ==> SingleInteger;

export { lcm: (SI, SI) -> SI } to Foreign C;

lcm(n: SI, m: SI): SI == (n quo gcd(n,m)) * m;




19.2 : Using Aldor code from C

For the second example, we show how to call an Aldor function from C.

C code which uses Aldor functions should include the file
``foam_c.h''. This file contains C type definitions corresponding to the various Aldor primitive types. For example, ``FiSInt'' is a typedef for the C type corresponding to ``SingleInteger''. On Unix, the full path name for this file is ``$ALDORROOT/include/foam_c.h''.

For this example, the C file ``cside.c'' refers to the function ``lcm'', supplied by the Aldor file ``aside.as''. These files are shown in figure 19.2.

The commands to compile, link, and run these files are:

% aldor -Fo aside.as
% cc -I$ALDORROOT/include -c cside.c
% cc cside.o aside.o -o lcm64 -L$ALDORROOT/lib -laldor -lfoam -lm
% lcm64

The lcm of 6 and 4 is 12

The first command compiles the Aldor code in the normal way to produce an object file. On Unix, this produces the object file ``aside.o''.

Compiling the C code which uses ``aside.o'' requires the use of a ``-I'' option to tell the compiler where to find ``foam_c.h''.

Additional options are needed to link an executable program: a ``-L'' option tells the C compiler where to look for libraries, and the ``-l'' options list the libraries which provide Aldor support functions.

The ``-laldor'' option provides a library with basic Aldor types such as floating point numbers, lists, file I/O, and so on.

The ``-lfoam'' option provides a library with run-time support for such things as memory management and big integer arithmetic. Applications can supply their own run time support library instead, if desired. Basically, the idea is to provide alternative macro definitions in ``foam_c.h'' and a C file with whatever code is needed by the macros.

The -lm option makes the standard C math library available. Because of the way Aldor compiles domains, this generally needs to be included even if no operations from the math library are used.

In ``aside.as'', the line beginning ``export to'' tells the export compiler that a wrapper function called lcm should be generated for the Aldor function with the same name. This wrapper will convert the C calling convention into that used by Aldor using the rules in the next section. Currently it is possible to export only functions in this way (an Aldor constant can be wrapped in a function, and types have no particular use in C).



19.3 : Data correspondence

This section describes the correspondence between the way data values are represented in Aldor and the way they are represented in C. It should be possible from this to understand which Aldor declaration will correspond to a declaration in C, and vice versa.

Aldor's abstract machine defines a number of types which correspond to types on the target machine (in this case C on top of some operating system). The ``Machine'' package, described in section 13.16, exports the types provided by the abstract machine. All Aldor values are represented internally as elements of one of these types. The complete listing and definition of the types is given in the FOAM reference guide.

Because many Aldor domains can be parameterized over different types, Aldor uses a pointer-sized object when passing domains. Thus, double precision floating point numbers (which are typically bigger than pointers) are ``boxed'', and a pointer to the box is passed, rather than the number itself. Types which are the same size or smaller than pointer-size are cast to the pointer type when used in a generic context and cast back as appropriate.

In order to make the underlying types available, Aldor provides the ``Machine'' package, which exports these types and operations on them. For example, the underlying representation type of DoubleFloat is DFlo$Machine. This type should be used when calling foreign functions, and the result coerced back to appropriate generic type at the Aldor level.

Records in Aldor are represented by an aggregate type of some kind in the hosting language. For example, in Scheme a vector is used (and all objects are the same size anyway). In C, structures are used. When calling C-defined functions that use records it is important to ensure that the elements of the Aldor record correspond to elements in the C structure. This implies that records intended for use in Foreign functions should use the underlying types, rather than the user-level types.

The Aldor types correspond to C types given as typedefs in the file ``$ALDORROOT/include/foam_c.h''. The following table shows the correspondance between the types exported from the Aldor package ``Machine'' and C:

Aldor typeC typedefUsual C type
   
Nil$MachineFiNilPtr
Word$MachineFiWordint
Arb$MachineFiArblong int
Ptr$Machine FiPtr Ptr
Bool$MachineFiBoolchar
Byte$MachineFiBytechar
HInt$MachineFiHIntshort
SInt$MachineFiSIntlong
Char$MachineFiCharchar
Arr$MachineFiArrPtr
Rec$MachineFiRecPtr
BInt$MachineFiBIntPtr
SFlo$MachineFiSFlofloat
DFlo$MachineFiDFlodouble
A -> BFiClosstruct _FiClos *

Here ``Ptr'' is defined as the type ``char *'' for compatibility with old C dialects, but could equally well be defined as ``void *''.

All other user defined types in Aldor correspond to the C linebreak typedef ``FiWord''. This includes Integer, SingleInteger and so on. The data correspondence on most 32 bit machines allows one to treat SingleInteger and SInt$Machine as the same type (which is the reason that arigato, above, works). However, on other machines, for example 16 or 64 bit machines, the two types are not equivalent.

Values belonging to "Record" types, are pointers to C structs of the corresponding members. For example, the C declaration

corresponds to the Aldor declaration Functions which return no value, or more than one value, are declared to be of type void, and additional return results are returned through pointers passed in as additional arguments.

Thus the expression:

implies that foo should be declared (in ANSI C) as:

A number of examples of exporting and importing C-defined functions can be found in ``$ALDORROOT/samples/test''.


Previous Home Contents Next