Ciml

Information

Introduction

Ciml is a Camlp4 extension which allows the inlining of C code and provides helpers for type conversion inside OCaml code. For example, one could use the following :

letext hello (s:string) : unit =  << 
printf("Hello %s !\n", s);
Return();
>>

How does it work ?

It is important to understand how Ciml works in order to use it correctly. Ciml does not compile C code, nor does it use Camlp4 to do so. What Ciml does is just strip out the C code from the OCaml code, and write it to a temporary C file. Using an intelligent Makefile you then compile that file and then link it to the OCaml compiled module.

Inlining C code

The letext statement is very similar to OCaml's let statement, and they share the same syntax. However, please note that letext statement's are only allowed at a top level (not nested).

Moreover, as the functions are declared as external, their type cannot be infered. This is why one needs to manually declare all types (which should nevertheless be done by using the external statement).

C code is surrounded by << and >> which represents quotations for Camlp4. If some C code is found at an expression level (inside a letext) it will automatically be wrapped into a C function declaration. C code found at the top level (statement level) will just be copied to the temporary C file.

Here is an example :

<<
// this is some C code at the statement level
// it is directly copied
#include <stdio.h>
>>
letext hello (s:string) : unit = <<
printf("Hello %s !\n", s);
Return();
>>

When preprocessed, the following file is created :

#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <caml/memory.h>
#include <caml/fail.h>
#include <caml/callback.h>
#include <caml/custom.h>
#include <caml/intext.h>


// this is some C code at the statement level
// it is directly copied
#include <stdio.h>

value hello (value s__0) {
CAMLparam1(s__0);
char* s = String_val(s__0);

#define Return(foo) CAMLreturn(Val_unit)

printf("Hello %s !\n", s);
Return();

#undef Return
}

You might notice that several other instructions were added to the source code :

Type Conversion

Here again, a little history: when a C function is called from OCaml as external, OCaml passes its arguments with the value C type. One then uses one of the Int_val, String_val, etc. macro to convert the value to whatever type is needed.

As Ciml is aware of the type of the arguments, automatic type converters are implemented. For example, when one writes :

letext hello (s:string) : unit =  << 
printf("Hello %s !\n", s);
Return();
>>

The s argument is passed as a value to the C function, but there is an automatic conversion using String_val (because we know that s is a string). Conversely, returned values are automatically converted:

// use:
Return(42);
// don't use:
Return(Val_int(42));

Currently, type converters are implemented for int, bool, float, string, unit.

Custom converters

You can add and remove custom converters using the following syntax:

(* add *)
register_fromval "Int_val" "int" : int
register_toval "Val_int" : int

(* remove *)
unregister_fromval : int
unregister_toval : int

Releases

Sources

The sources are available in a darcs repository:

darcs get http://chadok.info/darcs/ciml

and can be browsed in a the Redmine project:

http://redmine.chadok.info/projects/ciml