Browse thread
Shared libraries with ocamlopt callable from C (without main())?
[
Home
]
[ Index:
by date
|
by threads
]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: | 2009-01-10 (15:28) |
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 >