* Wrapping OCaml function returning a variant
@ 2007-03-28 11:33 Joel Reymont
2007-03-28 11:47 ` [Caml-list] " Richard Jones
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 11:33 UTC (permalink / raw)
To: Caml List
Is there an example of returning a variant from OCaml into C somewhere?
It's a regular variant, declared like this
type morpher_output =
| Success of string
| Error of string * int * int * int
The other issue is that I don't know how to deal with strings
allocated in OCaml. Will they be collected automatically?
The strings _must_ be allocated in OCaml but I can guarantee that
they will not be modified in the C code. Any suggestions on how to
deal with this?
Thanks, Joel
--
http://wagerlabs.com/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 11:33 Wrapping OCaml function returning a variant Joel Reymont
@ 2007-03-28 11:47 ` Richard Jones
2007-03-28 12:25 ` micha
2007-03-28 12:55 ` Serge Aleynikov
2 siblings, 0 replies; 16+ messages in thread
From: Richard Jones @ 2007-03-28 11:47 UTC (permalink / raw)
To: Joel Reymont; +Cc: Caml List
On Wed, Mar 28, 2007 at 12:33:46PM +0100, Joel Reymont wrote:
> The other issue is that I don't know how to deal with strings
> allocated in OCaml. Will they be collected automatically?
>
> The strings _must_ be allocated in OCaml but I can guarantee that
> they will not be modified in the C code. Any suggestions on how to
> deal with this?
String_val (ocaml_str) will give you a pointer to the bytes in the
string. It's even ASCIIZ (ie. ASCII NUL-terminated) so you can
directly use C str* functions on it.
There are two catches: The small one is that OCaml strings may contain
NUL characters internally, which is obviously not allowed in C
strings, so you have to either guarantee on the OCaml side that this
won't be the case, or else go through hoops on the C side.
The bigger catch is that the garbage collector can and will move the
string around whenever it likes. So if you save the pointer from
String_val, go back into OCaml code and back into C, and try to reuse
the saved pointer, it won't necessarily point to the string any more.
The string might even have been freed by the GC. If you want to do
that, either rewrite your code so it doesn't save the pointer like
this, strdup the string to make a private copy in C, or register a
global root.
Rich.
--
Richard Jones
Red Hat
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 12:55 ` Serge Aleynikov
@ 2007-03-28 12:01 ` Joel Reymont
2007-03-28 13:40 ` Serge Aleynikov
2007-03-28 12:13 ` Joel Reymont
1 sibling, 1 reply; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 12:01 UTC (permalink / raw)
To: Serge Aleynikov; +Cc: Caml List
On Mar 28, 2007, at 1:55 PM, Serge Aleynikov wrote:
> You can read the section 18.3.4 of http://caml.inria.fr/pub/docs/
> manual-ocaml/manual032.html
It does not clearly explain how to handle variant types in C code.
Maybe I'm dumb but I did not understand it.
> Then if still unclear, examine: http://oracaml.sourceforge.net/
> or any other C-interface library available on Caml Hump: http://
> caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=65
It looks like you are using polymorphic variants in new syntax. Maybe
I'm wrong but it doesn't work for me
# type foo = [Null | Int of int];;
Syntax error
I still don't understand how I can handle regular variants of the
following type returned by OCaml to the C side
> type morpher_output =
> | Success of string
> | Error of string * int * int * int
Thanks, Joel
--
http://wagerlabs.com/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 12:55 ` Serge Aleynikov
2007-03-28 12:01 ` Joel Reymont
@ 2007-03-28 12:13 ` Joel Reymont
2007-03-28 13:53 ` Serge Aleynikov
1 sibling, 1 reply; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 12:13 UTC (permalink / raw)
To: Serge Aleynikov; +Cc: Caml List
On Mar 28, 2007, at 1:55 PM, Serge Aleynikov wrote:
> If you are using caml_copy_string() or caml_alloc_string() they
> allocate strings on OCaml's heap, and will be automatically garbage
> collected.
How do I pass a C string into OCaml if the assumption is that it will
not be modified? Do I still need to copy it with caml_copy_string?
I don't think I need to allocate strings on the OCaml heap from C as
the string given to OCaml will be allocated on the C heap and the
string returned from OCaml will be garbage-collected automatically.
Thanks, Joel
--
http://wagerlabs.com/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 11:33 Wrapping OCaml function returning a variant Joel Reymont
2007-03-28 11:47 ` [Caml-list] " Richard Jones
@ 2007-03-28 12:25 ` micha
2007-03-28 12:51 ` Joel Reymont
2007-03-28 12:55 ` Serge Aleynikov
2 siblings, 1 reply; 16+ messages in thread
From: micha @ 2007-03-28 12:25 UTC (permalink / raw)
To: caml-list
Am Wed, 28 Mar 2007 12:33:46 +0100
schrieb Joel Reymont <joelr1@gmail.com>:
> Is there an example of returning a variant from OCaml into C
> somewhere?
>
> It's a regular variant, declared like this
>
> type morpher_output =
> | Success of string
> | Error of string * int * int * int
>
the labels are numbered starting from zero, so in c have have to
decode two possible values :
let a= Success("xxx") ...
is in C a block with tag 0 and size 1, to get the string write:
char* s = String_val(Field(a,0))
for the case
let b = Error("e",1,2,3) ...
you have a block with tag 1 and size 4:
to get the values you write:
char* err=String_val(Field(b,0));
int n1= Int_val(Field(b,1));
...
int n3= Int_val(Field(b,3));
hope that helps...
Michael
ps: polymorphic variants are handled different...
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 12:25 ` micha
@ 2007-03-28 12:51 ` Joel Reymont
2007-03-28 13:28 ` Richard Jones
2007-03-28 14:34 ` micha
0 siblings, 2 replies; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 12:51 UTC (permalink / raw)
To: micha; +Cc: caml-list
One last question which I couldn't answer by browsing through
mltypes.h...
What is the type of a on the C side?
Thanks, Joel
On Mar 28, 2007, at 1:25 PM, micha wrote:
> the labels are numbered starting from zero, so in c have have to
> decode two possible values :
>
> let a= Success("xxx") ...
>
> is in C a block with tag 0 and size 1, to get the string write:
>
> char* s = String_val(Field(a,0))
--
http://wagerlabs.com/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 11:33 Wrapping OCaml function returning a variant Joel Reymont
2007-03-28 11:47 ` [Caml-list] " Richard Jones
2007-03-28 12:25 ` micha
@ 2007-03-28 12:55 ` Serge Aleynikov
2007-03-28 12:01 ` Joel Reymont
2007-03-28 12:13 ` Joel Reymont
2 siblings, 2 replies; 16+ messages in thread
From: Serge Aleynikov @ 2007-03-28 12:55 UTC (permalink / raw)
To: Joel Reymont; +Cc: Caml List
Joel Reymont wrote:
> Is there an example of returning a variant from OCaml into C somewhere?
> It's a regular variant, declared like this
>
> type morpher_output =
> | Success of string
> | Error of string * int * int * int
You can read the section 18.3.4 of
http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html
Then if still unclear, examine: http://oracaml.sourceforge.net/
or any other C-interface library available on Caml Hump:
http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=65
> The other issue is that I don't know how to deal with strings allocated
> in OCaml. Will they be collected automatically?
If you are using caml_copy_string() or caml_alloc_string() they allocate
strings on OCaml's heap, and will be automatically garbage collected.
> The strings _must_ be allocated in OCaml but I can guarantee that they
> will not be modified in the C code. Any suggestions on how to deal with
> this?
Unless I am not understanding your question, the above two functions are
the way to allocate strings on OCaml's heap.
Serge
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 12:51 ` Joel Reymont
@ 2007-03-28 13:28 ` Richard Jones
2007-03-28 14:34 ` micha
1 sibling, 0 replies; 16+ messages in thread
From: Richard Jones @ 2007-03-28 13:28 UTC (permalink / raw)
To: Joel Reymont; +Cc: caml-list
On Wed, Mar 28, 2007 at 01:51:39PM +0100, Joel Reymont wrote:
> One last question which I couldn't answer by browsing through
> mltypes.h...
>
> What is the type of a on the C side?
'value'.
Rich.
--
Richard Jones
Red Hat
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 12:01 ` Joel Reymont
@ 2007-03-28 13:40 ` Serge Aleynikov
0 siblings, 0 replies; 16+ messages in thread
From: Serge Aleynikov @ 2007-03-28 13:40 UTC (permalink / raw)
To: Joel Reymont; +Cc: Caml List
Joel Reymont wrote:
>
> On Mar 28, 2007, at 1:55 PM, Serge Aleynikov wrote:
>
>> You can read the section 18.3.4 of
>> http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html
>
> It does not clearly explain how to handle variant types in C code. Maybe
> I'm dumb but I did not understand it.
>
>> Then if still unclear, examine: http://oracaml.sourceforge.net/
>> or any other C-interface library available on Caml Hump:
>> http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=65
>
> It looks like you are using polymorphic variants in new syntax. Maybe
> I'm wrong but it doesn't work for me
>
> # type foo = [Null | Int of int];;
> Syntax error
That's because this code is written using revised
(http://caml.inria.fr/pub/docs/tutorial-camlp4/tutorial005.html) syntax.
These are not polymorphic variants but rather a basic union type with
non-constant constructors.
Hint: you can start the ocaml toplevel like this to get it understand
revised syntax: "ocaml camlp4r.cma".
> I still don't understand how I can handle regular variants of the
> following type returned by OCaml to the C side
In terms of your example above, on the C side you would do:
void bar(value foo) {
if (Is_long(foo)) {
switch (Long_val(foo)) {
case 0: /* Null */
...
break;
/* if there are other constant constructors besides Null
add additional cases here */
default:
fail_exception(Long_val(foo), "Unknown constant constructor!");
}
} else {
switch (Tag_val(foo)) {
case 0: /* Int of int */
/* Access the non-constant value by Long_val(Field(foo,0))) */
break;
...
}
}
}
Regards,
Serge
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 12:13 ` Joel Reymont
@ 2007-03-28 13:53 ` Serge Aleynikov
0 siblings, 0 replies; 16+ messages in thread
From: Serge Aleynikov @ 2007-03-28 13:53 UTC (permalink / raw)
To: Joel Reymont; +Cc: Caml List
Joel Reymont wrote:
>
> On Mar 28, 2007, at 1:55 PM, Serge Aleynikov wrote:
>
>> If you are using caml_copy_string() or caml_alloc_string() they
>> allocate strings on OCaml's heap, and will be automatically garbage
>> collected.
>
> How do I pass a C string into OCaml if the assumption is that it will
> not be modified? Do I still need to copy it with caml_copy_string?
If you need to be able to access your C string value from OCaml,
caml_copy_string is what you need. OTOH, if you want the string to be
passed to OCaml as an opaque type (in which case OCaml won't be able to
access its value directly, though the value will live on the C heap and
can only be accessible from C) you can pass the string pointer using a
Custom block (see section 18.9.2
http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html).
Regards,
Serge
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 12:51 ` Joel Reymont
2007-03-28 13:28 ` Richard Jones
@ 2007-03-28 14:34 ` micha
2007-03-28 14:46 ` Joel Reymont
1 sibling, 1 reply; 16+ messages in thread
From: micha @ 2007-03-28 14:34 UTC (permalink / raw)
To: caml-list
Am Wed, 28 Mar 2007 13:51:39 +0100
schrieb Joel Reymont <joelr1@gmail.com>:
> One last question which I couldn't answer by browsing through
> mltypes.h...
>
> What is the type of a on the C side?
that may look like:
CAMLprim value cfunc(value x)
{
CAMLparam1(x);
switch (Tag_val(x)) {
case 0: do something with first variant;
case 1: do something with second variant
default: argh;
}
CAMLreturn(Val_unit);
}
Michael
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 14:34 ` micha
@ 2007-03-28 14:46 ` Joel Reymont
2007-03-28 14:56 ` micha
2007-03-28 14:57 ` Xavier Leroy
0 siblings, 2 replies; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 14:46 UTC (permalink / raw)
To: micha; +Cc: caml-list
I came up with this. Is it sound?
char *morph(char *code, char** error, int *line, int *start, int *end)
{
static value *closure = NULL;
value v;
char *res;
if (closure == NULL)
closure = caml_named_value("morph");
v = callback(*closure, caml_copy_string(code));
switch (Long_val(v)) {
case 0: /* success */
res = String_val(Field(v, 0));
*error = NULL;
case 1: /* error */
res = NULL;
*error = String_val(Field(v, 0));
*line = Int_val(Field(v, 1));
*start = Int_val(Field(v, 2));
*end = Int_val(Field(v, 3));
}
return res;
}
Thanks, Joel
On Mar 28, 2007, at 3:34 PM, micha wrote:
> that may look like:
>
> CAMLprim value cfunc(value x)
> {
> CAMLparam1(x);
> switch (Tag_val(x)) {
> case 0: do something with first variant;
> case 1: do something with second variant
> default: argh;
> }
> CAMLreturn(Val_unit);
> }
--
http://wagerlabs.com/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 14:46 ` Joel Reymont
@ 2007-03-28 14:56 ` micha
2007-03-28 14:57 ` Xavier Leroy
1 sibling, 0 replies; 16+ messages in thread
From: micha @ 2007-03-28 14:56 UTC (permalink / raw)
To: Joel Reymont; +Cc: caml-list
Am Wed, 28 Mar 2007 15:46:54 +0100
schrieb Joel Reymont <joelr1@gmail.com>:
> I came up with this. Is it sound?
>
>
> switch (Long_val(v)) {
I think you must use Tag_val(x) since your datatype is a constructed
type with parameters (it is a block not an integer as for :
type x = One | Two, here you would have integers )
> case 0: /* success */
> res = String_val(Field(v, 0));
maybe it's better to strcpy() the string if you want to be independent
of the ocaml side
cheers
Michael
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 14:46 ` Joel Reymont
2007-03-28 14:56 ` micha
@ 2007-03-28 14:57 ` Xavier Leroy
2007-03-28 15:07 ` Joel Reymont
1 sibling, 1 reply; 16+ messages in thread
From: Xavier Leroy @ 2007-03-28 14:57 UTC (permalink / raw)
To: Joel Reymont; +Cc: micha, caml-list
> I came up with this. Is it sound?
Not quite.
> char *morph(char *code, char** error, int *line, int *start, int *end)
> {
> static value *closure = NULL;
> value v;
> char *res;
>
> if (closure == NULL)
> closure = caml_named_value("morph");
>
> v = callback(*closure, caml_copy_string(code));
Here, caml_copy_string could trigger a GC and move the closure pointed
to by closure, so the value of *closure could become invalid.
You need to order the computations explicitly:
value vcode;
if (closure == NULL)
closure = caml_named_value("morph");
vcode = caml_copy_string(code);
v = callback(*closure, vcode);
> switch (Long_val(v)) {
v is not a constant constructor, but a constructor with arguments.
So, its representation is not an integer, but a pointer to a block.
You want to discriminate on the tag of this block.
switch (Tag_val(v)) {
> case 0: /* success */
> res = String_val(Field(v, 0));
> *error = NULL;
> case 1: /* error */
> res = NULL;
> *error = String_val(Field(v, 0));
> *line = Int_val(Field(v, 1));
> *start = Int_val(Field(v, 2));
> *end = Int_val(Field(v, 3));
> }
The next GC can move the strings obtained by String_val, making
invalid the pointer you return or store in *error. Take a copy immediately:
switch (Tag_val(v)) {
case 0: /* success */
res = strdup(String_val(Field(v, 0)));
*error = NULL;
case 1: /* error */
res = NULL;
*error = strdup(String_val(Field(v, 0)));
*line = Int_val(Field(v, 1));
*start = Int_val(Field(v, 2));
*end = Int_val(Field(v, 3));
}
Hope this helps,
- Xavier Leroy
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 14:57 ` Xavier Leroy
@ 2007-03-28 15:07 ` Joel Reymont
2007-03-28 22:47 ` Joel Reymont
0 siblings, 1 reply; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 15:07 UTC (permalink / raw)
To: Xavier Leroy; +Cc: micha, caml-list
Big thanks to everyone for this awesome hand-holding with the
FFI :-). I'm learning, albeit slowly. I have one remaining block on
my road to success, apologies for reposting.
I get undefined symbols when trying to produce an executable using
the OCaml library with the C wrapper.
gcc foo.c -L_build -lmorpher -o foo
/usr/bin/ld: Undefined symbols:
_caml_atom_table
_caml_code_area_end
_caml_code_area_start
_caml_static_data_end
_caml_static_data_start
collect2: ld returned 1 exit status
nm _build/libmorpher.a |grep caml_atom_table
00000400 C _caml_atom_table
U _caml_atom_table
What am I doing wrong?
Thanks, Joel
--
http://wagerlabs.com/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Wrapping OCaml function returning a variant
2007-03-28 15:07 ` Joel Reymont
@ 2007-03-28 22:47 ` Joel Reymont
0 siblings, 0 replies; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 22:47 UTC (permalink / raw)
To: Joel Reymont; +Cc: Xavier Leroy, micha, caml-list
I wasn't calling caml_startup in my code.
The errors went away once I did.
Foot in mouth!
On Mar 28, 2007, at 4:07 PM, Joel Reymont wrote:
> Big thanks to everyone for this awesome hand-holding with the
> FFI :-). I'm learning, albeit slowly. I have one remaining block on
> my road to success, apologies for reposting.
>
> I get undefined symbols when trying to produce an executable using
> the OCaml library with the C wrapper.
>
> gcc foo.c -L_build -lmorpher -o foo
> /usr/bin/ld: Undefined symbols:
> _caml_atom_table
> _caml_code_area_end
> _caml_code_area_start
> _caml_static_data_end
> _caml_static_data_start
> collect2: ld returned 1 exit status
--
http://wagerlabs.com/
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2007-03-28 22:47 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-28 11:33 Wrapping OCaml function returning a variant Joel Reymont
2007-03-28 11:47 ` [Caml-list] " Richard Jones
2007-03-28 12:25 ` micha
2007-03-28 12:51 ` Joel Reymont
2007-03-28 13:28 ` Richard Jones
2007-03-28 14:34 ` micha
2007-03-28 14:46 ` Joel Reymont
2007-03-28 14:56 ` micha
2007-03-28 14:57 ` Xavier Leroy
2007-03-28 15:07 ` Joel Reymont
2007-03-28 22:47 ` Joel Reymont
2007-03-28 12:55 ` Serge Aleynikov
2007-03-28 12:01 ` Joel Reymont
2007-03-28 13:40 ` Serge Aleynikov
2007-03-28 12:13 ` Joel Reymont
2007-03-28 13:53 ` Serge Aleynikov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox