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 mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by sympa.inria.fr (Postfix) with ESMTPS id 4B57F7F890 for ; Wed, 26 Mar 2014 00:14:52 +0100 (CET) Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of yallop@gmail.com) identity=pra; client-ip=74.125.82.41; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="yallop@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail3-smtp-sop.national.inria.fr: domain of yallop@gmail.com designates 74.125.82.41 as permitted sender) identity=mailfrom; client-ip=74.125.82.41; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="yallop@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-wg0-f41.google.com) identity=helo; client-ip=74.125.82.41; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="postmaster@mail-wg0-f41.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AsUBAIgNMlNKfVIplWdsb2JhbABEFYNBSwyDB79mgRUIFg4BAQEBBw0JCRIqgiUBAQEEIwQZARsYBQEDDAYFCw0CAiYCAiIBEQEFARwGG4dcAQMRDaEnizVZUYMOllEKGScNZIY3EQEFDIEdi0WBTTMHgm+BSQSYTYEyjxEYKYRcPQ X-IPAS-Result: AsUBAIgNMlNKfVIplWdsb2JhbABEFYNBSwyDB79mgRUIFg4BAQEBBw0JCRIqgiUBAQEEIwQZARsYBQEDDAYFCw0CAiYCAiIBEQEFARwGG4dcAQMRDaEnizVZUYMOllEKGScNZIY3EQEFDIEdi0WBTTMHgm+BSQSYTYEyjxEYKYRcPQ X-IronPort-AV: E=Sophos;i="4.97,730,1389740400"; d="scan'208";a="54111564" Received: from mail-wg0-f41.google.com ([74.125.82.41]) by mail3-smtp-sop.national.inria.fr with ESMTP/TLS/RC4-SHA; 26 Mar 2014 00:14:51 +0100 Received: by mail-wg0-f41.google.com with SMTP id n12so693491wgh.0 for ; Tue, 25 Mar 2014 16:14:51 -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:content-transfer-encoding; bh=cylEeyQhuDfx0v7uKuCKk+34e15HGRlf0Oky7+DKhOg=; b=eQ3b2o984JGwdy376hTlKp6MthAxLMMbIBG6kl6jcXCB7rLMAwWfPqg/ntLZ1oYU1+ ew66O8NGRro8dO+Huj0g839AfGuTaRTYYVcjOn1SKf/BVpuF6BnL57158QIcPc/2cf4X Zqsm/3R8qtxoI8xgt2IiG8Q+FkogxFGKqaG17ccQ6ChUisNygsHLnmOJ8QZJnRowbHAi f1mbNXdjepg4bYIXTwPCn4PNVnKH7nMbvUMqE9LhM9etVDMb83dlH9Dd75kBFPA6tvKm hVlUJ6Ms44+Lk0JAINIs9eqeWnHl0+WdLAJjypDybb4dmXweDzP7dkKWNDnr4TxgstwR hm+w== MIME-Version: 1.0 X-Received: by 10.180.77.49 with SMTP id p17mr27273180wiw.4.1395789290928; Tue, 25 Mar 2014 16:14:50 -0700 (PDT) Received: by 10.217.5.65 with HTTP; Tue, 25 Mar 2014 16:14:50 -0700 (PDT) In-Reply-To: References: Date: Tue, 25 Mar 2014 23:14:50 +0000 Message-ID: From: Jeremy Yallop To: =?UTF-8?Q?Milan_Stanojevi=C4=87?= Cc: Dan Benjamin , David Sheets , Bruno Deferrari , O Caml Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [Caml-list] Static linking via Ctypes? 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.= mli Jeremy