From: Matthieu Dubuget <matthieu.dubuget@gmail.com>
To: caml-list@inria.fr
Cc: Ben Jakb <ben.jakb@gmail.com>
Subject: Re: [Caml-list] Shared libraries with ocamlopt callable from C (without main())?
Date: Sat, 10 Jan 2009 12:50:43 +0100 [thread overview]
Message-ID: <49688B93.7080803@gmail.com> (raw)
In-Reply-To: <fa75c1020901091722m3e249c37mb963b54c08cdb2db@mail.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
next prev parent reply other threads:[~2009-01-10 11:50 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-01-08 22:45 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 [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49688B93.7080803@gmail.com \
--to=matthieu.dubuget@gmail.com \
--cc=ben.jakb@gmail.com \
--cc=caml-list@inria.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox