Version française
Home     About     Download     Resources     Contact us    
Browse thread
Shared libraries with ocamlopt callable from C (without main())?
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Ben Jakb <ben.jakb@g...>
Subject: Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())?
matthieu,
thanks for the interesting answer.
Unfortunately I can't build 'mycamlbuild.ml', and it is a bit too
advanced for me to understand.

Therefore I'll first go with your standard build commands. So - after
modifing the sources according to your suggestions I run:

BUILD
    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=.

EXECUTION
    cp add5lib.native.so  lib/
    ./maintest.native

ERROR
"maintest.native: add5wrapperlib.c:24: add5wrapper: Assertion `cbk' failed.
Aborted"

This is the referenced line:

    $ sed -n 24p add5wrapperlib.c
CAMLCBK_INIT(cbk, "add_five");


Any ideas what' wrong here?





2009/1/10 Matthieu Dubuget <matthieu.dubuget@gmail.com>:
> 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
>