From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 5502F7F890 for ; Wed, 26 Mar 2014 17:24:52 +0100 (CET) Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of travis.brady@gmail.com) identity=pra; client-ip=209.85.216.52; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="travis.brady@gmail.com"; x-sender="travis.brady@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of travis.brady@gmail.com designates 209.85.216.52 as permitted sender) identity=mailfrom; client-ip=209.85.216.52; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="travis.brady@gmail.com"; x-sender="travis.brady@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-qa0-f52.google.com) identity=helo; client-ip=209.85.216.52; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="travis.brady@gmail.com"; x-sender="postmaster@mail-qa0-f52.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Ap8CAOL+MlPRVdg0lWdsb2JhbABEFYNBSwyDC6kCMo1CiHSBFQgWDgEBAQEHDQkJEiqCJQEBAQMBIwQZARsSBgUBAwELBgMCCw0NHQICIQEBEQEFAQoSBhMICgmHSQEDCQgNkWmQCYs1WVGDDpZVChknAwpkhl4RAQUMjEkcgXwEB4JvgUkEiVKNDoFtgTOLNoNbGCmEeh8 X-IPAS-Result: Ap8CAOL+MlPRVdg0lWdsb2JhbABEFYNBSwyDC6kCMo1CiHSBFQgWDgEBAQEHDQkJEiqCJQEBAQMBIwQZARsSBgUBAwELBgMCCw0NHQICIQEBEQEFAQoSBhMICgmHSQEDCQgNkWmQCYs1WVGDDpZVChknAwpkhl4RAQUMjEkcgXwEB4JvgUkEiVKNDoFtgTOLNoNbGCmEeh8 X-IronPort-AV: E=Sophos;i="4.97,736,1389740400"; d="scan'208";a="64870779" Received: from mail-qa0-f52.google.com ([209.85.216.52]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 26 Mar 2014 17:24:51 +0100 Received: by mail-qa0-f52.google.com with SMTP id m5so2460471qaj.39 for ; Wed, 26 Mar 2014 09:24:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=6NkmJ6gwFjysDt4fjrRpteHPsYxtohmY+dcdD6zbr+U=; b=qoH/SOx6AfljYyEJP8QoRuJEk8njLLmXEZyyiDvyeYGogLXeKftOY3ZNgRimAKPhle dtBFoqn1IyRVNlyVNH2mejMBTXAadZ1wqEM9fa1p2Iwi9VGkQ4Vu113gagABlvijKjc1 iJE8hL4O7yfTsqfSTQX1Gt/BBjawqnoab6H2cfyG989zU5/RC2xNr1zJ/kxIjOlRumIF pIF4hDlryg3eGQrbZhq2cT0nb60rFdl8KSWaDQ3OMxH3Pi5iWBIII/+Iiibd4PMrkV3x 8JKdz4bVOASX8f574w18B0PhFXNhJ/soHawhhK3NJTjyUxoSud4YF50kfKLp4n6oEW8F E0pg== MIME-Version: 1.0 X-Received: by 10.140.24.151 with SMTP id 23mr87594644qgr.11.1395851090040; Wed, 26 Mar 2014 09:24:50 -0700 (PDT) Received: by 10.96.173.129 with HTTP; Wed, 26 Mar 2014 09:24:49 -0700 (PDT) In-Reply-To: References: Date: Wed, 26 Mar 2014 11:24:49 -0500 Message-ID: From: Travis Brady To: Jeremy Yallop Cc: =?ISO-8859-2?Q?Milan_Stanojevi=E6?= , Dan Benjamin , David Sheets , Bruno Deferrari , O Caml Content-Type: multipart/alternative; boundary=001a11c12804619c4104f584e8b2 Subject: Re: [Caml-list] Static linking via Ctypes? --001a11c12804619c4104f584e8b2 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable This thread is timely for me because I'm attempting to get my ctypes-based liblinear[1] bindings to behave (with oasis) but thus far have come up short. I've followed the instructions in [2] and tried to crib from onanomsg and ocaml-picosat, but am only able to support either the toplevel OR linking in binaries. But not both. So currently I can make binaries, but I'd love to be able to #require this in utop for interactive ipython-like usage. Is there a canonical solution to this problem for oasis users? I'm considering trying what jane st did with re2 and bundling liblinear up with my bindings and cribbing from their build process, but ideally this would all just work with oasis. thank you Travis [1] https://github.com/travisbrady/oliblinear [2] https://github.com/ocamllabs/ocaml-ctypes/issues/51#issuecomment-30729675 On Tue, Mar 25, 2014 at 6:14 PM, Jeremy Yallop wrote: > I wrote: > > Not exactly, since the stub generation support in the next ctypes > > release resolves these issues in a different way. In the current > > release (0.2.3) setting up foreign calls and linking are both entirely > > dynamic. Stub generation will make it possible to link statically as > > well. > > Milan Stanojevi=C4=87 asked: > > Can you tell us how would this work exactly? > > Let's say I have a function "foo" in my C file (that I want to link > > statically) and I want to give use it in ocaml with a ctype (void @-> > > returning int) > > What would I need to say in my ocaml program and do I have to tell > > anything to my build system? > > With the current release of ctypes we'd bind 'foo' like this: > > let f =3D foreign "foo" (void @-> returning int) > > The 'foreign' function searches for the symbol "foo" and sets up the > call; the return value is an OCaml function that we can call > immediately. > > val f : unit -> int > > With stub generation as implemented in the git master branch the call > to 'foreign' changes slightly. Instead of calling 'foreign' just > once, we're going to call it once for each stage of generation. The > way we do this is to abstract over 'foreign' with a functor. (Note > the similarity to the original binding of 'f' above.) > > module Bindings (F : Cstubs.FOREIGN) =3D > struct > let f =3D F.foreign "foo" (void @-> returning int) > end > > The first application of the functor generates C: > > Cstubs.write_c std_formatter ~prefix:"foo_" (module Bindings) > > The output is a wrapper for the C function 'foo' that marshals and > unmarshals arguments and return values as needed. > > The second application generates OCaml: > > Cstubs.write_ml std_formatter ~prefix:"foo_" (module Bindings) > > The output is an OCaml module that we can pass to 'Bindings' for the > third and final application, which links together the declaration of > 'f' and the generated code: > > Bindings(Generated_ML) > > As with the dynamic binding, this gives us an OCaml function that we > can call without further ado: > > val f : unit -> int > > The build process is reasonably straightforward. Since we're > generating code, there are more steps than with the dynamic version, > but we're less likely to need obscure linker flags. A typical > approach is to place the bindings functor in one file -- > foo_binding.ml, say: > > module Bindings(F : Cstubs.FOREIGN) =3D > struct > let foo =3D F.foreign "foo" Ctypes.(void @-> returning int) > end > > and the calls to 'write_c' and 'write_ml' other files. I'll put the > call to 'write_c' along with code to print out the headers used in > generate_c.ml: > > let () =3D > print_endline "#include "; > print_endline "#include \"foo.h\""; > Cstubs.write_c Format.std_formatter ~prefix:"foo_" > (module Foo_binding.Bindings) > > The call to 'write_ml' goes in generate_ml.ml: > > let () =3D Cstubs.write_ml Format.std_formatter ~prefix:"foo_" > (module Foo_binding.Bindings) > > Then we can compile and run the two programs to generate the stub code: > > $ ocamlfind ocamlc -c -package ctypes.stubs \ > foo_binding.ml generate_c.ml generate_ml.ml > $ ocamlfind ocamlc -o generate_ml.native -linkpkg -package ctypes.stubs= \ > foo_binding.cmo generate_ml.cmo > $ ./generate_ml.native > generated.ml > $ ocamlfind ocamlc -o generate_c.native -linkpkg -package ctypes.stubs \ > foo_binding.cmo generate_c.cmo > $ ./generate_c.native > generated_c_stubs.c > > We can then compile the stub code and link it in with the bindings > functor and the library containing 'foo': > > $ ocamlfind ocamlc -c -package ctypes.stubs -I `ocamlc -where`/.. \ > generated_c_stubs.c generated.ml > $ ocamlfind ocamlmklib -o foo -linkpkg -package ctypes.stubs \ > generated_c_stubs.o generated.cmo foo_binding.cmo -L. -lfoo > > Finally, we can load the code and call the 'foo' function: > > $ ocaml -short-paths > OCaml version 4.01.0 > > # #use "topfind";; > [...] > # #require "ctypes.stubs";; > [...] > # #load "foo.cma";; > # include Foo_binding.Bindings(Generated);; > val foo : unit -> int =3D > # foo ();; > foo called > - : int =3D 3 > > The full stub generation interface (which is actually just the > 'write_ml' and 'write_c' functions) is here: > > > https://github.com/ocamllabs/ocaml-ctypes/blob/1e1634/src/cstubs/cstubs.m= li > > Jeremy > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > --001a11c12804619c4104f584e8b2 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
This thread is timely for me because I'm attempting to= get my ctypes-based liblinear[1] bindings to behave (with oasis) but thus = far have come up short.
I've followed the instructions in [2] and t= ried to crib from onanomsg and ocaml-picosat, but am only able to support e= ither the toplevel OR linking in binaries. =C2=A0But not both.
So currently I can make binaries, but I'd love to be able to #requ= ire this in utop for interactive ipython-like usage.

Is there a canonical solution to this problem for oasis users?
I'm considering trying what jane st did with re2 and bundling libl= inear up with my bindings and cribbing from their build process, but ideall= y this would all just work with oasis.

thank you
Travis

<= br>
On Tue, Mar 25, 2014 at 6:14 PM, Jeremy Y= allop <yallop@gmail.com> wrote:
I wrote:
> Not exactly, since the stub generation support in the next ctypes
> release resolves these issues in a different way. =C2=A0In the current=
> release (0.2.3) setting up foreign calls and linking are both entirely=
> dynamic. =C2=A0Stub generation will make it possible to link staticall= y as
> well.

Milan Stanojevi=C4=87 asked:
> Can you tell us how would this work exactly?
> Let's say I have a function "foo" in my C file (that I w= ant to link
> statically) and I want to give use it in ocaml with a ctype (void @-&g= t;
> returning int)
> What would I need to say in my ocaml program and do I have to tell
> anything to my build system?

With the current release of ctypes we'd bind 'foo' like t= his:

=C2=A0 =C2=A0let f =3D foreign "foo" (void @-> returning int)<= br>
The 'foreign' function searches for the symbol "foo" and = sets up the
call; the return value is an OCaml function that we can call
immediately.

=C2=A0 =C2=A0val f : unit -> int

With stub generation as implemented in the git master branch the call
to 'foreign' changes slightly. =C2=A0Instead of calling 'foreig= n' just
once, we're going to call it once for each stage of generation. =C2=A0T= he
way we do this is to abstract over 'foreign' with a functor. =C2=A0= (Note
the similarity to the original binding of 'f' above.)

=C2=A0 module Bindings (F : Cstubs.FOREIGN) =3D
=C2=A0 struct
=C2=A0 =C2=A0 =C2=A0let f =3D F.foreign "foo" (void @-> return= ing int)
=C2=A0 end

The first application of the functor generates C:

=C2=A0 Cstubs.write_c std_formatter ~prefix:"foo_" (module Bindin= gs)

The output is a wrapper for the C function 'foo' that marshals and<= br> unmarshals arguments and return values as needed.

The second application generates OCaml:

=C2=A0 Cstubs.write_ml std_formatter ~prefix:"foo_" (module Bindi= ngs)

The output is an OCaml module that we can pass to 'Bindings' for th= e
third and final application, which links together the declaration of
'f' and the generated code:

=C2=A0 Bindings(Generated_ML)

As with the dynamic binding, this gives us an OCaml function that we
can call without further ado:

=C2=A0 val f : unit -> int

The build process is reasonably straightforward. =C2=A0Since we're
generating code, there are more steps than with the dynamic version,
but we're less likely to need obscure linker flags. =C2=A0A typical
approach is to place the bindings functor in one file --
foo_binding.ml, say= :

=C2=A0 =C2=A0module Bindings(F : Cstubs.FOREIGN) =3D
=C2=A0 =C2=A0struct
=C2=A0 =C2=A0 =C2=A0let foo =3D F.foreign "foo" Ctypes.(void @-&g= t; returning int)
=C2=A0 =C2=A0end

and the calls to 'write_c' and 'write_ml' other files. =C2= =A0I'll put the
call to 'write_c' along with code to print out the headers used in<= br> generate_c.ml:

=C2=A0 =C2=A0let () =3D
=C2=A0 =C2=A0 =C2=A0print_endline "#include <ctypes/cstubs_internal= s.h>";
=C2=A0 =C2=A0 =C2=A0print_endline "#include \"foo.h\"";=
=C2=A0 =C2=A0 =C2=A0Cstubs.write_c Format.std_formatter ~prefix:"foo_&= quot;
=C2=A0 =C2=A0 =C2=A0 =C2=A0(module Foo_binding.Bindings)

The call to 'write_ml' goes in generate_ml.ml:

=C2=A0 =C2=A0let () =3D Cstubs.write_ml Format.std_formatter ~prefix:"= foo_"
=C2=A0 =C2=A0 =C2=A0(module Foo_binding.Bindings)

Then we can compile and run the two programs to generate the stub code:

=C2=A0 $ ocamlfind ocamlc -c -package ctypes.stubs \
=C2=A0 =C2=A0 =C2=A0foo= _binding.ml generate= _c.ml generate_ml.m= l
=C2=A0 $ ocamlfind ocamlc -o generate_ml.native -linkpkg -package ctypes.st= ubs \
=C2=A0 =C2=A0 =C2=A0foo_binding.cmo generate_ml.cmo
=C2=A0 $ ./generate_ml.native > generated.ml
=C2=A0 $ ocamlfind ocamlc -o generate_c.native -linkpkg -package ctypes.stu= bs \
=C2=A0 =C2=A0 =C2=A0foo_binding.cmo generate_c.cmo
=C2=A0 $ ./generate_c.native > generated_c_stubs.c

We can then compile the stub code and link it in with the bindings
functor and the library containing 'foo':

=C2=A0 $ ocamlfind ocamlc -c -package ctypes.stubs -I `ocamlc -where`/.. \<= br> =C2=A0 =C2=A0 =C2=A0generated_c_stubs.c generated.ml
=C2=A0 $ ocamlfind ocamlmklib -o foo -linkpkg -package ctypes.stubs \
=C2=A0 =C2=A0 =C2=A0generated_c_stubs.o generated.cmo foo_binding.cmo -L. -= lfoo

Finally, we can load the code and call the 'foo' function:

=C2=A0 =C2=A0$ ocaml -short-paths
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0OCaml version 4.01.0

=C2=A0 =C2=A0# #use "topfind";;
=C2=A0 =C2=A0[...]
=C2=A0 =C2=A0# #require "ctypes.stubs";;
=C2=A0 =C2=A0[...]
=C2=A0 =C2=A0# #load "foo.cma";;
=C2=A0 =C2=A0# include Foo_binding.Bindings(Generated);;
=C2=A0 =C2=A0val foo : unit -> int =3D <fun>
=C2=A0 =C2=A0# foo ();;
=C2=A0 =C2=A0foo called
=C2=A0 =C2=A0- : int =3D 3

The full stub generation interface (which is actually just the
'write_ml' and 'write_c' functions) is here:

=C2=A0 =C2=A0https://github.com/ocamllabs/oc= aml-ctypes/blob/1e1634/src/cstubs/cstubs.mli

Jeremy

--
Caml-list mailing list. =C2=A0Subscription management and archives:
ht= tps://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
--001a11c12804619c4104f584e8b2--