% Ciml Information =========== * Authors * Adrien Friggeri * Olivier Schwander * Version : 0.42 * Licence : ? Introduction ============ Ciml is a [Camlp4](http://brion.inria.fr/gallium/index.php/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 : ~~~ {.ocaml} 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 : ~~~ {.ocaml} << // this is some C code at the statement level // it is directly copied #include >> letext hello (s:string) : unit = << printf("Hello %s !\n", s); Return(); >> ~~~ When preprocessed, the following file is created : ~~~ {.c} #include #include #include #include #include #include #include // this is some C code at the statement level // it is directly copied #include 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 : * Several includes, those are needed in order to link OCaml and C * `CAMLParam1` and `CAMLreturn`, those are used to deal with the garbarge collector * `#define Return(foo)`, this allows you to simply write `Return()` at the end of your function, instead of some complex stuff. * ... actually, Ciml does much more than that... 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 : ~~~ {.ocaml} 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: ~~~ {.ocaml} // 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: ~~~ {.ocaml} (* add *) register_fromval "Int_val" "int" : int register_toval "Val_int" : int (* remove *) unregister_fromval : int unregister_toval : int ~~~ Sources ======= The sources are available in a darcs repository: darcs get http://chadok.info/darcs/ciml