-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmyocamlbuild.ml
132 lines (112 loc) · 4.72 KB
/
myocamlbuild.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
(* Modified & taken from
http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild
*)
open Ocamlbuild_plugin
(* these functions are not really officially exported *)
let run_and_read = Ocamlbuild_pack.My_unix.run_and_read
let blank_sep_strings = Ocamlbuild_pack.Lexers.blank_sep_strings
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
let split_nl s = split s '\n'
let before_space s =
try
String.before s (String.index s ' ')
with Not_found -> s
let singletons = List.map (fun x -> [x])
let ml_name =
let default_char = '_' in
let name_char = function
| ('_' | 'a'..'z' | 'A'..'Z' | '0'..'9' | '\'') as c -> c
| _ -> default_char in
let name_char0 = function
| ('_' | 'a'..'z') as c -> c
| 'A'..'Z' as c -> Char.lowercase c
| _ -> default_char in
fun s ->
let s = String.copy s in
for i = 0 to String.length s - 1 do
s.[i] <- (if i = 0 then name_char0 else name_char) s.[i];
done;
s
(* this lists all supported packages *)
let find_packages () =
List.map before_space (split_nl & run_and_read "ocamlfind list")
(* this is supposed to list available syntaxes, but I don't know how to do it. *)
let find_syntaxes () = ["camlp4o"; "camlp4r"]
(* ocamlfind command *)
let ocamlfind x = S[A"ocamlfind"; x]
let _ = dispatch begin function
| Before_options ->
(* by using Before_options one let command line options have an higher priority *)
(* on the contrary using After_options will guarantee to have the higher priority *)
(* override default commands by ocamlfind ones *)
(* always use -rectypes, otherwise it doesn't work with menhir --infer *)
Options.ocamlc := ocamlfind & S[A"ocamlc";A"-rectypes"];
Options.ocamlopt := ocamlfind & S[A"ocamlopt";A"-rectypes"];
Options.ocamldep := ocamlfind & A"ocamldep";
Options.ocamldoc := ocamlfind & S[A"ocamldoc";A"-rectypes"];
Options.ocamlmktop := ocamlfind & A"ocamlmktop"
| After_rules ->
(* When one link an OCaml library/binary/package, one should use -linkpkg *)
flag ["ocaml"; "link"; "program"] & A"-linkpkg";
(* For each ocamlfind package one inject the -package option when
* compiling, computing dependencies, generating documentation and
* linking. *)
List.iter begin fun pkg ->
flag ["ocaml"; "compile"; "pkg_"^pkg] & S[A"-package"; A pkg];
flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S[A"-package"; A pkg];
flag ["ocaml"; "doc"; "pkg_"^pkg] & S[A"-package"; A pkg];
flag ["ocaml"; "link"; "pkg_"^pkg] & S[A"-package"; A pkg];
flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S[A"-package"; A pkg];
end (find_packages ());
(* Like -package but for extensions syntax. Morover -syntax is useless
* when linking. *)
List.iter begin fun syntax ->
flag ["ocaml"; "compile"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
flag ["ocaml"; "ocamldep"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
flag ["ocaml"; "doc"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
flag ["ocaml"; "infer_interface"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
end (find_syntaxes ());
(* The default "thread" tag is not compatible with ocamlfind.
Indeed, the default rules add the "threads.cma" or "threads.cmxa"
options when using this tag. When using the "-linkpkg" option with
ocamlfind, this module will then be added twice on the command line.
To solve this, one approach is to add the "-thread" option when using
the "threads" package using the previous plugin.
*)
flag ["ocaml"; "pkg_threads"; "compile"] (S[A "-thread"]);
flag ["ocaml"; "pkg_threads"; "link"] (S[A "-thread"]);
flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"]);
flag ["ocaml"; "link"; "static"] (S[A"-ccopt";A"-static"]);
(*
A .of file should contain a list of filenames
It produces a .ml file containing these files as string values
*)
rule "%.of -> %.ml"
~prod:"%.ml"
~dep:"%.of"
begin fun env build ->
let dir = Filename.dirname & env "%.of" in
let contents =
env "%.of"
|> string_list_of_file
|> List.map ((/) dir)
|> List.map Ocamlbuild_pack.Pathname.normalize
|> singletons
|> build
|> List.map (fun file ->
let file = Outcome.good file in
Printf.sprintf "let %s = %S\n" (ml_name & Filename.basename file) (read_file file)
) in
Echo(contents, env "%.ml")
end;
| _ -> ()
end