* Shared libraries with ocamlopt callable from C (without main())? @ 2009-01-08 22:45 Ben Aurel 2009-01-09 8:21 ` [Caml-list] " Matthieu Dubuget 0 siblings, 1 reply; 10+ messages in thread From: Ben Aurel @ 2009-01-08 22:45 UTC (permalink / raw) To: caml-list hi I'm thinking about the possibility to use OCaml as an extension language. If I wanted to call a OCaml function from langX I had to use a C wrapper. langX -> ( C API of langX | C Wrapper | C API of OCaml ) -> OCaml Maybe I make it more complicated than it is. But could somebody tell me if ( and maybe how ) this can be done. I made some attempts, but there is always a main() function involved. But this C wrapper would be a shared library. Thanks in advance ben ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())? 2009-01-08 22:45 Shared libraries with ocamlopt callable from C (without main())? Ben Aurel @ 2009-01-09 8:21 ` 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 0 siblings, 2 replies; 10+ messages in thread From: Matthieu Dubuget @ 2009-01-09 8:21 UTC (permalink / raw) To: caml-list Ben Aurel a écrit : > I'm thinking about the possibility to use OCaml as an extension > language. If I wanted to call a OCaml function from langX I had to use > a C wrapper. > > langX -> ( C API of langX | C Wrapper | C API of OCaml ) -> OCaml > Yes > But could somebody tell me if ( and maybe how ) this can be done. I made some attempts, but > there is always a main() function involved. But this C wrapper would be a shared library. > Exactly. You can deliver your OCaml code as shared library, and then call it from any language that can call a shared library. Could you point out what problem you faced? Salutations Matt ^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [Caml-list] Shared libraries with ocamlopt callable from C(without main())? 2009-01-09 8:21 ` [Caml-list] " Matthieu Dubuget @ 2009-01-09 8:44 ` RABIH.ELCHAAR 2009-01-10 1:22 ` [Caml-list] Shared libraries with ocamlopt callable from C (without main())? Ben Jakb 1 sibling, 0 replies; 10+ messages in thread From: RABIH.ELCHAAR @ 2009-01-09 8:44 UTC (permalink / raw) To: ben.aurel; +Cc: caml-list The simplest way of achieving what you want might be the following: 1) Write the ocaml code you want to call. 2) register your caml functions via Callback.register 3) In your C code, define the callback values for each ocaml function, via a macro like #define ACTION(actionname) \ static value *actionname##_closure = NULL; and fore each c function that wraps the caml call, call ACTION("camlfunctionname") before your c wrapping code. 4) define an initialization helper (to get the pointers to ocaml functions), something like #define INITACTION(actionname) \ actionname##_closure = caml_named_value(#actionname); 5) In your DLLMain function, you can have something like BOOL APIENTRY DllMain(HANDLE module, DWORD reason, void *reserved) { char * argv[2]; switch (reason) { case DLL_PROCESS_ATTACH: argv[0] = "--"; argv[1] = NULL; caml_startup(argv); INITACTION(analyze) INITACTION(updateBlob) ..... break; } return TRUE; } This handles the C functions:(C Wrapper | C API of OCaml ) -> OCaml defining a C dll with the needed entries. You can use afterwards your langX -> ( C API of langX -> call above dll). If your langX can call directly C functions without the need of type conversions, this can do. If not, this approach might give you two dlls (langX -> C dll) and (C -> ocaml) dll. If you want only one dll, I think this is only a linking issue, and can be solved by inputing the C->ocaml , compiled ocaml and langX->C together to the linker. Hope this helps, Sincerely, Rabih Chaar -----Message d'origine----- De : caml-list-bounces@yquem.inria.fr [mailto:caml-list-bounces@yquem.inria.fr] De la part de Matthieu Dubuget Envoyé : vendredi 9 janvier 2009 09:22 À : caml-list@inria.fr Objet : Re: [Caml-list] Shared libraries with ocamlopt callable from C(without main())? Ben Aurel a écrit : > I'm thinking about the possibility to use OCaml as an extension > language. If I wanted to call a OCaml function from langX I had to use > a C wrapper. > > langX -> ( C API of langX | C Wrapper | C API of OCaml ) -> OCaml > Yes > But could somebody tell me if ( and maybe how ) this can be done. I made some attempts, but > there is always a main() function involved. But this C wrapper would be a shared library. > Exactly. You can deliver your OCaml code as shared library, and then call it from any language that can call a shared library. Could you point out what problem you faced? Salutations Matt _______________________________________________ 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 This message and any attachments (the "message") are confidential, intended solely for the addressee(s), and may contain legally privileged information. Any unauthorised use or dissemination is prohibited. E-mails are susceptible to alteration. Neither Societe Generale Asset Management nor any of its subsidiaries or affiliates shall be liable for the message if altered, changed or falsified. Find out more about Societe Generale Asset Management's proposal on www.sgam.com ******** Ce message et toutes les pieces jointes (ci-apres le "message") sont confidentiels et susceptibles de contenir des informations couvertes par le secret professionnel. Ce message est etabli a l'intention exclusive de ses destinataires. Toute utilisation ou diffusion non autorisee est interdite. Tout message electronique est susceptible d'alteration. Societe Generale Asset Management et ses filiales declinent toute responsabilite au titre de ce message s'il a ete altere, deforme ou falsifie. Decouvrez l'offre et les services de Societe Generale Asset Management sur le site www.sgam.fr ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())? 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 ` Ben Jakb 2009-01-10 11:50 ` Matthieu Dubuget 2009-01-11 16:27 ` [Caml-list] " Xavier Leroy 1 sibling, 2 replies; 10+ messages in thread From: Ben Jakb @ 2009-01-10 1:22 UTC (permalink / raw) To: matthieu.dubuget, caml-list > Could you point out what problem you faced? I try to create a static library called "libadd5wrapperlib.a" ( I know kinda WTF ). So here is my simple example: (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;; ===== $ cat ./add5wrapperlib.c (Wraps the Ocaml code ) ===== #include <stdio.h> #include <caml/mlvalues.h> #include <caml/callback.h> int add5wrapper(char **argv) { int add_5; caml_startup(argv); add_5=Int_val(callback(*caml_named_value("add five"),Val_unit)); return add_5; } ===== $ cat ./include/libadd5wrapper.h (header file) ===== extern int add5 (char **argv); ===== $ cat ./main.c ===== #include <stdio.h> #include "libadd5wrapper.h" int main (int argc,char **argv){ printf("Gimme - %d \n", add5wrapper()); return 0; } Now I try to BUILD the whole thing: ---------------------------------------------- # 1.) Build the OCaml code ocamlopt -output-obj add5.ml -o add5-prog.o # 2.) Create the static library gcc -c add5wrapperlib.c ar rs lib/libadd5wrapperlib.a add5wrapperlib.o # 3.) Create the main object file gcc -c main.c -Iinclude -I"`ocamlc -where`" # 4.) Build the whole thing: gcc --static -Iinclude -Llib -o mainprog.opt main.o add5wrapperlib.o -L"`ocamlc -where`" -ladd5wrapperlib -lm -ldl -lasmrun Number 4 is where it breaks. I get a ton of errors and this is where it ends for me. Because # 4 is also the point where I definitely have no idea what I'm doing. Thanks for helping me. Errors of #4: /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(startup.o): In function `caml_main': startup.c:(.text+0x209): undefined reference to `caml_data_segments' startup.c:(.text+0x21d): undefined reference to `caml_code_segments' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_ceil_float': floats.c:(.text+0x225): undefined reference to `ceil' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_atan2_float': floats.c:(.text+0x24b): undefined reference to `atan2' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_atan_float': floats.c:(.text+0x268): undefined reference to `atan' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_acos_float': floats.c:(.text+0x285): undefined reference to `acos' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_asin_float': floats.c:(.text+0x2a2): undefined reference to `asin' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_tanh_float': floats.c:(.text+0x2bf): undefined reference to `tanh' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_tan_float': floats.c:(.text+0x2dc): undefined reference to `tan' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_cosh_float': floats.c:(.text+0x2f9): undefined reference to `cosh' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_cos_float': floats.c:(.text+0x316): undefined reference to `cos' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_sinh_float': floats.c:(.text+0x333): undefined reference to `sinh' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_sin_float': floats.c:(.text+0x350): undefined reference to `sin' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_power_float': floats.c:(.text+0x376): undefined reference to `pow' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_sqrt_float': floats.c:(.text+0x3a6): undefined reference to `sqrt' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_log10_float': floats.c:(.text+0x487): undefined reference to `log10' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_log_float': floats.c:(.text+0x4a4): undefined reference to `log' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_fmod_float': floats.c:(.text+0x599): undefined reference to `fmod' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_floor_float': floats.c:(.text+0x5b6): undefined reference to `floor' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(floats.o): In function `caml_exp_float': floats.c:(.text+0x5d3): undefined reference to `exp' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(unix.o): In function `caml_dlerror': unix.c:(.text+0x1db): undefined reference to `dlerror' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(unix.o): In function `caml_dlsym': unix.c:(.text+0x1f5): undefined reference to `dlsym' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(unix.o): In function `caml_dlclose': unix.c:(.text+0x208): undefined reference to `dlclose' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(unix.o): In function `caml_dlopen': unix.c:(.text+0x223): undefined reference to `dlopen' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(i386.o): In function `caml_start_program': (.text+0x129): undefined reference to `caml_program' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(i386.o): In function `caml_callback2_exn': (.text+0x221): undefined reference to `caml_apply2' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(i386.o): In function `caml_callback3_exn': (.text+0x241): undefined reference to `caml_apply3' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_array_bound_error': fail.c:(.text+0x75): undefined reference to `caml_exn_Invalid_argument' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_raise_stack_overflow': fail.c:(.text+0x98): undefined reference to `caml_bucket_Stack_overflow' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_raise_out_of_memory': fail.c:(.text+0xaa): undefined reference to `caml_bucket_Out_of_memory' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_raise_sys_error': fail.c:(.text+0x144): undefined reference to `caml_exn_Sys_error' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_invalid_argument': fail.c:(.text+0x17d): undefined reference to `caml_exn_Invalid_argument' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_failwith': fail.c:(.text+0x196): undefined reference to `caml_exn_Failure' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_raise_sys_blocked_io': fail.c:(.text+0x21a): undefined reference to `caml_exn_Sys_blocked_io' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_raise_not_found': fail.c:(.text+0x22c): undefined reference to `caml_exn_Not_found' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_raise_zero_divide': fail.c:(.text+0x23e): undefined reference to `caml_exn_Division_by_zero' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(fail.o): In function `caml_raise_end_of_file': fail.c:(.text+0x250): undefined reference to `caml_exn_End_of_file' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(roots.o): In function `caml_init_frame_descriptors': roots.c:(.text+0x118): undefined reference to `caml_frametable' roots.c:(.text+0x136): undefined reference to `caml_frametable' roots.c:(.text+0x18f): undefined reference to `caml_frametable' roots.c:(.text+0x207): undefined reference to `caml_frametable' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(roots.o): In function `caml_do_roots': roots.c:(.text+0x25c): undefined reference to `caml_globals' roots.c:(.text+0x293): undefined reference to `caml_globals' /usr/local/godi/lib/ocaml/std-lib/libasmrun.a(roots.o): In function `caml_oldify_local_roots': roots.c:(.text+0x364): undefined reference to `caml_globals' roots.c:(.text+0x36b): undefined reference to `caml_globals' collect2: ld returned 1 exit status 2009/1/9 Matthieu Dubuget <matthieu.dubuget@gmail.com>: > Ben Aurel a écrit : >> I'm thinking about the possibility to use OCaml as an extension >> language. If I wanted to call a OCaml function from langX I had to use >> a C wrapper. >> >> langX -> ( C API of langX | C Wrapper | C API of OCaml ) -> OCaml >> > > Yes > >> But could somebody tell me if ( and maybe how ) this can be done. I made some attempts, but >> there is always a main() function involved. But this C wrapper would be a shared library. >> > > Exactly. You can deliver your OCaml code as shared library, and then > call it from > any language that can call a shared library. > > Could you point out what problem you faced? > > Salutations > > Matt > > > _______________________________________________ > 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 > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())? 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 [not found] ` <200901101911.41594.monnier.florent@gmail.com> 2009-01-11 16:27 ` [Caml-list] " Xavier Leroy 1 sibling, 2 replies; 10+ messages in thread From: Matthieu Dubuget @ 2009-01-10 11:50 UTC (permalink / raw) To: caml-list; +Cc: Ben Jakb 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 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())? 2009-01-10 11:50 ` Matthieu Dubuget @ 2009-01-10 15:28 ` Ben Jakb 2009-01-10 15:36 ` Matthieu Dubuget [not found] ` <200901101911.41594.monnier.florent@gmail.com> 1 sibling, 1 reply; 10+ messages in thread From: Ben Jakb @ 2009-01-10 15:28 UTC (permalink / raw) To: matthieu.dubuget, caml-list 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 > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())? 2009-01-10 15:28 ` Ben Jakb @ 2009-01-10 15:36 ` Matthieu Dubuget 2009-01-10 18:08 ` Ben Jakb 0 siblings, 1 reply; 10+ messages in thread From: Matthieu Dubuget @ 2009-01-10 15:36 UTC (permalink / raw) To: caml-list; +Cc: Ben Jakb Ben Jakb a écrit : > matthieu, > thanks for the interesting answer. > Unfortunately I can't build 'mycamlbuild.ml', and it is a bit too > advanced for me to understand. If you have a > 3.10 version of ocaml, you don't need to compile yourself myocamlbuild.ml. This is done automatically by ocamlbuild. > > 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? Yes ;-) This is exactly why i use assert there. I introduced a bug: the string in the C file is "add_five", while the registered one in the ml file is "add five". Hope this helps ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())? 2009-01-10 15:36 ` Matthieu Dubuget @ 2009-01-10 18:08 ` Ben Jakb 0 siblings, 0 replies; 10+ messages in thread From: Ben Jakb @ 2009-01-10 18:08 UTC (permalink / raw) To: matthieu.dubuget, caml-list > I introduced a bug: the string in the C file is "add_five", while the > registered one in the ml file is "add five". Touché. I suppose I looked to long to this code And yes it works now, thanks ... 2009/1/10 Matthieu Dubuget <matthieu.dubuget@gmail.com>: > Ben Jakb a écrit : >> matthieu, >> thanks for the interesting answer. >> Unfortunately I can't build 'mycamlbuild.ml', and it is a bit too >> advanced for me to understand. > > If you have a > 3.10 version of ocaml, you don't need to compile > yourself myocamlbuild.ml. > > This is done automatically by ocamlbuild. > >> >> 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? > > Yes ;-) > > This is exactly why i use assert there. > > I introduced a bug: the string in the C file is "add_five", while the > registered one in the ml file is "add five". > > > Hope this helps > ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <200901101911.41594.monnier.florent@gmail.com>]
* Re: Shared libraries with ocamlopt callable from C (without main())? [not found] ` <200901101911.41594.monnier.florent@gmail.com> @ 2009-01-10 18:18 ` Ben Jakb 0 siblings, 0 replies; 10+ messages in thread From: Ben Jakb @ 2009-01-10 18:18 UTC (permalink / raw) To: Florent Monnier, caml-list > 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 > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())? 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-11 16:27 ` Xavier Leroy 1 sibling, 0 replies; 10+ messages in thread From: Xavier Leroy @ 2009-01-11 16:27 UTC (permalink / raw) To: Ben Jakb; +Cc: matthieu.dubuget, caml-list > ===== $ cat ./main.c ===== > #include <stdio.h> > #include "libadd5wrapper.h" > int main (int argc,char **argv){ > printf("Gimme - %d \n", add5wrapper()); Should be add5wrapper(argv) -- as gcc's warnings told you. > return 0; > } > > Now I try to BUILD the whole thing: > [...] > Number 4 is where it breaks. I get a ton of errors and this is where > it ends for me. Because # 4 is also the point where I definitely have > no idea what I'm doing. Two things: - You're not linking in add5-prog.o as far as I can see - In static mode, the Unix linker is very picky about the relative order of -lxxx arguments on the command-line. For more information, see the Info pages for GNU ld. You probably don't need -static anyway. The following works: ocamlopt -output-obj add5.ml -o add5-prog.o gcc -I`ocamlc -where` -c add5wrapperlib.c gcc -c main.c gcc -o mainprog.opt main.o add5wrapperlib.o add5-prog.o \ -L`ocamlc -where` -lasmrun -ldl -lm Add "-static" to the last line if you know you really need it. Hope this puts you back on tracks. - Xavier Leroy ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2009-01-11 16:28 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-01-08 22:45 Shared libraries with ocamlopt callable from C (without main())? 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 2009-01-11 16:27 ` [Caml-list] " Xavier Leroy
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox