Go to the first, previous, next, last section, table of contents.


Writing an IDL file for a C library

When writing an IDL file for a C library that doesn't have an IDL interface already, the include files for that library are a good starting point: just copy the relevant type and functin declarations to the IDL file, then annotate them with IDL attributes to describe more precisely their actual behavior. The documentation of the library must be read carefully to determine the mode of function parameters ("in", "out", "inout"), the actual sizes of arrays, etc.

The type definitions in the IDL file need not correspond exactly with those in the include files. Often, a cleaner Caml interface can be obtained by omitting irrelevant struct fields, or changing their types. For instance, the Unix library functions for reading library entries uses the following structure:


        struct dirent {
            long int d_ino;
            __off_t d_off;
            unsigned short int d_reclen;
            unsigned char d_type;
            char d_name[256];
        };

Of those fields, only "d_name" and "d_ino" are of interest to the user; the other fields are internal information for the library functions, are not specified in the POSIX specs, and therefore must not be used. Thus, in the IDL file, you should declare:


        struct dirent {
            long int d_ino;
            char d_name[256];
        };

Thus, the Caml code will have "type struct_dirent = {d_ino: int; d_name: string}" as desired. However, the generated stub code, being compiled against the "true" definition of "struct dirent", will find those two fields at the correct offsets in the actual struct.

Special attention must be paid to integer fields or variables. By default, integer IDL types are mapped to the Caml type "int", which is convenient to use in Caml code, but loses one bit when converting from a C "long" integer, and may lose one bit (on 32-bit platforms) when converting from a C "int" integer. When the range of values represented by the C integer is small enough, this loss is acceptable. Otherwise, you should use the attributes "nativeint", "int32" or "int64" so that integer IDL types are mapped to one of the Caml boxed integer types. (We recommend that you use "int32" or "int64" for integers that are specified as being exactly 32 bit wide or 64 bit wide, and "nativeint" for unspecified "int" or "long" integers.)

Yet another possibility is to declare certain integer fields or variables as "double" in the IDL file, so that they are represented by "float" in Caml, and all 32 bits of the integer are preserved in Caml. For instance, the Unix function to get the current type is declared as


        time_t time(time_t * t);

where "time_t" is usually defined as "long". We can nonetheless pretend (in the IDL file) that "time" returns a double:


        double time() quote(" _res = time(NULL); ");

This way, "time" will have the Caml type "unit -> float". Again, the stub code "knows" that "time" actually returns an integer, and therefore will insert the right integer-float coercions.


Go to the first, previous, next, last section, table of contents.