caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* How to wrap around C++?
@ 2010-02-08  2:13 Luca de Alfaro
  2010-02-08  4:06 ` Michael Ekstrand
  2010-02-08 12:38 ` [Caml-list] " Guillaume Yziquel
  0 siblings, 2 replies; 11+ messages in thread
From: Luca de Alfaro @ 2010-02-08  2:13 UTC (permalink / raw)
  To: Inria Ocaml Mailing List

[-- Attachment #1: Type: text/plain, Size: 862 bytes --]

I need to be able to call some C++ functions from my Ocaml code.
Can someone point me to some examples on how this is done?  Is it an issue
if what I need to wrap is C++, rather than the more standard C?

I also would like to know if I can do something more complex... namely, I
would like to create a C++ object, and return it to Ocaml.
Ocaml then needs to be able to call methods of that object.  The object does
not need to be directly accessible from Ocaml, but it needs to be
persistent, so that all Ocaml calls refer to the same object.

Essentially, the C++ object implements access to a file via some
compression, etc, mechanism.  In C++, one creates the object, calls write
and read methods, calls the method for closing the file, and deletes the
object.

How can I wrap around such an object in Ocaml?  Is it possible?  Any
advice?

Many thanks,

Luca

[-- Attachment #2: Type: text/html, Size: 1031 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: How to wrap around C++?
  2010-02-08  2:13 How to wrap around C++? Luca de Alfaro
@ 2010-02-08  4:06 ` Michael Ekstrand
  2010-02-08  4:17   ` Michael Ekstrand
  2010-02-08 16:03   ` [Caml-list] " Luca de Alfaro
  2010-02-08 12:38 ` [Caml-list] " Guillaume Yziquel
  1 sibling, 2 replies; 11+ messages in thread
From: Michael Ekstrand @ 2010-02-08  4:06 UTC (permalink / raw)
  To: caml-list

On 02/07/2010 08:13 PM, Luca de Alfaro wrote:
> Essentially, the C++ object implements access to a file via some
> compression, etc, mechanism.  In C++, one creates the object, calls
> write and read methods, calls the method for closing the file, and
> deletes the object. 
> 
> How can I wrap around such an object in Ocaml?  Is it possible?  Any
> advice? 

It is possible.  One way would be to use Swig.  The other is to write
the wrappers yourself, providing OCaml external functions for each of
the methods you want to call.  If it's just a few methods, it isn't too
difficult.  The documentation on interfacing with OCaml from C (in the
manual) is quite helpful with several examples, albeit all for C.  For
C++, there are just a few additional things to think about (that I know of):

* Make sure no C++ exceptions leak to OCaml.
* Wrap your OCaml includes in 'extern "C" { ... }"
* Export all your stub functions with C linkage (extern "C")
* Compiling is tricky, since the OCaml compiler driver doesn't know what
to do with C++.  The Swig documentation[1] has a workaround for this,
useful even if you don't use Swig.

You can use OCaml's custom object support to manage the class instnaces.
 Your custom block will store a pointer to the object.  The finalizer
will then need to take care of deleting the object (or decreasing its
reference count, or whatever is appropriate).

The basic thing you'll do is to create an ML file defining an abstract
type for your object, external functions for your wrapper stubs (which
need to be plain C functions taking and returning OCaml values), and
then whatever higher-level convenience functions (or classes, if you
want to re-wrap the C++ code in an OCaml object-oriented interface) you
want to expose for actually using the module.

- Michael


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: How to wrap around C++?
  2010-02-08  4:06 ` Michael Ekstrand
@ 2010-02-08  4:17   ` Michael Ekstrand
  2010-02-08 16:03   ` [Caml-list] " Luca de Alfaro
  1 sibling, 0 replies; 11+ messages in thread
From: Michael Ekstrand @ 2010-02-08  4:17 UTC (permalink / raw)
  To: caml-list

On 02/07/2010 10:06 PM, Michael Ekstrand wrote:
> * Compiling is tricky, since the OCaml compiler driver doesn't know what
> to do with C++.  The Swig documentation[1] has a workaround for this,
> useful even if you don't use Swig.

I forgot the footnote with a link:

1. http://www.swig.org/Doc1.3/Ocaml.html#Ocaml_nn4

- Michael


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Caml-list] How to wrap around C++?
  2010-02-08  2:13 How to wrap around C++? Luca de Alfaro
  2010-02-08  4:06 ` Michael Ekstrand
@ 2010-02-08 12:38 ` Guillaume Yziquel
  1 sibling, 0 replies; 11+ messages in thread
From: Guillaume Yziquel @ 2010-02-08 12:38 UTC (permalink / raw)
  To: Luca de Alfaro; +Cc: Inria Ocaml Mailing List

Luca de Alfaro a écrit :
> I need to be able to call some C++ functions from my Ocaml code.
> Can someone point me to some examples on how this is done?  Is it an issue
> if what I need to wrap is C++, rather than the more standard C?
> 
> I also would like to know if I can do something more complex... namely, I
> would like to create a C++ object, and return it to Ocaml.
> Ocaml then needs to be able to call methods of that object.  The object does
> not need to be directly accessible from Ocaml, but it needs to be
> persistent, so that all Ocaml calls refer to the same object.
> 
> Essentially, the C++ object implements access to a file via some
> compression, etc, mechanism.  In C++, one creates the object, calls write
> and read methods, calls the method for closing the file, and deletes the
> object.
> 
> How can I wrap around such an object in Ocaml?  Is it possible?  Any
> advice?
> 
> Many thanks,
> 
> Luca

As mentioned earlier there are Swig bindings from Art Yerkes that do 
work with OCaml. Unfortunately the documentation is rather terse, and 
you have code that believes somehow that OCaml is dynamically typed: You 
pass list as arguments, there is some runtime type checking done at the 
interface, and you may have to use Obj.magic on OCaml side.

I have started rewritting Swig bindings to make them static and 
hopefully more efficient. I nevertheless stopped (and I hope to come 
back to it) for two reasons: lack of time, and a major shortcoming on 
Swig side: typemaps do not allow to construct OCaml polymorphic type. 
This means that you have to declare an intlist type instead of an int 
list type. To amend that, you have to dig into Swig's internals. While 
possible, it is rather painful to do. And you really feel that Swig is 
more aimed at dynamically typed languages wishing to interface with C++ 
than at statically typed languages.

You can find my bitroting Swig module here:

http://swig.svn.sourceforge.net/viewvc/swig/branches/yziquel-ocaml/

(If someone feels like pursuing this Swig endeavour, I'll gladly help 
out...)

Here's an example of what you can obtain with Swig (but if I were you, 
I'd definitely do the bindings manually). You can go directly at the 
bottom of the email for the stub code per se. As you can see, you have 
to use extern "C" to be able to interface C++ with the C interface of 
OCaml. Concerning C++ objects, things depends. For instance, if the 
object is allocated on the stack, there's no way you can bring it back 
to OCaml. If it's allocated with new, you can indeed bring it back to 
OCaml. You simply have to register finalisers that trigger the 
destructor of the object once the OCaml GC reclaims it. (Assuming that 
no other OCaml values holds the object, that is...)

For the sake of exhaustivity, my Makefile was

> all: freeling.cma
> 
> freeling.cma: dllfreeling_stubs.so freeling.cmo freeling.cmo
>         ocamlc -a -dllib dllfreeling_stubs.so -dllib libmorfo.so -dllib libfries.so -dllib libpcre.so -dllib libomlet.so -dllib libdb_cxx.so -o freeling.cma freeling.cmo freeling.cmo
> 
> freeling.cmo: freeling.ml
>         ocamlc -c freeling.ml
> 
> freeling.cmo: freeling_wrap.cxx freeling.mli freeling.ml
>         ocamlc -c freeling.mli
>         ocamlc -c freeling.ml
> 
> dllfreeling_stubs.so: libfreeling_stubs.a freeling_wrap.cxx.o
>         ocamlmklib -o freeling_stubs freeling_wrap.cxx.o
> 
> libfreeling_stubs.a: freeling_wrap.cxx.o
>         ar rcs libfreeling_stubs.a freeling_wrap.cxx.o
> 
> freeling_wrap.cxx.o: freeling_wrap.cxx.c
>         gcc -fPIC -O2 -c -xc++ freeling_wrap.cxx.c
> 
> freeling_wrap.cxx.c: freeling_wrap.cxx
>         cp freeling_wrap.cxx freeling_wrap.cxx.c
> 
> freeling_wrap.cxx:
>         swig -ocaml -c++ freeling.i
> 
> clean:
>         rm -f freeling.ml
>         rm -f freeling.mli
>         rm -f freeling_wrap.cxx
>         rm -f freeling_wrap.cxx.c
>         rm -f freeling.cmi
>         rm -f freeling.cmo
>         rm -f freeling_wrap.cxx.o


The Swig interface file, freeling.i:

> %module freeling
> %{
>   #include "freeling.h"
> %}
> 
> %include <std_string.i>
> %include <std_list.i>
> 
> %nodefaultdtor;
> 
> %template() std::list<word>;
> 
> class tokenizer {
>    public:
>        /// Constructor
>        tokenizer(const std::string &);
> 
>        /// tokenize string with default options
>        std::list<word> tokenize(const std::string &);
>        /// tokenize string with default options, tracking offset in given int param.
>        //std::list<word> tokenize(const std::string &, unsigned long &);
> };

Was generating the following on the OCaml side:

> module Swig = struct
> 
>   (* The Swig module contains raw accessors to C functions,
>      as well as type declarations enforcing sound typing. *)
> 
>   type tokenizer
>   external _wrap_new_tokenizer : string -> tokenizer = "_wrap_new_tokenizer"
>   external _wrap_tokenizer_tokenize : tokenizer -> string -> ocaml_typeparm[word] list = "_wrap_tokenizer_tokenize"
> 
> end;;
> 
> class virtual _opaque_tokenizer = object(self)
>   val virtual underlying_cpp_object : Swig.tokenizer
>   method tokenize = Swig._wrap_tokenizer_tokenize underlying_cpp_object
> end;;
> 
> class type tokenizer = object
>   method tokenize : string -> ocaml_typeparm[word] list
> end;;
> 
> class tokenizer_0 arg0 = object(self)
>   inherit _opaque_tokenizer
>   val underlying_cpp_object = Swig._wrap_new_tokenizer arg0
> end;;

with the following .mli file:

> class type tokenizer = object
>   method tokenize : string -> ocaml_typeparm[word] list
> end
> 
> class tokenizer_0 : string -> tokenizer

and the following C stub code:

> #ifdef __cplusplus
> /* SwigValueWrapper is described in swig.swg */
> template<typename T> class SwigValueWrapper {
>   struct SwigMovePointer {
>     T *ptr;
>     SwigMovePointer(T *p) : ptr(p) { }
>     ~SwigMovePointer() { delete ptr; }
>     SwigMovePointer& operator=(SwigMovePointer& rhs) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = rhs.ptr; rhs.ptr = 0; return *this; }
>   } pointer;
>   SwigValueWrapper& operator=(const SwigValueWrapper<T>& rhs);
>   SwigValueWrapper(const SwigValueWrapper<T>& rhs);
> public:
>   SwigValueWrapper() : pointer(0) { }
>   SwigValueWrapper& operator=(const T& t) { SwigMovePointer tmp(new T(t)); pointer = tmp; return *this; }
>   operator T&() const { return *pointer.ptr; }
>   T *operator&() { return pointer.ptr; }
> };
> 
> template <typename T> T SwigValueInit() {
>   return T();
> }
> #endif
> 
> /* -----------------------------------------------------------------------------
>  *  This section contains generic SWIG labels for method/variable
>  *  declarations/attributes, and other compiler dependent labels.
>  * ----------------------------------------------------------------------------- */
> 
> /* template workaround for compilers that cannot correctly implement the C++ standard */
> #ifndef SWIGTEMPLATEDISAMBIGUATOR
> # if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
> #  define SWIGTEMPLATEDISAMBIGUATOR template
> # elif defined(__HP_aCC)
> /* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
> /* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
> #  define SWIGTEMPLATEDISAMBIGUATOR template
> # else
> #  define SWIGTEMPLATEDISAMBIGUATOR
> # endif
> #endif
> 
> /* inline attribute */
> #ifndef SWIGINLINE
> # if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
> #   define SWIGINLINE inline
> # else
> #   define SWIGINLINE
> # endif
> #endif
> 
> /* attribute recognised by some compilers to avoid 'unused' warnings */
> #ifndef SWIGUNUSED
> # if defined(__GNUC__)
> #   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
> #     define SWIGUNUSED __attribute__ ((__unused__)) 
> #   else
> #     define SWIGUNUSED
> #   endif
> # elif defined(__ICC)
> #   define SWIGUNUSED __attribute__ ((__unused__)) 
> # else
> #   define SWIGUNUSED 
> # endif
> #endif
> 
> #ifndef SWIG_MSC_UNSUPPRESS_4505
> # if defined(_MSC_VER)
> #   pragma warning(disable : 4505) /* unreferenced local function has been removed */
> # endif 
> #endif
> 
> #ifndef SWIGUNUSEDPARM
> # ifdef __cplusplus
> #   define SWIGUNUSEDPARM(p)
> # else
> #   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
> # endif
> #endif
> 
> /* internal SWIG method */
> #ifndef SWIGINTERN
> # define SWIGINTERN static SWIGUNUSED
> #endif
> 
> /* internal inline SWIG method */
> #ifndef SWIGINTERNINLINE
> # define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
> #endif
> 
> /* exporting methods */
> #if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
> #  ifndef GCC_HASCLASSVISIBILITY
> #    define GCC_HASCLASSVISIBILITY
> #  endif
> #endif
> 
> #ifndef SWIGEXPORT
> # if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
> #   if defined(STATIC_LINKED)
> #     define SWIGEXPORT
> #   else
> #     define SWIGEXPORT __declspec(dllexport)
> #   endif
> # else
> #   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
> #     define SWIGEXPORT __attribute__ ((visibility("default")))
> #   else
> #     define SWIGEXPORT
> #   endif
> # endif
> #endif
> 
> /* calling conventions for Windows */
> #ifndef SWIGSTDCALL
> # if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
> #   define SWIGSTDCALL __stdcall
> # else
> #   define SWIGSTDCALL
> # endif 
> #endif
> 
> /* Deal with Microsoft's attempt at deprecating C standard runtime functions */
> #if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
> # define _CRT_SECURE_NO_DEPRECATE
> #endif
> 
> /* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
> #if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
> # define _SCL_SECURE_NO_DEPRECATE
> #endif
> 
> 
> 
>   #include <stdlib.h>
>   #include <string.h>
>   #include <stdio.h>
> 
>   /* Including OCaml system. */
>   #define CAML_VALUE value
>   extern "C" {
>     #include <caml/alloc.h>
>     #include <caml/custom.h>
>     #include <caml/mlvalues.h>
>     #include <caml/memory.h>
>     #include <caml/callback.h>
>     #include <caml/fail.h>
>     #include <caml/misc.h>
>   }
> 
>   #define SWIG_CAMLlocal1(x) \
>     CAML_VALUE x = 0; \
>     CAMLxparam1 (x)
> 
>   #define SWIG_CAMLlocal2(x, y) \
>     CAML_VALUE x = 0, y = 0; \
>     CAMLxparam2 (x, y)
> 
>   #define SWIG_CAMLlocal3(x, y, z) \
>     CAML_VALUE x = 0, y = 0, z = 0; \
>     CAMLxparam3 (x, y, z)
> 
>   #define SWIG_CAMLlocal4(x, y, z, t) \
>     CAML_VALUE x = 0, y = 0, z = 0, t = 0; \
>     CAMLxparam4 (x, y, z, t)
> 
>   #define SWIG_CAMLlocal5(x, y, z, t, u) \
>     CAML_VALUE x = 0, y = 0, z = 0, t = 0, u = 0; \
>     CAMLxparam5 (x, y, z, t, u)
> 
>   #define SWIG_CAMLlocalN(x, size) \
>     CAML_VALUE x [(size)] = { 0, /* 0, 0, ... */ }; \
>     CAMLxparamN (x, (size))
> 
> 
> 
>   /* Declarations for custom block operations. */
> 
>   /* For more information of Objective Caml custom blocks,
>    * consult the Objective Caml manual, section 18.9. */
> 
>   static struct custom_operations custom_swigtype_ocaml_operations = {
>     "org.homelinux.yziquel.ocaml.swig",
>     custom_finalize_default,
>     custom_compare_default,
>     custom_hash_default,
>     custom_serialize_default,
>     custom_deserialize_default
>   };
> 
> 
> 
> #define SWIGVERSION 0x010340 
> #define SWIG_VERSION SWIGVERSION
> 
> 
> #define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
> #define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
> 
> 
>   #include "freeling.h"
> 
> 
> #include <stdexcept>
> 
> 
> #if defined(__GNUC__)
> #  if __GNUC__ == 2 && __GNUC_MINOR <= 96
> #     define SWIG_STD_NOMODERN_STL
> #  endif
> #endif
> 
> 
> #include <string>
> #include <stdexcept>
> 
> 
>   #include <string>
> 
> 
>   #include <list>
> 
> extern "C" CAML_VALUE _wrap_new_tokenizer (CAML_VALUE ocaml_arg1)
> {
>   CAMLparam0();
>   SWIG_CAMLlocal1(caml_result);
>   std::string *arg1 = 0 ;
>   CAMLxparam1(ocaml_arg1);
>   tokenizer *result = 0 ;
>   
>   {
>     std::string arg1_str(String_val(ocaml_arg1), caml_string_length(ocaml_arg1));
>     arg1 = &arg1_str;
>   }
>   result = (tokenizer *)new tokenizer((std::string const &)*arg1);
>   {
>     caml_result = caml_alloc_custom(&custom_swigtype_ocaml_operations, sizeof (void *), 0, 1);
>     *((void **) Data_custom_val(caml_result)) = (void *)result;
>   }
>   CAMLreturn(caml_result);
> }
> 
> extern "C" CAML_VALUE _wrap_tokenizer_tokenize (CAML_VALUE ocaml_arg1, CAML_VALUE ocaml_arg2)
> {
>   CAMLparam0();
>   SWIG_CAMLlocal1(caml_result);
>   tokenizer *arg1 = (tokenizer *) 0 ;
>   std::string *arg2 = 0 ;
>   CAMLxparam1(ocaml_arg1);
>   CAMLxparam1(ocaml_arg2);
>   std::list< word > result;
>   
>   arg1 = *((tokenizer * *) Data_custom_val(ocaml_arg1)); 
>   {
>     std::string arg2_str(String_val(ocaml_arg2), caml_string_length(ocaml_arg2));
>     arg2 = &arg2_str;
>   }
>   result = (arg1)->tokenize((std::string const &)*arg2);
>   {
>     caml_result = caml_alloc_custom(&custom_swigtype_ocaml_operations, sizeof (void *), 0 ,1);
>     *((void **) Data_custom_val(caml_result)) = new std::list< word >((const std::list< word > &)result);
>   }
>   CAMLreturn(caml_result);
> }
> 

-- 
      Guillaume Yziquel
http://yziquel.homelinux.org/


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Caml-list] Re: How to wrap around C++?
  2010-02-08  4:06 ` Michael Ekstrand
  2010-02-08  4:17   ` Michael Ekstrand
@ 2010-02-08 16:03   ` Luca de Alfaro
  2010-02-08 16:33     ` Luca de Alfaro
                       ` (2 more replies)
  1 sibling, 3 replies; 11+ messages in thread
From: Luca de Alfaro @ 2010-02-08 16:03 UTC (permalink / raw)
  To: Michael Ekstrand; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 1287 bytes --]

Thank you very much!  I follow the general lines, but...


> * Make sure no C++ exceptions leak to OCaml.
>

This will be next to impossible: the C++ code I need to wrap is huge, and I
have no idea of what possible exceptions can be generated.  I will have to
try to see if there is a generic exception catcher.


> * Wrap your OCaml includes in 'extern "C" { ... }"
>

Here, I am not sure what you mean.  You mean,

extern "C" {
#include <caml/mlvalues.h>
...
}

?


> * Export all your stub functions with C linkage (extern "C")
>

Ok, evidently, I need to learn this extern "C" construct.


> * Compiling is tricky, since the OCaml compiler driver doesn't know what
> to do with C++.  The Swig documentation[1] has a workaround for this,
> useful even if you don't use Swig.
>
>
Why would the Ocaml compiler driver need to know what to do with C++?
The C++ I need to link to is rather huge, and I will need to compile it with
its own build setup.
Once that is built, I need to compile the stubs, the Ocaml, and link the
three together (Ocaml, stubs, and C++), in native mode, but  why would the
Ocaml compiler need to deal with C++?

Another question: I could also try to do the vice-versa, and use Ocaml as
libraries from C++.  Has anybody tried doing this?  Is it easy to do?

Luca

[-- Attachment #2: Type: text/html, Size: 2180 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Caml-list] Re: How to wrap around C++?
  2010-02-08 16:03   ` [Caml-list] " Luca de Alfaro
@ 2010-02-08 16:33     ` Luca de Alfaro
  2010-02-08 17:44       ` Guillaume Yziquel
  2010-02-08 17:54     ` Guillaume Yziquel
  2010-02-09  0:25     ` Michael Ekstrand
  2 siblings, 1 reply; 11+ messages in thread
From: Luca de Alfaro @ 2010-02-08 16:33 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 862 bytes --]

I am trying another approach... it might make more sense for me to embed the
Ocaml into C++.
I have read the instructions, and it seems feasible, except that I have a
few questions:

   - All I need to pass, as arguments, are int, float, string, and arrays of
   these.  Any example of how to deal with the arrays?
   - How can I return arrays, in a way that C or C++ understands?  How can I
   return tuples, i.e., how can I return multiple values from Ocaml to C?
   - Finally, do I need to worry about the Ocaml garbage collector, if I
   call Ocaml from C/C++?  Will it run every now and then? How can the garbage
   collector know whether a value returned by an Ocaml function is still being
   used in C/C++?  How can I tell it that it is no longer used?

The problem I am trying to solve seems to be a can of worms from whichever
angle I take it...

Luca

[-- Attachment #2: Type: text/html, Size: 921 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Caml-list] Re: How to wrap around C++?
  2010-02-08 16:33     ` Luca de Alfaro
@ 2010-02-08 17:44       ` Guillaume Yziquel
  2010-02-08 17:57         ` Luca de Alfaro
  2010-02-09  6:53         ` Basile STARYNKEVITCH
  0 siblings, 2 replies; 11+ messages in thread
From: Guillaume Yziquel @ 2010-02-08 17:44 UTC (permalink / raw)
  To: Luca de Alfaro; +Cc: caml-list

Luca de Alfaro a écrit :
> I am trying another approach... it might make more sense for me to embed the
> Ocaml into C++.

This is not the way you'll get the most help out of this list. People 
are more familiar with making C bindings. Making C++ bindings is rather 
close to it.

> I have read the instructions, and it seems feasible, except that I have a
> few questions:
> 
>    - All I need to pass, as arguments, are int, float, string, and arrays of
>    these.  Any example of how to deal with the arrays?

You need to construct them from C side, and it's more a pain than taking 
C structs and wrapping them into OCaml.

The manual describes the structure of OCaml values rather precisely. 
There are also some pages by Richard Jones on his blog which explain 
rather nicely the internals of OCaml values. One advice: stick to the 
macros provided. Do not try to construct manually, say, OCaml strings on 
the C side. Use caml_copy_string and friends.

>    - How can I return arrays, in a way that C or C++ understands?  How can I
>    return tuples, i.e., how can I return multiple values from Ocaml to C?

These are documented in the manual and in Richard Jones' blog.

For couples, you can do

> value couple = caml_alloc(2, 0);
> Store_field(couple, 0, my_ocaml_val);
> Store_field(couple, 1, my_other_ocml_val);

For arrays, you'll have seamless integration by using Bigarrays.

>    - Finally, do I need to worry about the Ocaml garbage collector, if I
>    call Ocaml from C/C++?  Will it run every now and then? How can the garbage
>    collector know whether a value returned by an Ocaml function is still being
>    used in C/C++?  How can I tell it that it is no longer used?

Essentially, the garbage collector will run potentially each time you 
allocate an OCaml value. caml_copy_string? the GC may run.

You have to register values being used on the C side as a GC root. It's 
easier and more documented to do it the other way round by calling C++ 
from OCaml.

> The problem I am trying to solve seems to be a can of worms from whichever
> angle I take it...

No.

The solution I proposed with Swig is very verbose, but it is a clean 
solution if you do it manually.

You have Makefile compilation instructions to compile C++ with OCaml 
(the main issue with C++ and the extern "C" is essentially the name 
mangling of symbols provided by your C++ object files. All the rest is 
pretty similar to C. This is really the *main* point).

You have at the end of my last email and example of how to construct an 
object and feed it back to OCaml. It may not be really clean, it lacks 
finalisers, but these last two points are stuff that you're going to 
have to deal with anyway if you're going with the OCaml/C interface. 
Look up "custom blocks" and finalisation in the OCaml manual section 
concerning the C interface.

> Luca

All the best,

-- 
      Guillaume Yziquel
http://yziquel.homelinux.org/


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Caml-list] Re: How to wrap around C++?
  2010-02-08 16:03   ` [Caml-list] " Luca de Alfaro
  2010-02-08 16:33     ` Luca de Alfaro
@ 2010-02-08 17:54     ` Guillaume Yziquel
  2010-02-09  0:25     ` Michael Ekstrand
  2 siblings, 0 replies; 11+ messages in thread
From: Guillaume Yziquel @ 2010-02-08 17:54 UTC (permalink / raw)
  To: Luca de Alfaro; +Cc: Michael Ekstrand, caml-list

Luca de Alfaro a écrit :
> Thank you very much!  I follow the general lines, but...
> 
>> * Wrap your OCaml includes in 'extern "C" { ... }"
> 
> Here, I am not sure what you mean.  You mean,
> 
> extern "C" {
> #include <caml/mlvalues.h>
> ...
> }
> 
> ?

See the code in my email:

>   /* Including OCaml system. */
>   #define CAML_VALUE value
>   extern "C" {
>     #include <caml/alloc.h>
>     #include <caml/custom.h>
>     #include <caml/mlvalues.h>
>     #include <caml/memory.h>
>     #include <caml/callback.h>
>     #include <caml/fail.h>
>     #include <caml/misc.h>
>   }

on one hand, and

> extern "C" CAML_VALUE _wrap_tokenizer_tokenize (CAML_VALUE ocaml_arg1, CAML_VALUE ocaml_arg2)
> {
>   CAMLparam0();
>   SWIG_CAMLlocal1(caml_result);
>   tokenizer *arg1 = (tokenizer *) 0 ;
>   std::string *arg2 = 0 ;
>   CAMLxparam1(ocaml_arg1);
>   CAMLxparam1(ocaml_arg2);
>   std::list< word > result;
>   
>   arg1 = *((tokenizer * *) Data_custom_val(ocaml_arg1)); 
>   {
>     std::string arg2_str(String_val(ocaml_arg2), caml_string_length(ocaml_arg2));
>     arg2 = &arg2_str;
>   }
>   result = (arg1)->tokenize((std::string const &)*arg2);
>   {
>     caml_result = caml_alloc_custom(&custom_swigtype_ocaml_operations, sizeof (void *), 0 ,1);
>     *((void **) Data_custom_val(caml_result)) = new std::list< word >((const std::list< word > &)result);
>   }
>   CAMLreturn(caml_result);
> }

on the other...

>> * Export all your stub functions with C linkage (extern "C")
> 
> Ok, evidently, I need to learn this extern "C" construct.

Yes. It's essentially here to cope with C++ name mangling.

>> * Compiling is tricky, since the OCaml compiler driver doesn't know what
>> to do with C++.  The Swig documentation[1] has a workaround for this,
>> useful even if you don't use Swig.
>
> Why would the Ocaml compiler driver need to know what to do with C++?

Because it knows how to compile C, but doesn't know how to compile C++.

> The C++ I need to link to is rather huge, and I will need to compile it with
> its own build setup.

Compile your C++ on one hand as you usually would. No issue there. You 
could even wrap a .so file generated from C++ code without knowing 
anything about the source code of the .so file. OK, except headers, and 
vendor info and version info of your C++ compiler.

But, you have to compile the C glue as above with extern "C" and the 
trick I gave you in the Makefile, which btw come from the Swig website.

> Once that is built, I need to compile the stubs, the Ocaml, and link the
> three together (Ocaml, stubs, and C++), in native mode, but  why would the
> Ocaml compiler need to deal with C++?

The OCaml compiler does not deal with C++. It only knows about C.

It's the C stub that need to:

-1- be linked in OCaml code, and therefore, no C++ name mangling 
exported from these C stubs, hence the export "C".

-2- be linked with C++ code. Hence the C++ code within the Extern "C" 
brackets.

> Another question: I could also try to do the vice-versa, and use Ocaml as
> libraries from C++.  Has anybody tried doing this?  Is it easy to do?

I would stick with embedding C++ code into OCaml than the reverse. It's 
likely that you'd get more answers this way.

> Luca

-- 
      Guillaume Yziquel
http://yziquel.homelinux.org/


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Caml-list] Re: How to wrap around C++?
  2010-02-08 17:44       ` Guillaume Yziquel
@ 2010-02-08 17:57         ` Luca de Alfaro
  2010-02-09  6:53         ` Basile STARYNKEVITCH
  1 sibling, 0 replies; 11+ messages in thread
From: Luca de Alfaro @ 2010-02-08 17:57 UTC (permalink / raw)
  To: guillaume.yziquel; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 3729 bytes --]

Thank you Guillaume.
The reason why it is complex for me to use C/C++ inside Ocaml is that it is
a huge, and hugely complex, body of C/C++ code, that comes with all sort of
nonstandard things, and with its own entire build process.  It is not clear
to me what happens if the main file is not some very special setup that
C/C++ is using.  I will look into it, but the difficulty is determined by
the conventions and build process of the C/C++ I have to deal with.

Luca

On Mon, Feb 8, 2010 at 9:44 AM, Guillaume Yziquel <
guillaume.yziquel@citycable.ch> wrote:

> Luca de Alfaro a écrit :
>
>> I am trying another approach... it might make more sense for me to embed
>> the
>> Ocaml into C++.
>>
>
> This is not the way you'll get the most help out of this list. People are
> more familiar with making C bindings. Making C++ bindings is rather close to
> it.
>
>
>  I have read the instructions, and it seems feasible, except that I have a
>> few questions:
>>
>>   - All I need to pass, as arguments, are int, float, string, and arrays
>> of
>>   these.  Any example of how to deal with the arrays?
>>
>
> You need to construct them from C side, and it's more a pain than taking C
> structs and wrapping them into OCaml.
>
> The manual describes the structure of OCaml values rather precisely. There
> are also some pages by Richard Jones on his blog which explain rather nicely
> the internals of OCaml values. One advice: stick to the macros provided. Do
> not try to construct manually, say, OCaml strings on the C side. Use
> caml_copy_string and friends.
>
>    - How can I return arrays, in a way that C or C++ understands?  How can
>> I
>>
>>   return tuples, i.e., how can I return multiple values from Ocaml to C?
>>
>
> These are documented in the manual and in Richard Jones' blog.
>
> For couples, you can do
>
>  value couple = caml_alloc(2, 0);
>> Store_field(couple, 0, my_ocaml_val);
>> Store_field(couple, 1, my_other_ocml_val);
>>
>
> For arrays, you'll have seamless integration by using Bigarrays.
>
>    - Finally, do I need to worry about the Ocaml garbage collector, if I
>>
>>   call Ocaml from C/C++?  Will it run every now and then? How can the
>> garbage
>>   collector know whether a value returned by an Ocaml function is still
>> being
>>   used in C/C++?  How can I tell it that it is no longer used?
>>
>
> Essentially, the garbage collector will run potentially each time you
> allocate an OCaml value. caml_copy_string? the GC may run.
>
> You have to register values being used on the C side as a GC root. It's
> easier and more documented to do it the other way round by calling C++ from
> OCaml.
>
>
>  The problem I am trying to solve seems to be a can of worms from whichever
>> angle I take it...
>>
>
> No.
>
> The solution I proposed with Swig is very verbose, but it is a clean
> solution if you do it manually.
>
> You have Makefile compilation instructions to compile C++ with OCaml (the
> main issue with C++ and the extern "C" is essentially the name mangling of
> symbols provided by your C++ object files. All the rest is pretty similar to
> C. This is really the *main* point).
>
> You have at the end of my last email and example of how to construct an
> object and feed it back to OCaml. It may not be really clean, it lacks
> finalisers, but these last two points are stuff that you're going to have to
> deal with anyway if you're going with the OCaml/C interface. Look up "custom
> blocks" and finalisation in the OCaml manual section concerning the C
> interface.
>
>  Luca
>>
>
> All the best,
>
>
> --
>     Guillaume Yziquel
> http://yziquel.homelinux.org/
>
>

[-- Attachment #2: Type: text/html, Size: 5107 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: How to wrap around C++?
  2010-02-08 16:03   ` [Caml-list] " Luca de Alfaro
  2010-02-08 16:33     ` Luca de Alfaro
  2010-02-08 17:54     ` Guillaume Yziquel
@ 2010-02-09  0:25     ` Michael Ekstrand
  2 siblings, 0 replies; 11+ messages in thread
From: Michael Ekstrand @ 2010-02-09  0:25 UTC (permalink / raw)
  To: caml-list

On 02/08/2010 10:03 AM, Luca de Alfaro wrote:
> Thank you very much!  I follow the general lines, but...
> 
>     * Make sure no C++ exceptions leak to OCaml.
> 
> This will be next to impossible: the C++ code I need to wrap is huge,
> and I have no idea of what possible exceptions can be generated.  I will
> have to try to see if there is a generic exception catcher. 

There is.

try {
   some code
} catch (...) {
   caml_failwith("foo: exception thrown");
}

with appropriate considerations for freeing memory, etc.

>     * Wrap your OCaml includes in 'extern "C" { ... }"
> 
> 
> Here, I am not sure what you mean.  You mean, 
> 
> extern "C" {
> #include <caml/mlvalues.h>
> ...
> }
> 

Exactly.

>     * Export all your stub functions with C linkage (extern "C")
> 
> Ok, evidently, I need to learn this extern "C" construct.

Yes, if you're interfacing between C and C++, you do need to know it.
In this context, it is applied as a modifier to the function definition
(like static).  The big thing it does is turn off the name mangling used
by the C++ compiler to implement overloading, type safety, etc.

>     * Compiling is tricky, since the OCaml compiler driver doesn't know what
>     to do with C++.  The Swig documentation[1] has a workaround for this,
>     useful even if you don't use Swig.
> 
> 
> Why would the Ocaml compiler driver need to know what to do with C++? 
> The C++ I need to link to is rather huge, and I will need to compile it
> with its own build setup. 
> Once that is built, I need to compile the stubs, the Ocaml, and link the
> three together (Ocaml, stubs, and C++), in native mode, but  why would
> the Ocaml compiler need to deal with C++?

You will have 3 pieces: the C++ library, the OCaml interface, and the
stubs gluing them together.  Stubs must be C-compatible, so they can be
called from OCaml.  But they also need to be able to call into C++,
hence they must be written in C++.  Therefore, your stub code must be
written in C++, exporting a C-compatible interface (via extern "C").
Generally, you use the OCaml compiler driver to compile stubs rather
than gcc directly, but OCaml doesn't know how to call g++.

- Michael



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Caml-list] Re: How to wrap around C++?
  2010-02-08 17:44       ` Guillaume Yziquel
  2010-02-08 17:57         ` Luca de Alfaro
@ 2010-02-09  6:53         ` Basile STARYNKEVITCH
  1 sibling, 0 replies; 11+ messages in thread
From: Basile STARYNKEVITCH @ 2010-02-09  6:53 UTC (permalink / raw)
  To: guillaume.yziquel; +Cc: Luca de Alfaro, caml-list

Guillaume Yziquel wrote:
> Essentially, the garbage collector will run potentially each time you 
> allocate an OCaml value. caml_copy_string? the GC may run.

The garbage collector may also run when calling (from C or C++ code) a callback, that is a function like caml_callback 
... (see section 18.7 of the manual), since this apply an Ocaml closure which of course will allocate Ocaml values.

In practical terms, you should consider that the Ocaml GC can be invoked by any C function from the Ocaml runtime (as 
seen by your C or C++ code) and that it moves pointers at every invocation.

So you better be safe and play carefully Ocaml rules.

Unless you really understand all the details of Ocaml runtime, I strongly recommend against playing tricks with Ocaml, 
for instance trying to avoid CAMLlocalX or CAMLparamX or CAMLreturn macros.

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} ***


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-02-09  6:53 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-08  2:13 How to wrap around C++? Luca de Alfaro
2010-02-08  4:06 ` Michael Ekstrand
2010-02-08  4:17   ` Michael Ekstrand
2010-02-08 16:03   ` [Caml-list] " Luca de Alfaro
2010-02-08 16:33     ` Luca de Alfaro
2010-02-08 17:44       ` Guillaume Yziquel
2010-02-08 17:57         ` Luca de Alfaro
2010-02-09  6:53         ` Basile STARYNKEVITCH
2010-02-08 17:54     ` Guillaume Yziquel
2010-02-09  0:25     ` Michael Ekstrand
2010-02-08 12:38 ` [Caml-list] " Guillaume Yziquel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).