caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: "Ben Jakb" <ben.jakb@gmail.com>
To: "Florent Monnier" <monnier.florent@gmail.com>, caml-list@inria.fr
Subject: Re: Shared libraries with ocamlopt callable from C (without main())?
Date: Sat, 10 Jan 2009 19:18:01 +0100	[thread overview]
Message-ID: <fa75c1020901101018y57fd0813m40741808698b33f0@mail.gmail.com> (raw)
In-Reply-To: <200901101911.41594.monnier.florent@gmail.com>

> Can I leech this example to include it in my small ocaml/C wrapping tutorial ?
> http://www.linux-nantes.org/%7Efmonnier/OCaml/ocaml-wrapping-c.php

this would be great (imho). Your articles where the starting point for
my attempts.


2009/1/10 Florent Monnier <monnier.florent@gmail.com>:
> Hi,
> Can I leech this example to include it in my small ocaml/C wrapping tutorial ?
> http://www.linux-nantes.org/%7Efmonnier/OCaml/ocaml-wrapping-c.php
>
> If so, do you want that your name appears or not or you don't mind ?
>
> Cheers
> Florent
> --
> Matthieu Dubuget a écrit :
>> Ben Jakb a écrit :
>> > I try to create a static library called "libadd5wrapperlib.a" ( I know
>> > kinda WTF ). So here is my simple example:
>>
>> I did not succeed (yet ;-) ) in making a static library…
>> I have an example with a shared one, though.
>>
>> > (Warning: You'll see a lot of bad code below, sorry for that, I work
>> > hard to improve)
>> >
>> > =====  $ cat ./add5.ml =====
>> >     (* the code doesnt add anything yet, it just gives 5 back *)
>> >     let add_five () =
>> >       let i = ref 0 in
>> >         i := 5;
>> >         !i;;
>> >     Callback.register "add five" add_five;;
>>
>> I wrote :
>>
>>       Callback.register "add five" (fun () -> 5)
>>
>> > =====  $ cat ./add5wrapperlib.c (Wraps the Ocaml code ) =====
>> >     #include <stdio.h>
>> >     #include <caml/mlvalues.h>
>> >     #include <caml/callback.h>
>>
>> #include <assert.h>
>>
>> #define CAMLCBK_INIT( callback, cbk_name) \
>>         static value *callback = NULL; \
>>         if (callback == NULL) callback = \
>>               caml_named_value(cbk_name);\
>>           assert(callback);
>>
>> static int init_done = 0;
>>
>> void init_lib(void){
>>   char *vide[1];
>>   vide[0] = NULL;
>>   if (!init_done){
>>       caml_startup(vide);
>>       init_done = 1;
>>   }
>> }
>>
>> int add5wrapper(){
>>   CAMLCBK_INIT(cbk, "add_five");
>>   return (Int_val ( caml_callback(*cbk, Val_unit)));
>> }
>>
>> > =====  $ cat ./include/libadd5wrapper.h (header file) =====
>>
>> extern void init_lib(void);
>> extern int add5wrapper(void);
>>
>> > =====  $ cat ./main.c =====
>> >     #include <stdio.h>
>> >     #include "libadd5wrapper.h"
>> >     int main (int argc,char **argv){
>>
>> init_lib();
>>
>> >        printf("Gimme - %d \n", add5wrapper());
>> >        return 0;
>> > }
>> >
>> > Now I try to BUILD the whole thing:
>> > ----------------------------------------------
>>
>> ocamlopt -c add5.ml
>> ocamlopt -c add5wrapperlib.c
>> ocamlopt -o add5lib.native.so -ccopt -shared add5.cmx add5wrapperlib.o
>>
>> ocamlc.opt -ccopt -Iinclude -c main.c
>> gcc -o maintest.native main.o -l:add5lib.native.so -L. -Wl,-rpath=.
>>
>> In fact, i used ocamlbuild.
>>
>>
>> --------------myocamlbuild.ml -------------------------------------
>> open Ocamlbuild_plugin
>> open Command
>> open Outcome
>>
>> (* properties as (string * string) list read from "ocamlc -config" *)
>> let my_ocamlc_config =
>>   let rec sc s h =
>>     Scanf.sscanf s "%s@: %s@\n%n"
>>       begin fun k v n->
>>               let h' = (k, v) :: h in
>>               let len = String.length s in
>>                 if
>>                       len - n <= 0
>>                 then
>>                       h'
>>                 else
>>                       sc (String.sub s n (len - n)) h'
>>       end in
>>     sc (Ocamlbuild_pack.My_unix.run_and_read "ocamlc -config") []
>>
>> let ext_o = List.assoc "ext_obj" my_ocamlc_config
>> let ext_so = List.assoc "ext_dll" my_ocamlc_config
>> let syst = List.assoc "system" my_ocamlc_config
>>
>> let split s ch =
>>   let x = ref [] in
>>   let rec go s =
>>     let pos = String.index s ch in
>>       x := (String.before s pos)::!x;
>>       go (String.after s (pos + 1))
>>   in
>>       try
>>       go s
>>       with Not_found -> !x
>>
>> exception Found of string
>>
>> let pwd () =
>>   let env = Array.to_list (Unix.environment ()) in
>>   let rec search = function
>>         [] -> ""
>>
>>       | h :: tl ->
>>
>>               try
>>                 Scanf.sscanf h "PWD=%s" (fun x -> x)
>>               with
>>                       _ -> search tl in
>>       search env
>>
>> let split_nl s = split s '\n'
>>
>> let before_space s =
>>   try
>>     String.before s (String.index s ' ')
>>   with Not_found -> s
>>
>> let uncap_module_path p =
>>   (Pathname.dirname p) / (String.uncapitalize (Pathname.basename p))
>>
>> let _ = dispatch begin function
>>
>>   | After_rules ->
>>
>>         if syst = "linux_elf" then
>>               flag ["link"; "cmldll"]  (S[A"-ccopt";A"-shared"])
>>         else if syst = "mingw" then begin
>>               flag ["link";"cmldll"] (S[A"-output-obj"])
>>         end;
>>
>>         flag ["cmldll";"link";"byte"] (S[A"-custom"]);
>>
>>         rule "Mixed C-Ocaml native DLL: cmldll & o* & cmx* -> native DLL
>> (.dll | .so)"
>>               ~dep:"%.cmldll"
>>               ~prod:("%.native" ^ ext_so)
>>               begin
>>                 fun env build ->
>>                       let output = env ("%.native" ^ ext_so)
>>                       and input = env "%.cmldll" in
>>                       let dir = Pathname.dirname input in
>>
>>                       (* TODO: use functions of Pathname module? *)
>>                       let ext_o_files, moduls_files =
>>                         string_list_of_file input |>
>>                                 List.partition (fun fic -> Filename.check_suffix fic ".o") in
>>                       let objs = ext_o_files |>
>>                               List.map Filename.chop_extension |>
>>                                       List.map (fun fic -> fic ^ ext_o) in
>>                       let cmxs = moduls_files |>
>>                               List.map (fun modul ->
>>                                                       (uncap_module_path modul) -.- "cmx") in
>>                       let deps = cmxs @ objs in
>>
>>                         List.iter ignore_good
>>                               (build (List.map (fun x -> [dir/x]) deps));
>>
>>                         Cmd (S [!Options.ocamlopt;
>>                                         A"-o"; Px output;
>>                                         T (tags_of_pathname output++"ocaml"++"native"++"cmldll"++"link");
>>                                         atomize_paths deps
>>                                        ])
>>               end;
>>
>>       (* Allows to have .h copied in the _build directory *)
>>       dep ["file:main.c"] ["include/libadd5wrapper.h"];
>>
>>         flag ["include_libadd"] (S[A"-ccopt";A"-Iinclude"]);
>>         tag_file "main.c" ["include_libadd"];
>>
>>         rule "Compile maintest.native"
>>               ~deps:["main.o"; "add5lib.native.so"]
>>               ~prod:"maintest.native"
>>               begin fun _ _ ->
>>                 let target = "maintest.native" in
>>                 let spc = "-Wl,-rpath=" ^ ((pwd ()) / (!Options.build_dir))  in
>>                       Cmd(
>>                         S[
>>                               A"gcc";
>>                               A"-o";A target;
>>                               A"main.o";
>>                               A"-l:add5lib.native.so";
>>                               A"-L."; A spc;
>>                         ])
>>               end;
>>
>>   | _ -> ()
>>
>> end
>>
>> --------------end of myocamlbuild.ml -----------------------
>>
>> and the helper file add5lib.mlcdll:
>>
>> -------------add5lib.mlcdll----------------------
>> Add5
>> add5wrapperlib.o
>> -------------end of add5lib.mlcdll------------------
>>
>> do
>> ocamlbuild maintest.native
>> in order to build.
>>
>> This myocamlbuild.ml file is a "work in progress".
>> You can use it as you want if it can be of any help for you.
>>
>> Salutations
>>
>> _______________________________________________
>> Caml-list mailing list. Subscription management:
>> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
>> Archives: http://caml.inria.fr
>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>


  parent reply	other threads:[~2009-01-10 18:18 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-08 22:45 Ben Aurel
2009-01-09  8:21 ` [Caml-list] " Matthieu Dubuget
2009-01-09  8:44   ` [Caml-list] Shared libraries with ocamlopt callable from C(without main())? RABIH.ELCHAAR
2009-01-10  1:22   ` [Caml-list] Shared libraries with ocamlopt callable from C (without main())? Ben Jakb
2009-01-10 11:50     ` Matthieu Dubuget
2009-01-10 15:28       ` Ben Jakb
2009-01-10 15:36         ` Matthieu Dubuget
2009-01-10 18:08           ` Ben Jakb
     [not found]       ` <200901101911.41594.monnier.florent@gmail.com>
2009-01-10 18:18         ` Ben Jakb [this message]
2009-01-11 16:27     ` Xavier Leroy

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=fa75c1020901101018y57fd0813m40741808698b33f0@mail.gmail.com \
    --to=ben.jakb@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=monnier.florent@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).