Merge branch 'local-ocamlbuild' into local-trunk
[SXSI/xpathcomp.git] / myocamlbuild.ml
1 open Ocamlbuild_plugin
2 open Command
3 open Myocamlbuild_config
4 open Format
5
6 let print_list l =
7   Printf.eprintf "%![";
8   List.iter (fun s -> Printf.eprintf " '%s' " s) l;
9   Printf.eprintf "]\n%!"
10
11
12 (*let cxx_flags = S (List.map ( fun x -> A x) cxx_flags)*)
13 let _A x = A x
14 let _S ?(extra=N) l = S (List.map (fun e -> (S [extra; _A e] )) l)
15 ;;
16
17 let cxx_flags = ref [ _S cxx_flags ]
18
19 let project_dirs = [ src_path; include_path ]
20 let cxx_include_flags = _S cxx_includes
21 let cxx_link_flags = ref  [ _S cxx_lpaths; _S cxx_libs]
22 let native_link_flags = ref (List.map (fun s -> s ^ ".cmxa") ocaml_link)
23 let byte_link_flags =  ref ("-custom" :: (List.map (fun s -> s ^ ".cma") ocaml_link))
24 let link_flags = [ A"-linkpkg" ]
25
26 let native_compile_flags = ref [A"-fno-PIC"]
27 let compile_flags = ref []
28
29 let dwsize = sprintf "-DWORDSIZE%i" Sys.word_size
30
31 (* Utils *)
32 let ( @= ) r l = r := !r @ l
33 let ( =:: ) r e = r := e :: !r
34
35 (* Pre-processed files *)
36 let pp_macro_options = ref
37   [ A "-parser"; A "macro"; A dwsize; A "-I"; P include_path ]
38
39 let include_full_path =  Pathname.pwd / include_path
40 module Depends =
41 struct
42 open Scanf
43 let scan_include ml =
44   let ic = try open_in ml with
45       _ -> open_in (include_full_path / ml)
46   in
47   let includes = ref [] in
48   try
49     while true do
50       let s = input_line ic in
51       try
52         if String.length s > 0 then sscanf s " INCLUDE \"%s@\"" ((=::) includes)
53       with
54           Scan_failure _ -> ()
55     done; []
56   with End_of_file -> close_in ic; !includes
57
58 let ocaml ml =
59   let rec loop file =
60     let includes = scan_include file in
61     List.fold_left (fun a i -> (loop i) @ a) includes includes
62   in
63   let includes = loop ml in
64     dep [ "file:" ^ ml ]
65       (List.map (fun s ->  include_path / s) includes)
66
67 let parse_depends file depfile =
68   let ichan = open_in depfile in
69   let iscan = Scanning.from_channel ichan in
70   let () = bscanf iscan " %s@: " ignore in
71   let () = bscanf iscan " %s " ignore in
72   let includes = ref [] in
73   try
74     while true do
75       try
76         let s = bscanf iscan " %s " (fun s -> s) in
77         if s = "" then raise End_of_file;
78         if s <> "\\" then includes =::s
79       with
80           Scan_failure _ -> ()
81     done; []
82   with
83       End_of_file -> close_in ichan; !includes
84
85 let uniq l =
86   let rec loop l acc =
87     match l with
88       | []  -> acc
89       | [ e ] -> e::acc
90       | e1 :: ((e2 :: _) as ll) ->
91         loop ll (if e1 = e2 then acc else e1 :: acc)
92   in
93   loop (List.sort compare l) []
94
95 let cxx cpp =
96   let depfile = ( cpp ^ ".depends") in
97   let cmd = Cmd (S[ A cxx_cmd ; S !cxx_flags; cxx_include_flags ; A"-MM";
98                     A "-MG"; A "-MF";  P depfile; P cpp])
99   in
100   let () = Command.execute ~quiet:true ~pretend:false cmd in
101   let includes = parse_depends cpp depfile in
102   List.filter (Pathname.is_relative) (uniq includes)
103 end
104
105 let cxx_compile env build =
106   let src = env "%.cpp" and obj = env "%.o" in
107   let local_include = Depends.cxx src in
108   let local_dispatch = List.map (fun p -> List.map (fun p' -> p'/p) project_dirs) local_include in
109   let  () = ignore (build local_dispatch) in
110   Cmd(S[A cxx_cmd; A "-o" ; P obj; A "-c";  S !cxx_flags; cxx_include_flags; P src])
111
112 (* Native compile and link action *)
113
114 let ocamlfind x = S[ A"ocamlfind"; x ; A "-package"; A ocamlfind_packages ]
115
116 let ppopt l = List.map (fun e -> S[ A"-ppopt"; e ]) l
117
118 let () = dispatch begin
119   function
120     | Before_rules ->
121
122       Options.ocamlc := ocamlfind  (A"ocamlc");
123       Options.ocamlopt := ocamlfind (A"ocamlopt");
124       Options.ocamldep := ocamlfind (A"ocamldep");
125       Options.ocamldoc := ocamlfind (A"ocamldoc");
126       Options.ocamlmktop := ocamlfind (A"ocamlmktop");
127
128
129       if (List.mem "profile" !Options.tags) then begin
130         pp_macro_options @= [ A "-DPROFILE" ];
131         native_compile_flags @= [A "-p" ];
132         native_link_flags @= [ "-p" ];
133         cxx_flags @= [ A "-pg" ];
134         cxx_link_flags @= [ A "-pg" ];
135       end;
136
137       if (List.mem "debug" !Options.tags) then begin
138         pp_macro_options @= [ A "-DDEBUG" ];
139         cxx_flags @= [ A "-O0"; A "-g" ];
140         cxx_link_flags @= [ A "-g" ];
141       end
142       else begin
143         compile_flags @= [A "-noassert"; A "-unsafe"];
144         native_compile_flags @= [ A "-inline"; A ocaml_inline ];
145         cxx_flags @= [ A "-O3" ]
146       end;
147
148       let dir_path = Pathname.pwd / src_path in
149       let dir = Pathname.readdir dir_path in
150
151       Array.iter (fun entry ->
152         if Pathname.check_extension entry "ml" then
153           Depends.ocaml (src_path / entry)
154         (* else if Pathname.check_extension entry "cpp" then
155           Depends.cxx (src_path / entry) *)
156       ) dir;
157
158     | After_rules ->
159       dep [ "link" ] cstub_lib;
160       rule "compile cpp -> o" ~prod:"%.o" ~deps:[ "%.cpp"] cxx_compile;
161
162       let syntax_flags = S ([ A "-syntax"; A "camlp4o";
163                             S (ppopt [A "-printer" ; A"ocaml"]);
164                             S (ppopt !pp_macro_options) ])
165       in
166       flag [ "ocaml"; "ocamldep"] syntax_flags;
167       flag [ "ocaml"; "compile" ] (S[ A "-cc"; A cxx_cmd; syntax_flags; S !compile_flags ]);
168       flag [ "ocaml"; "native"; "compile" ] (S !native_compile_flags);
169       flag [ "ocaml"; "link" ]
170         (S [ S link_flags ; A "-cc"; A cxx_cmd; A "-cclib" ;
171              Quote (S [ _S cstub_lib;  S !cxx_link_flags]) ]);
172       flag [ "ocaml"; "byte"; "link" ] (_S !byte_link_flags);
173       flag [ "ocaml"; "native"; "link" ] (_S !native_link_flags);
174       flag [ "c"; "ocamlmklib"] (S[ A "-custom"; ])
175     | _ -> ()
176 end