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: | -- (:) |
| 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
>