caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: "Milan Stanojević" <milanst@gmail.com>
To: Jeremy Yallop <yallop@gmail.com>
Cc: Dan Benjamin <dbenjamin@janestreet.com>,
	David Sheets <sheets@alum.mit.edu>,
	 Bruno Deferrari <utizoc@gmail.com>, O Caml <caml-list@inria.fr>
Subject: Re: [Caml-list] Static linking via Ctypes?
Date: Wed, 26 Mar 2014 13:25:26 -0400	[thread overview]
Message-ID: <CAKR7PS-geFfh2eRYi0FD+d3OQB=UR1duQnQHYzfkg4T=cgGNig@mail.gmail.com> (raw)
In-Reply-To: <CAAxsn=FkJepR8Mj4kkPysFhAyGaSZOjFJ6rDSdo766x0f_Xi_w@mail.gmail.com>

Interesting. Thanks for the explanation.

Just wanted to add that what David Sheets suggested worked for us
(Jane Street) without need for any special linker flags apart from
what our build system already does for C files which I think is pretty
standard (compiles all C files into a library that is then linked into
the packed ocaml library).
But it's just one specific linux distribution




On Tue, Mar 25, 2014 at 7:14 PM, Jeremy Yallop <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.  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ć 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 = 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) =
>   struct
>      let f = 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) =
>    struct
>      let foo = 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 () =
>      print_endline "#include <ctypes/cstubs_internals.h>";
>      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 () = 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 = <fun>
>    # foo ();;
>    foo called
>    - : int = 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.mli
>
> 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

  parent reply	other threads:[~2014-03-26 17:26 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-25 14:54 dbenjamin
2014-03-25 15:04 ` Bruno Deferrari
2014-03-25 15:11   ` Dan Benjamin
2014-03-25 15:24     ` David Sheets
2014-03-25 17:55       ` Dan Benjamin
2014-03-25 21:19         ` Jeremy Yallop
2014-03-25 21:37           ` Milan Stanojević
2014-03-25 23:14             ` Jeremy Yallop
2014-03-26 16:24               ` Travis Brady
2014-03-26 17:17                 ` Daniel Bünzli
2014-03-26 17:25               ` Milan Stanojević [this message]
2014-03-25 15:10 ` Daniel Bünzli

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAKR7PS-geFfh2eRYi0FD+d3OQB=UR1duQnQHYzfkg4T=cgGNig@mail.gmail.com' \
    --to=milanst@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=dbenjamin@janestreet.com \
    --cc=sheets@alum.mit.edu \
    --cc=utizoc@gmail.com \
    --cc=yallop@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).