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 (18:18) |
From: | Ben Jakb <ben.jakb@g...> |
Subject: | Re: Shared libraries with ocamlopt callable from C (without main())? |
> 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 >