/trunk/Doc/Manual/Ocaml.html
HTML | 991 lines | 830 code | 159 blank | 2 comment | 0 complexity | 884d9a27b53c0188aa531301a74d6826 MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>SWIG and Ocaml</title>
- <link rel="stylesheet" type="text/css" href="style.css">
- </head>
- <body bgcolor="#ffffff">
- <a name="n1"></a>
- <H1><a name="Ocaml"></a>29 SWIG and Ocaml</H1>
- <!-- INDEX -->
- <div class="sectiontoc">
- <ul>
- <li><a href="#Ocaml_nn2">Preliminaries</a>
- <ul>
- <li><a href="#Ocaml_nn3">Running SWIG</a>
- <li><a href="#Ocaml_nn4">Compiling the code</a>
- <li><a href="#Ocaml_nn5">The camlp4 module</a>
- <li><a href="#Ocaml_nn6">Using your module</a>
- <li><a href="#Ocaml_nn7">Compilation problems and compiling with C++</a>
- </ul>
- <li><a href="#Ocaml_nn8">The low-level Ocaml/C interface</a>
- <ul>
- <li><a href="#Ocaml_nn9">The generated module</a>
- <li><a href="#Ocaml_nn10">Enums</a>
- <ul>
- <li><a href="#Ocaml_nn11">Enum typing in Ocaml</a>
- </ul>
- <li><a href="#Ocaml_nn12">Arrays</a>
- <ul>
- <li><a href="#Ocaml_nn13">Simple types of bounded arrays</a>
- <li><a href="#Ocaml_nn14">Complex and unbounded arrays</a>
- <li><a href="#Ocaml_nn15">Using an object</a>
- <li><a href="#Ocaml_nn16">Example typemap for a function taking float * and int</a>
- </ul>
- <li><a href="#Ocaml_nn17">C++ Classes</a>
- <ul>
- <li><a href="#Ocaml_nn18">STL vector and string Example</a>
- <li><a href="#Ocaml_nn19">C++ Class Example</a>
- <li><a href="#Ocaml_nn20">Compiling the example</a>
- <li><a href="#Ocaml_nn21">Sample Session</a>
- </ul>
- <li><a href="#Ocaml_nn22">Director Classes</a>
- <ul>
- <li><a href="#Ocaml_nn23">Director Introduction</a>
- <li><a href="#Ocaml_nn24">Overriding Methods in Ocaml</a>
- <li><a href="#Ocaml_nn25">Director Usage Example</a>
- <li><a href="#Ocaml_nn26">Creating director objects</a>
- <li><a href="#Ocaml_nn27">Typemaps for directors, <tt>directorin, directorout, directorargout</tt></a>
- <li><a href="#Ocaml_nn28"><tt>directorin</tt> typemap</a>
- <li><a href="#Ocaml_nn29"><tt>directorout</tt> typemap</a>
- <li><a href="#Ocaml_nn30"><tt>directorargout</tt> typemap</a>
- </ul>
- <li><a href="#Ocaml_nn31">Exceptions</a>
- </ul>
- </ul>
- </div>
- <!-- INDEX -->
- <p>
- This chapter describes SWIG's
- support of Ocaml. Ocaml is a relatively recent addition to the ML family,
- and is a recent addition to SWIG. It's the second compiled, typed
- language to be added. Ocaml has widely acknowledged benefits for engineers,
- mostly derived from a sophisticated type system, compile-time checking
- which eliminates several classes of common programming errors, and good
- native performance. While all of this is wonderful, there are well-written
- C and C++ libraries that Ocaml users will want to take advantage of as
- part of their arsenal (such as SSL and gdbm), as well as their own mature
- C and C++ code. SWIG allows this code to be used in a natural, type-safe
- way with Ocaml, by providing the necessary, but repetitive glue code
- which creates and uses Ocaml values to communicate with C and C++ code.
- In addition, SWIG also produces the needed Ocaml source that binds
- variants, functions, classes, etc.
- </p>
- <p>
- If you're not familiar with the Objective Caml language, you can visit
- <a href="http://www.ocaml.org/">The Ocaml Website</a>.
- </p>
- <H2><a name="Ocaml_nn2"></a>29.1 Preliminaries</H2>
- <p>
- SWIG 1.3 works with Ocaml 3.04 and above. Given the choice,
- you should use the latest stable release. The SWIG Ocaml module has
- been tested on Linux (x86,PPC,Sparc) and Cygwin on Windows. The
- best way to determine whether your system will work is to compile the
- examples and test-suite which come with SWIG. You can do this by running
- <tt>make check</tt> from the SWIG root directory after installing SWIG.
- The Ocaml module has been tested using the system's dynamic linking (the
- usual -lxxx against libxxx.so, as well as with Gerd Stolpmann's
- <a
- href="http://download.camlcity.org/download/">Dl package
- </a>. The ocaml_dynamic and ocaml_dynamic_cpp targets in the
- file Examples/Makefile illustrate how to compile and link SWIG modules that
- will be loaded dynamically. This has only been tested on Linux so far.
- </p>
- <H3><a name="Ocaml_nn3"></a>29.1.1 Running SWIG</H3>
- <p>
- The basics of getting a SWIG Ocaml module up and running
- can be seen from one of SWIG's example Makefiles, but is also described
- here. To build an Ocaml module, run SWIG using the <tt>-ocaml</tt>
- option.
- </p>
- <div class="code">
- <pre>
- %swig -ocaml example.i
- </pre>
- </div>
-
- <p> This will produce 3 files. The file <tt>example_wrap.c</tt> contains
- all of the C code needed to build an Ocaml module. To build the module,
- you will compile the file <tt>example_wrap.c</tt> with <tt>ocamlc</tt> or
- <tt>ocamlopt</tt> to create the needed .o file. You will need to compile
- the resulting .ml and .mli files as well, and do the final link with -custom
- (not needed for native link). </p>
-
- <H3><a name="Ocaml_nn4"></a>29.1.2 Compiling the code</H3>
- <p>
- The O'Caml SWIG module now requires you to compile a module (<tt>Swig</tt>)
- separately. In addition to aggregating common SWIG functionality, the Swig
- module contains the data structure that represents C/C++ values. This allows
- easier data sharing between modules if two or more are combined, because
- the type of each SWIG'ed module's c_obj is derived from Swig.c_obj_t. This
- also allows SWIG to acquire new conversions painlessly, as well as giving
- the user more freedom with respect to custom typing.
- Use <tt>ocamlc</tt> or <tt>ocamlopt</tt> to compile your
- SWIG interface like:
- </p>
-
- <div class="code">
- <pre>
- % swig -ocaml -co swig.mli ; swig -ocaml co swig.ml
- % ocamlc -c swig.mli ; ocamlc -c swig.ml
- % ocamlc -c -ccopt "-I/usr/include/foo" example_wrap.c
- % ocamlc -c example.mli
- % ocamlc -c example.ml
- </pre>
- </div>
-
- <p> <tt>ocamlc</tt> is aware of .c files and knows how to handle them. Unfortunately,
- it does not know about .cxx, .cc, or .cpp files, so when SWIG is invoked
- in C++ mode, you must: </p>
-
- <div class="code">
- <pre>
- % cp example_wrap.cxx example_wrap.cxx.c<br>% ocamlc -c ... -ccopt -xc++ example_wrap.cxx.c<br>% ...<br>
- </pre>
- </div>
- <H3><a name="Ocaml_nn5"></a>29.1.3 The camlp4 module</H3>
- <p>
- The camlp4 module (swigp4.ml -> swigp4.cmo) contains a simple rewriter which
- makes C++ code blend more seamlessly with objective caml code. It's use is
- optional, but encouraged. The source file is included in the Lib/ocaml
- directory of the SWIG source distribution. You can checkout this file with
- <tt>"swig -ocaml -co swigp4.ml"</tt>. You should compile the file with
- <tt>"ocamlc -I `camlp4 -where` -pp 'camlp4o pa_extend.cmo q_MLast.cmo' -c swigp4.ml"</tt>
- </p>
- <p>
- The basic principle of the module is to recognize certain non-caml expressions
- and convert them for use with C++ code as interfaced by SWIG. The camlp4
- module is written to work with generated SWIG interfaces, and probably isn't
- great to use with anything else.
- </p>
- <p>
- Here are the main rewriting rules:
- </p>
- <table border="1" summary="Rewriting rules">
- <tr><th>Input</th><th>Rewritten to</th></tr>
- <tr><td>f'( ... ) as in<br> atoi'("0") or<br> _exit'(0)</td>
- <td>f(C_list [ ... ]) as in<br> atoi (C_list [ C_string "0" ]) or<br> _exit (C_list [ C_int 0 ])</td></tr>
- <tr><td>object -> method ( ... )</td><td>(invoke object) "method" (C_list [ ... ])</td></tr>
- <tr><td>
- object <i>'binop</i> argument as in<br>
- a '+= b</td>
- <td>
- (invoke object) "+=" argument as in<br>
- (invoke a) "+=" b<td></tr>
- <tr><th colspan=2>Note that because camlp4 always recognizes <<
- and >>, they are replaced by lsl and lsr in operator names.
- <tr><td>
- <i>'unop</i> object as in<br>
- '! a
- </td><td>
- (invoke a) "!" C_void</td></tr>
- <tr><td>
- <b>Smart pointer access like this</b><br>
- object '-> method ( args )<br>
- </td><td>
- (invoke (invoke object "->" C_void))
- </td></tr>
- <tr><td>
- <b>Invoke syntax</b><br>
- object . '( ... )
- </td><td>
- (invoke object) "()" (C_list [ ... ])
- </td></tr>
- <tr><td>
- <b>Array syntax</b><br>
- object '[ 10 ]
- </td><td>
- (invoke object) "[]" (C_int 10)
- </td></tr>
- <tr><td>
- <b>Assignment syntax</b><br>
- let a = '10 and b = '"foo" and c = '1.0 and d = 'true
- </td><td>
- let a = C_int 10 and b = C_string "foo" and c = C_double 1.0 and d = C_bool true
- </td></tr>
- <tr><td>
- <b>Cast syntax</b><br>
- let a = _atoi '("2") as int<br>
- let b = (getenv "PATH") to string<br>
- This works for int, string, float, bool
- </td><td>
- let a = get_int (_atoi (C_string "2"))<br>
- let b = C_string (getenv "PATH")
- </td></tr>
- </table>
- <H3><a name="Ocaml_nn6"></a>29.1.4 Using your module</H3>
- <p>
- You can test-drive your module by building a
- toplevel ocaml interpreter. Consult the ocaml manual for details.
- </p>
-
- <p>
- When linking any ocaml bytecode with your module, use the -custom
- option to build your functions into the primitive list. This
- option is not needed when you build native code.
- </p>
- <H3><a name="Ocaml_nn7"></a>29.1.5 Compilation problems and compiling with C++</H3>
- <p>
- As mentioned above, .cxx files need special
- handling to be compiled with <tt>ocamlc</tt>. Other than that, C code
- that uses <tt>class</tt> as a non-keyword, and C code that is too
- liberal with pointer types may not compile under the C++ compiler.
- Most code meant to be compiled as C++ will not have problems.
- </p>
- <H2><a name="Ocaml_nn8"></a>29.2 The low-level Ocaml/C interface</H2>
- <p>
- In order to provide access to overloaded functions, and
- provide sensible outputs from them, all C entities are represented as
- members of the c_obj type:
- </p>
- <p>
- In the code as seen by the typemap
- writer, there is a value, swig_result, that always contains the
- current return data. It is a list, and must be appended with the
- caml_list_append function, or with functions and macros provided by
- objective caml.<br>
- </p>
-
- <div class="code"><pre>
- type c_obj =
- C_void
- | C_bool of bool
- | C_char of char
- | C_uchar of char
- | C_short of int
- | C_ushort of int
- | C_int of int
- | C_uint of int32
- | C_int32 of int32
- | C_int64 of int64
- | C_float of float
- | C_double of float
- | C_ptr of int64 * int64
- | C_array of c_obj array
- | C_list of c_obj list
- | C_obj of (string -> c_obj -> c_obj)
- | C_string of string
- | C_enum of c_enum_t
- </pre></div>
- <p>
- A few functions exist which generate and return these:
- </p>
-
- <ul>
- <li>caml_ptr_val receives a c_obj and returns a void *. This
- should be used for all pointer purposes.</li>
- <li>caml_long_val receives a c_obj and returns a long. This
- should be used for most integral purposes.<br>
- </li>
- <li>caml_val_ptr receives a void * and returns a c_obj.</li>
- <li>caml_val_bool receives a C int and returns a c_obj representing
- it's bool value.</li>
- <li>caml_val_(u)?(char|short|int|long|float|double) receives an
- appropriate C value and returns a c_obj representing it.</li>
- <li>caml_val_string receives a char * and returns a string value.</li>
- <li>caml_val_string_len receives a char * and a length and returns
- a string value.</li>
- <li>caml_val_obj receives a void * and an object type and returns
- a C_obj, which contains a closure giving method access.</li>
-
- </ul>
- <p>
- Because of this style, a typemap can return any kind of value it
- wants from a function. This enables out typemaps and inout typemaps
- to work well. The one thing to remember about outputting values
- is that you must append them to the return list with swig_result = caml_list_append(swig_result,v).
- </p>
- <p>
- This function will return a new list that has your element
- appended. Upon return to caml space, the fnhelper function
- beautifies the result. A list containing a single item degrades to
- only that item (i.e. [ C_int 3 ] -> C_int 3), and a list
- containing more than one item is wrapped in C_list (i.e. [ C_char
- 'a' ; C_char 'b' -> C_list [ C_char 'a' ; C_char b
- ]). This is in order to make return values easier to handle
- when functions have only one return value, such as constructors,
- and operators. In addition, string, pointer, and object
- values are interchangeable with respect to caml_ptr_val, so you can
- allocate memory as caml strings and still use the resulting
- pointers for C purposes, even using them to construct simple objects
- on. Note, though, that foreign C++ code does not respect the garbage
- collector, although the SWIG interface does.</p>
- <p>
- The wild card type that you can use in lots of different ways is
- C_obj. It allows you to wrap any type of thing you like as an
- object using the same mechanism that the ocaml module
- does. When evaluated in caml_ptr_val, the returned value is
- the result of a call to the object's "&" operator, taken as a pointer.
- </p>
- <p>
- You should only construct values using objective caml, or using the
- functions caml_val_* functions provided as static functions to a SWIG
- ocaml module, as well as the caml_list_* functions. These functions
- provide everything a typemap needs to produce values. In addition,
- value items pass through directly, but you must make your own type
- signature for a function that uses value in this way.
- </p>
- <H3><a name="Ocaml_nn9"></a>29.2.1 The generated module</H3>
- <p>
- The SWIG <tt>%module</tt> directive specifies the name of the Ocaml
- module to be generated. If you specified `<tt>%module example</tt>',
- then your Ocaml code will be accessible in the module Example. The
- module name is always capitalized as is the ocaml convention. Note
- that you must not use any Ocaml keyword to name your module. Remember
- that the keywords are not the same as the C++ ones.
- </p>
- <p>
- You can introduce extra code into the output wherever you like with SWIG.
- These are the places you can introduce code:
- <table border="1" summary="Extra code sections">
- <tr><td>"header"</td><td>This code is inserted near the beginning of the
- C wrapper file, before any function definitions.</td></tr>
- <tr><td>"wrapper"</td><td>This code is inserted in the function definition
- section.</td></tr>
- <tr><td>"runtime"</td><td>This code is inserted near the end of the C wrapper
- file.</td></tr>
- <tr><td>"mli"</td><td>This code is inserted into the caml interface file.
- Special signatures should be inserted here.
- </td></tr>
- <tr><td>"ml"</td><td>This code is inserted in the caml code defining the
- interface to your C code. Special caml code, as well as any initialization
- which should run when the module is loaded may be inserted here.
- </td></tr>
- <tr><td>"classtemplate"</td><td>The "classtemplate" place is special because
- it describes the output SWIG will generate for class definitions.
- </td></tr>
- </table>
-
- <H3><a name="Ocaml_nn10"></a>29.2.2 Enums</H3>
- <p>
- SWIG will wrap enumerations as polymorphic variants in the output
- Ocaml code, as above in C_enum. In order to support all
- C++-style uses of enums, the function int_to_enum and enum_to_int are
- provided for ocaml code to produce and consume these values as
- integers. Other than that, correct uses of enums will not have
- a problem. Since enum labels may overlap between enums, the
- enum_to_int and int_to_enum functions take an enum type label as an
- argument. Example:
- </p>
- <div class="code"><pre>
- %module enum_test
- %{
- enum c_enum_type { a = 1, b, c = 4, d = 8 };
- %}
- enum c_enum_type { a = 1, b, c = 4, d = 8 };
- </pre></div>
- <p>
- The output mli contains:
- </p>
- <div class="code"><pre>
- type c_enum_type = [
- `unknown
- | `c_enum_type
- ]
- type c_enum_tag = [
- `int of int
- | `a
- | `b
- | `c
- | `d
- ]
- val int_to_enum c_enum_type -> int -> c_obj
- val enum_to_int c_enum_type -> c_obj -> c_obj
- </pre>
- </div>
- <p>
- So it's possible to do this:
- </p>
- <div class="code">
- <pre>
- bash-2.05a$ ocamlmktop -custom enum_test_wrap.o enum_test.cmo -o enum_test_top
- bash-2.05a$ ./enum_test_top
- Objective Caml version 3.04
- # open Enum_test ;;
- # let x = C_enum `a ;;
- val x : Enum_test.c_obj = C_enum `a
- # enum_to_int `c_enum_type x ;;
- - : Enum_test.c_obj = C_int 1
- # int_to_enum `c_enum_type 4 ;;
- - : Enum_test.c_obj = C_enum `c
- </pre>
- </div>
- <H4><a name="Ocaml_nn11"></a>29.2.2.1 Enum typing in Ocaml</H4>
- <p>
- The ocaml SWIG module now has support for loading and using multiple SWIG
- modules at the same time. This enhances modularity, but presents problems
- when used with a language which assumes that each module's types are complete
- at compile time. In order to achieve total soundness enum types are now
- isolated per-module. The type issue matters when values are shared between
- functions imported from different modules. You must convert values to master
- values using the swig_val function before sharing them with another module.
- </p>
- <H3><a name="Ocaml_nn12"></a>29.2.3 Arrays</H3>
- <H4><a name="Ocaml_nn13"></a>29.2.3.1 Simple types of bounded arrays</H4>
- <p>
- SWIG has support for array types, but you generally will need to provide
- a typemap to handle them. You can currently roll your own, or expand
- some of the macros provided (but not included by default) with the SWIG
- distribution.
- </p>
- <p>
- By including "carray.i", you will get access to some macros that help you
- create typemaps for array types fairly easily.
- </p>
- <p>
- <tt>%make_simple_array_typemap</tt> is the easiest way to get access to
- arrays of simple types with known bounds in your code, but this only works
- for arrays whose bounds are completely specified.
- </p>
- <H4><a name="Ocaml_nn14"></a>29.2.3.2 Complex and unbounded arrays</H4>
- <p>
- Unfortunately, unbounded arrays and pointers can't be handled in a
- completely general way by SWIG, because the end-condition of such an
- array can't be predicted. In some cases, it will be by consent
- (e.g. an array of four or more chars), sometimes by explicit length
- (char *buffer, int len), and sometimes by sentinel value (0,-1,etc.).
- SWIG can't predict which of these methods will be used in the array,
- so you have to specify it for yourself in the form of a typemap.
- </p>
- <H4><a name="Ocaml_nn15"></a>29.2.3.3 Using an object</H4>
- <p>
- It's possible to use C++ to your advantage by creating a simple object that
- provides access to your array. This may be more desirable in some cases,
- since the object can provide bounds checking, etc., that prevents crashes.
- </p>
- <p>
- Consider writing an object when the ending condition of your array is complex,
- such as using a required sentinel, etc.
- </p>
- <H4><a name="Ocaml_nn16"></a>29.2.3.4 Example typemap for a function taking float * and int</H4>
- <p>
- This is a simple example <tt>in</tt> typemap for an array of float, where the
- length of the array is specified as an extra parameter. Other such typemaps
- will work similarly. In the example, the function printfloats is called with
- a float array, and specified length. The actual length reported in the len
- argument is the length of the array passed from ocaml, making passing an array
- into this type of function convenient.
- </p>
- <table border="1" bgcolor="#dddddd" summary="float * and int typemap example">
- <tr><th><center>tarray.i</center></th></tr>
- <tr><td><pre>
- %module tarray
- %{
- #include <stdio.h>
- void printfloats( float *tab, int len ) {
- int i;
- for( i = 0; i < len; i++ ) {
- printf( "%f ", tab[i] );
- }
- printf( "\n" );
- }
- %}
- %typemap(in) (float *tab, int len) {
- int i;
- /* $*1_type */
- $2 = caml_array_len($input);
- $1 = ($*1_type *)malloc( $2 * sizeof( float ) );
- for( i = 0; i < $2; i++ ) {
- $1[i] = caml_double_val(caml_array_nth($input,i));
- }
- }
- void printfloats( float *tab, int len );
- </pre></td></tr>
- <tr><th>Sample Run</th></tr>
- <tr><td><pre>
- # open Tarray ;;
- # _printfloats (C_array [| C_double 1.0 ; C_double 3.0 ; C_double 5.6666 |]) ;;
- 1.000000 3.000000 5.666600
- - : Tarray.c_obj = C_void
- </pre></td></tr></table>
- <H3><a name="Ocaml_nn17"></a>29.2.4 C++ Classes</H3>
- <p>
- C++ classes, along with structs and unions are represented by C_obj
- (string -> c_obj -> c_obj) wrapped closures. These objects
- contain a method list, and a type, which allow them to be used like
- C++ objects. When passed into typemaps that use pointers, they
- degrade to pointers through their "&" method. Every method
- an object has is represented as a string in the object's method table,
- and each method table exists in memory only once. In addition
- to any other operators an object might have, certain builtin ones are
- provided by SWIG: (all of these take no arguments (C_void))
- </p>
- <table summary="SWIG provided operators">
- <tr><td>"~"</td><td>Delete this object</td></tr>
- <tr><td>"&"</td><td>Return an ordinary C_ptr value representing this
- object's address</td></tr>
- <tr><td>"sizeof"</td><td>If enabled with ("sizeof"="1") on the module node,
- return the object's size in char.</td></tr>
- <tr><td>":methods"</td><td>Returns a list of strings containing the names of
- the methods this object contains</td></tr>
- <tr><td>":classof"</td><td>Returns the name of the class this object belongs
- to.</td></tr>
- <tr><td>":parents"</td><td>Returns a list of all direct parent classes which
- have been wrapped by SWIG.</td></tr>
- <tr><td>"::[parent-class]"</td><td>Returns a view of the object as the
- indicated parent class. This is mainly used internally by the SWIG module,
- but may be useful to client programs.</td></tr>
- <tr><td>"[member-variable]"</td><td>Each member variable is wrapped as a
- method with an optional parameter.
- Called with one argument, the member variable is set to the value of the
- argument. With zero arguments, the value is returned.
- </td></tr>
- </table>
- <p>
- Note that this string belongs to the wrapper object, and not
- the underlying pointer, so using create_[x]_from_ptr alters the
- returned value for the same object.
- </p>
- <H4><a name="Ocaml_nn18"></a>29.2.4.1 STL vector and string Example</H4>
- <p>
- Standard typemaps are now provided for STL vector and string. More are in
- the works. STL strings are passed just like normal strings, and returned
- as strings. STL string references don't mutate the original string, (which
- might be surprising), because Ocaml strings are mutable but have fixed
- length. Instead, use multiple returns, as in the argout_ref example.
- </p>
- <table border="1" bgcolor="#dddddd" summary="STL vector and string example">
- <tr><th><center>example.i</center></th></tr>
- <tr><td><pre>
- %module example
- %{
- #include "example.h"
- %}
- %include <stl.i>
- namespace std {
- %template(StringVector) std::vector < string >;
- };
- %include "example.h"
- </pre></td></tr>
- <tr><td><font size="-1"><i>This example is in Examples/ocaml/stl
- </i></font></td></tr>
- </table>
- <p>
- Since there's a makefile in that directory, the example is easy to build.
- </p>
- <p>
- Here's a sample transcript of an interactive session using a string vector
- after making a toplevel (make toplevel). This example uses the camlp4
- module.
- </p>
- <div class="code"><pre>
- bash-2.05a$ ./example_top
- Objective Caml version 3.06
- Camlp4 Parsing version 3.06
- # open Swig ;;
- # open Example ;;
- # let x = new_StringVector '() ;;
- val x : Example.c_obj = C_obj <fun>
- # x -> ":methods" () ;;
- - : Example.c_obj =
- C_list
- [C_string "nop"; C_string "size"; C_string "empty"; C_string "clear";
- C_string "push_back"; C_string "[]"; C_string "="; C_string "set";
- C_string "~"; C_string "&"; C_string ":parents"; C_string ":classof";
- C_string ":methods"]
- # x -> push_back ("foo") ;;
- - : Example.c_obj = C_void
- # x -> push_back ("bar") ;;
- - : Example.c_obj = C_void
- # x -> push_back ("baz") ;;
- - : Example.c_obj = C_void
- # x '[1] ;;
- - : Example.c_obj = C_string "bar"
- # x -> set (1,"spam") ;;
- - : Example.c_obj = C_void
- # x '[1] ;;
- - : Example.c_obj = C_string "spam"
- # for i = 0 to (x -> size() as int) - 1 do
- print_endline ((x '[i to int]) as string)
- done ;;
- foo
- bar
- baz
- - : unit = ()
- #
- </pre></div>
- <H4><a name="Ocaml_nn19"></a>29.2.4.2 C++ Class Example</H4>
- <p>
- Here's a simple example using Trolltech's Qt Library:
- </p>
- <table border="1" bgcolor="#dddddd" summary="Qt Library example">
- <tr><th><center>qt.i</center></th></tr>
- <tr><td><pre>
- %module qt
- %{
- #include <qapplication.h>
- #include <qpushbutton.h>
- %}
- class QApplication {
- public:
- QApplication( int argc, char **argv );
- void setMainWidget( QWidget *widget );
- void exec();
- };
- class QPushButton {
- public:
- QPushButton( char *str, QWidget *w );
- void resize( int x, int y );
- void show();
- };
- </pre></td></tr></table>
- <H4><a name="Ocaml_nn20"></a>29.2.4.3 Compiling the example</H4>
- <div class="code"><pre>
- bash-2.05a$ QTPATH=/your/qt/path
- bash-2.05a$ for file in swig.mli swig.ml swigp4.ml ; do swig -ocaml -co $file ; done
- bash-2.05a$ ocamlc -c swig.mli ; ocamlc -c swig.ml
- bash-2.05a$ ocamlc -I `camlp4 -where` -pp "camlp4o pa_extend.cmo q_MLast.cmo" -c swigp4.ml
- bash-2.05a$ swig -ocaml -c++ -I$QTPATH/include qt.i
- bash-2.05a$ mv qt_wrap.cxx qt_wrap.c
- bash-2.05a$ ocamlc -c -ccopt -xc++ -ccopt -g -g -ccopt -I$QTPATH/include qt_wrap.c
- bash-2.05a$ ocamlc -c qt.mli
- bash-2.05a$ ocamlc -c qt.ml
- bash-2.05a$ ocamlmktop -custom swig.cmo -I `camlp4 -where` \
- camlp4o.cma swigp4.cmo qt_wrap.o qt.cmo -o qt_top -cclib \
- -L$QTPATH/lib -cclib -lqt
- </pre></div>
- <H4><a name="Ocaml_nn21"></a>29.2.4.4 Sample Session</H4>
- <div class="code"><pre>
- bash-2.05a$ ./qt_top
- Objective Caml version 3.06
- Camlp4 Parsing version 3.06
- # open Swig ;;
- # open Qt ;;
- # let a = new_QApplication '(0,0) ;;
- val a : Qt.c_obj = C_obj <fun>
- # let hello = new_QPushButton '("hi",0) ;;
- val hello : Qt.c_obj = C_obj <fun>
- # hello -> resize (100,30) ;;
- - : Qt.c_obj = C_void
- # hello -> show () ;;
- - : Qt.c_obj = C_void
- # a -> exec () ;;
- </pre></div>
- <p>
- Assuming you have a working installation of QT, you will see a window
- containing the string "hi" in a button.
- </p>
- <H3><a name="Ocaml_nn22"></a>29.2.5 Director Classes</H3>
- <H4><a name="Ocaml_nn23"></a>29.2.5.1 Director Introduction</H4>
- <p>
- Director classes are classes which allow Ocaml code to override the public
- methods of a C++ object. This facility allows the user to use C++ libraries
- that require a derived class to provide application specific functionality in
- the context of an application or utility framework.
- </p>
- <p>
- You can turn on director classes by using an optional module argument like
- this:
- </p>
- <div class="code"><pre>
- %module(directors="1")
- ...
- // Turn on the director class for a specific class like this:
- %feature("director")
- class foo {
- ...
- };
- </pre></div>
- <H4><a name="Ocaml_nn24"></a>29.2.5.2 Overriding Methods in Ocaml</H4>
- <p>
- Because the Ocaml language module treats C++ method calls as calls to a
- certain function, all you need to do is to define the function that will
- handle the method calls in terms of the public methods of the object, and
- any other relevant information. The function <tt>new_derived_object</tt>
- uses a stub class to call your methods in place of the ones provided by the
- underlying implementation. The object you receive is the underlying object,
- so you are free to call any methods you want from within your derived method.
- Note that calls to the underlying object do not invoke Ocaml code. You need
- to handle that yourself.
- </p>
- <p>
- <tt>new_derived_object</tt> receives your function, the function that creates
- the underlying object, and any constructor arguments, and provides an
- object that you can use in any usual way. When C++ code calls one of the
- object's methods, the object invokes the Ocaml function as if it had been
- invoked from Ocaml, allowing any method definitions to override the C++ ones.
- </p>
- <p>
- In this example, I'll examine the objective caml code involved in providing
- an overloaded class. This example is contained in Examples/ocaml/shapes.
- </p>
- <H4><a name="Ocaml_nn25"></a>29.2.5.3 Director Usage Example</H4>
- <table border="1" bgcolor="#dddddd" summary="Director usage example">
- <tr><th><center>example_prog.ml</center>
- </th></tr>
- <tr><td><pre>
- open Swig
- open Example
- ...
- let triangle_class pts ob meth args =
- match meth with
- "cover" ->
- (match args with
- C_list [ x_arg ; y_arg ] ->
- let xa = x_arg as float
- and ya = y_arg as float in
- (point_in_triangle pts xa ya) to bool
- | _ -> raise (Failure "cover needs two double arguments."))
- | _ -> (invoke ob) meth args ;;
- let triangle =
- new_derived_object
- new_shape
- (triangle_class ((0.0,0.0),(0.5,1.0),(1.0,0.0)))
- '() ;;
- let _ = _draw_shape_coverage '(triangle, C_int 60, C_int 20) ;;
- </pre></td></tr>
- </table>
- <p>
- This is the meat of what you need to do. The actual "class" definition
- containing the overloaded method is defined in the function triangle_class.
- This is a lot like the class definitions emitted by SWIG, if you look at
- example.ml, which is generated when SWIG consumes example.i. Basically,
- you are given the arguments as a c_obj and the method name as a string, and
- you must intercept the method you are interested in and provide whatever
- return value you need. Bear in mind that the underlying C++ code needs the
- right return type, or an exception will be thrown. This exception will
- generally be Failure, or NotObject. You must call other ocaml methods that
- you rely on yourself. Due to the way directors are implemented, method
- calls on your object from with ocaml code will always invoke C++ methods
- even if they are overridden in ocaml.
- </p>
- <p>
- In the example, the draw_shape_coverage function plots the indicated number
- of points as either covered (<tt>x</tt>) or uncovered ( ) between
- 0 and 1 on the X and Y axes. Your shape implementation can provide any
- coverage map it likes, as long as it responds to the "cover" method call
- with a boolean return (the underlying method returns bool). This might allow
- a tricky shape implementation, such as a boolean combination, to be expressed
- in a more effortless style in ocaml, while leaving the "engine" part of the
- program in C++.
- </p>
- <H4><a name="Ocaml_nn26"></a>29.2.5.4 Creating director objects</H4>
- <p>
- The definition of the actual object triangle can be described this way:
- </p>
- <div class="code"><pre>
- let triangle =
- new_derived_object
- new_shape
- (triangle_class ((0.0,0.0),(0.5,1.0),(1.0,0.0)))
- '()
- </pre></div>
- <p>
- The first argument to <tt>new_derived_object</tt>, new_shape is the method
- which returns a shape instance. This function will be invoked with the
- third argument will be appended to the argument list [ C_void ]. In the
- example, the actual argument list is sent as (C_list [ C_void ; C_void ]).
- The augmented constructor for a director class needs the first argument
- to determine whether it is being constructed as a derived object, or as
- an object of the indicated type only (in this case <tt>shape</tt>). The
- Second argument is a closure that will be added to the final C_obj.
- </p>
- <p>
- The actual object passed to the self parameter of the director object will
- be a C_director_core, containing a c_obj option ref and a c_obj. The
- c_obj provided is the same object that will be returned from new_derived
- object, that is, the object exposing the overridden methods. The other part
- is an option ref that will have its value extracted before becoming the
- <tt>ob</tt> parameter of your class closure. This ref will contain
- <tt>None</tt> if the C++ object underlying is ever destroyed, and will
- consequently trigger an exception when any method is called on the object
- after that point (the actual raise is from an inner function used by
- new_derived_object, and throws NotObject). This prevents a deleted C++
- object from causing a core dump, as long as the object is destroyed
- properly.
- </p>
- <H4><a name="Ocaml_nn27"></a>29.2.5.5 Typemaps for directors, <tt>directorin, directorout, directorargout</tt></H4>
- <p>
- Special typemaps exist for use with directors, the <tt>directorin, directorout, directorargout</tt>
- are used in place of <tt>in, out, argout</tt> typemaps, except that their
- direction is reversed. They provide for you to provide argout values, as
- well as a function return value in the same way you provide function arguments,
- and to receive arguments the same way you normally receive function returns.
- </p>
- <H4><a name="Ocaml_nn28"></a>29.2.5.6 <tt>directorin</tt> typemap</H4>
- <p>
- The <tt>directorin</tt> typemap is used when you will receive arguments from a call
- made by C++ code to you, therefore, values will be translated from C++ to
- ocaml. You must provide some valid C_obj value. This is the value your ocaml
- code receives when you are called. In general, a simple <tt>directorin</tt> typemap
- can use the same body as a simple <tt>out</tt> typemap.
- </p>
- <H4><a name="Ocaml_nn29"></a>29.2.5.7 <tt>directorout</tt> typemap</H4>
- <p>
- The <tt>directorout</tt> typemap is used when you will send an argument from your
- code back to the C++ caller. That is; directorout specifies a function return
- conversion. You can usually use the same body as an <tt>in</tt> typemap
- for the same type, except when there are special requirements for object
- ownership, etc.
- </p>
- <H4><a name="Ocaml_nn30"></a>29.2.5.8 <tt>directorargout</tt> typemap</H4>
- <p>
- C++ allows function arguments which are by pointer (*) and by reference (&)
- to receive a value from the called function, as well as sending one there.
- Sometimes, this is the main purpose of the argument given. <tt>directorargout</tt>
- typemaps allow your caml code to emulate this by specifying additional return
- values to be put into the output parameters. The SWIG ocaml module is a bit
- loose in order to make code easier to write. In this case, your return to
- the caller must be a list containing the normal function return first, followed
- by any argout values in order. These argout values will be taken from the
- list and assigned to the values to be returned to C++ through directorargout typemaps.
- In the event that you don't specify all of the necessary values, integral
- values will read zero, and struct or object returns have undefined results.
- </p>
- <H3><a name="Ocaml_nn31"></a>29.2.6 Exceptions</H3>
- <p>
- Catching exceptions is now supported using SWIG's %exception feature. A simple
- but not too useful example is provided by the throw_exception testcase in
- Examples/test-suite. You can provide your own exceptions, too.
- </p>
- </body>
- </html>