How do I link C++ code with OCaml? Let's say I have a main program in
C/C++ and a function I want to call in OCaml:
---- main.c / main.cpp ---
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/callback.h>
int main (int argc, char ** argv) {
char * caml_argv[argc + 1];
int i;
for (i = 0; i < argc + 1; i++) caml_argv[i] = argv[i];
caml_argv[argc] = NULL;
caml_main (caml_argv);
return 0;
}
--------
---- test.ml ----
let f x = x + 1
let () = Callback.register "test" f
--------
If I name the main program "main.c", I can compile the code like this
with no trouble whatsoever:
gcc -I /opt/local/lib/ocaml -c main.c
ocamlopt -o main test.cmx main.o
If I name the main program "main.cpp", and run the same commands---
gcc -I /opt/local/lib/ocaml -c main.cpp
ocamlopt -o main test.cmx main.o
---then I get this:
Undefined symbols:
"_caml_atom_table", referenced from:
_intern_alloc in libasmrun.a(intern.o)
_intern_rec in libasmrun.a(intern.o)
_caml_alloc in libasmrun.a(alloc.o)
_caml_alloc_dummy_float in libasmrun.a(alloc.o)
_caml_alloc_dummy in libasmrun.a(alloc.o)
_caml_alloc_array in libasmrun.a(alloc.o)
"___gxx_personality_v0", referenced from:
_main in main.o
CIE in main.o
"_caml_code_area_start", referenced from:
_extern_rec in libasmrun.a(extern.o)
_extern_rec in libasmrun.a(extern.o)
_segv_handler in libasmrun.a(signals_asm.o)
_caml_code_checksum in libasmrun.a(intern.o)
_intern_rec in libasmrun.a(intern.o)
"_caml_code_area_end", referenced from:
_extern_rec in libasmrun.a(extern.o)
_segv_handler in libasmrun.a(signals_asm.o)
_caml_code_checksum in libasmrun.a(intern.o)
"caml_main(char**)", referenced from:
_main in main.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
File "caml_startup", line 1, characters 0-1:
Error: Error during linking
Now I know gcc does something slightly different with cpp files, and I
can eliminate the complaint about the __gxx symbol if I add "-cclib
-lstdc++" (which I fully expected to need working with C++ programs).
But why are the caml symbols missing!?!? (It took me over 2 hours to
figure out it was the "cpp" extension that was the root of these
missing caml symbols in my real program because that was the *last*
thing I expected.) I'm using OCaml 3.11.1 on OS X 10.6.2.
- Aaron
_______________________________________________
Caml-list mailing list. Subscription management:
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
Archives: http://caml.inria.fr
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
You might try (when mixing C++ and OCaml) wrapping the whole thing in an
'extern "C" {...}' block (*including* the #includes and the entire main
function).
Robert Roessler
> You might try (when mixing C++ and OCaml) wrapping the whole thing in an
> 'extern "C" {...}' block (*including* the #includes and the entire main
> function).
Thanks for the tip. This does resolve the missing caml symbols (even
when naming the file with a cpp extension). However, my real program
actually uses some C++ features. I think I could convert it to a real
C program, but I assumed there would be some other way.
- Aaron
I suspect it will work if only the #include directives pertaining to Caml
header files are marked as 'extern "C"'. You just need to tell the compiler to
use the C linkage convention rather than the C++ name mangling convention for
the external Caml functions that your program (implicitly or explicitly) calls.
This is done at the function prototype site, not the call site. Everything
else in the program should be unaffected.
Xavier, could the headers have the guards added? (I only spot-checked one,
mlvalues.h, and that didn't appear to have it).
Mark
What you can do is to create a thin C layer between your Ocaml and C++ code.
I am including a very simple code - an interface to the Cubpack
library in Ocaml.
If your interface is big, you might try some of the authomatic
builders like SWIG (http://www.swig.org) which I understand can wrap
C++ classes for use in Ocaml.
Jan
--
-------------------------------------------------------------------------
Jan Kybic <ky...@fel.cvut.cz> tel. +420 2 2435 5721
http://cmp.felk.cvut.cz/~kybic ICQ 20056945
// stub to call Cubpack++ integration routines from Ocaml
//
//
// Jan Kybic, February 2004
// $Id: cubpack_stub.cc 322 2004-02-06 18:03:01Z jkybic $
extern "C" {
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/callback.h>
}
#include <cubpack.h>
#include <stdio.h>
// This code is NOT thread safe
// There is nothing to do about it except change Cubpack++
static value ocamlCallback ;
// Call a Ocaml function with two arguments u,v
real evalOcaml(const Point& p) {
CAMLparam0() ;
double z ;
CAMLlocal3(ou,ov,oz) ;
ou=copy_double(p.X()) ;
ov=copy_double(p.Y()) ;
oz=callback2(ocamlCallback,ou,ov) ;
z=Double_val(oz) ;
CAMLreturn(z) ;
}
static double doIntegrate(double a, double r,int m) {
CAMLparam0() ;
Point p1(0.0,0.0), p2(0.0,1.0), p3(1.0,0.0);
TRIANGLE T(p1,p2,p3);
CAMLreturn (Integrate(evalOcaml,T)) ;
}
extern "C"
// parameters: absolute and relative error bounds, maximum number
// of evaluations, the function to evaluate
value cubpackIntegrateTriangle (value a,value r,value m,value f) {
CAMLparam4(a,r,m,f) ; // register for GC
CAMLlocal1(z) ;
register_global_root(&ocamlCallback) ;
ocamlCallback=f ;
z=copy_double(doIntegrate(Double_val(a),Double_val(r),Int_val(m))) ;
remove_global_root(&ocamlCallback) ;
CAMLreturn(z) ;
}
// end of cubpack_stub.cc
In addition of all the other good answers, you could look at how some existing C++ open-source libraries interface to Ocaml.
Both the Parma Polyhedra Library (PPL, under GPLv3 licence), at http://www.cs.unipr.it/ppl/ and the Low Level Virtual
Machine library (LLVM, under a BSD-like licence) at http://llvm.org/ are free libraries, coded in C++, interfaced to Ocaml.
Regards.
--
Basile STARYNKEVITCH http://starynkevitch.net/Basile/
email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359
8, rue de la Faiencerie, 92340 Bourg La Reine, France
*** opinions {are only mines, sont seulement les miennes} ***
extern "C" {
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/callback.h>
}
Thanks to everyone for the helpful comments.
- Aaron