1
|
(* OASIS_START *)
|
2
|
(* DO NOT EDIT (digest: 5a9a2168dcb86db37476d58b8c0e25b3) *)
|
3
|
module OASISGettext = struct
|
4
|
(* # 22 "src/oasis/OASISGettext.ml" *)
|
5
|
|
6
|
|
7
|
let ns_ str =
|
8
|
str
|
9
|
|
10
|
|
11
|
let s_ str =
|
12
|
str
|
13
|
|
14
|
|
15
|
let f_ (str: ('a, 'b, 'c, 'd) format4) =
|
16
|
str
|
17
|
|
18
|
|
19
|
let fn_ fmt1 fmt2 n =
|
20
|
if n = 1 then
|
21
|
fmt1^^""
|
22
|
else
|
23
|
fmt2^^""
|
24
|
|
25
|
|
26
|
let init =
|
27
|
[]
|
28
|
|
29
|
|
30
|
end
|
31
|
|
32
|
module OASISExpr = struct
|
33
|
(* # 22 "src/oasis/OASISExpr.ml" *)
|
34
|
|
35
|
|
36
|
|
37
|
|
38
|
|
39
|
open OASISGettext
|
40
|
|
41
|
|
42
|
type test = string
|
43
|
|
44
|
|
45
|
type flag = string
|
46
|
|
47
|
|
48
|
type t =
|
49
|
| EBool of bool
|
50
|
| ENot of t
|
51
|
| EAnd of t * t
|
52
|
| EOr of t * t
|
53
|
| EFlag of flag
|
54
|
| ETest of test * string
|
55
|
|
56
|
|
57
|
|
58
|
type 'a choices = (t * 'a) list
|
59
|
|
60
|
|
61
|
let eval var_get t =
|
62
|
let rec eval' =
|
63
|
function
|
64
|
| EBool b ->
|
65
|
b
|
66
|
|
67
|
| ENot e ->
|
68
|
not (eval' e)
|
69
|
|
70
|
| EAnd (e1, e2) ->
|
71
|
(eval' e1) && (eval' e2)
|
72
|
|
73
|
| EOr (e1, e2) ->
|
74
|
(eval' e1) || (eval' e2)
|
75
|
|
76
|
| EFlag nm ->
|
77
|
let v =
|
78
|
var_get nm
|
79
|
in
|
80
|
assert(v = "true" || v = "false");
|
81
|
(v = "true")
|
82
|
|
83
|
| ETest (nm, vl) ->
|
84
|
let v =
|
85
|
var_get nm
|
86
|
in
|
87
|
(v = vl)
|
88
|
in
|
89
|
eval' t
|
90
|
|
91
|
|
92
|
let choose ?printer ?name var_get lst =
|
93
|
let rec choose_aux =
|
94
|
function
|
95
|
| (cond, vl) :: tl ->
|
96
|
if eval var_get cond then
|
97
|
vl
|
98
|
else
|
99
|
choose_aux tl
|
100
|
| [] ->
|
101
|
let str_lst =
|
102
|
if lst = [] then
|
103
|
s_ "<empty>"
|
104
|
else
|
105
|
String.concat
|
106
|
(s_ ", ")
|
107
|
(List.map
|
108
|
(fun (cond, vl) ->
|
109
|
match printer with
|
110
|
| Some p -> p vl
|
111
|
| None -> s_ "<no printer>")
|
112
|
lst)
|
113
|
in
|
114
|
match name with
|
115
|
| Some nm ->
|
116
|
failwith
|
117
|
(Printf.sprintf
|
118
|
(f_ "No result for the choice list '%s': %s")
|
119
|
nm str_lst)
|
120
|
| None ->
|
121
|
failwith
|
122
|
(Printf.sprintf
|
123
|
(f_ "No result for a choice list: %s")
|
124
|
str_lst)
|
125
|
in
|
126
|
choose_aux (List.rev lst)
|
127
|
|
128
|
|
129
|
end
|
130
|
|
131
|
|
132
|
# 132 "myocamlbuild.ml"
|
133
|
module BaseEnvLight = struct
|
134
|
(* # 22 "src/base/BaseEnvLight.ml" *)
|
135
|
|
136
|
|
137
|
module MapString = Map.Make(String)
|
138
|
|
139
|
|
140
|
type t = string MapString.t
|
141
|
|
142
|
|
143
|
let default_filename =
|
144
|
Filename.concat
|
145
|
(Sys.getcwd ())
|
146
|
"setup.data"
|
147
|
|
148
|
|
149
|
let load ?(allow_empty=false) ?(filename=default_filename) () =
|
150
|
if Sys.file_exists filename then
|
151
|
begin
|
152
|
let chn =
|
153
|
open_in_bin filename
|
154
|
in
|
155
|
let st =
|
156
|
Stream.of_channel chn
|
157
|
in
|
158
|
let line =
|
159
|
ref 1
|
160
|
in
|
161
|
let st_line =
|
162
|
Stream.from
|
163
|
(fun _ ->
|
164
|
try
|
165
|
match Stream.next st with
|
166
|
| '\n' -> incr line; Some '\n'
|
167
|
| c -> Some c
|
168
|
with Stream.Failure -> None)
|
169
|
in
|
170
|
let lexer =
|
171
|
Genlex.make_lexer ["="] st_line
|
172
|
in
|
173
|
let rec read_file mp =
|
174
|
match Stream.npeek 3 lexer with
|
175
|
| [Genlex.Ident nm; Genlex.Kwd "="; Genlex.String value] ->
|
176
|
Stream.junk lexer;
|
177
|
Stream.junk lexer;
|
178
|
Stream.junk lexer;
|
179
|
read_file (MapString.add nm value mp)
|
180
|
| [] ->
|
181
|
mp
|
182
|
| _ ->
|
183
|
failwith
|
184
|
(Printf.sprintf
|
185
|
"Malformed data file '%s' line %d"
|
186
|
filename !line)
|
187
|
in
|
188
|
let mp =
|
189
|
read_file MapString.empty
|
190
|
in
|
191
|
close_in chn;
|
192
|
mp
|
193
|
end
|
194
|
else if allow_empty then
|
195
|
begin
|
196
|
MapString.empty
|
197
|
end
|
198
|
else
|
199
|
begin
|
200
|
failwith
|
201
|
(Printf.sprintf
|
202
|
"Unable to load environment, the file '%s' doesn't exist."
|
203
|
filename)
|
204
|
end
|
205
|
|
206
|
|
207
|
let rec var_expand str env =
|
208
|
let buff =
|
209
|
Buffer.create ((String.length str) * 2)
|
210
|
in
|
211
|
Buffer.add_substitute
|
212
|
buff
|
213
|
(fun var ->
|
214
|
try
|
215
|
var_expand (MapString.find var env) env
|
216
|
with Not_found ->
|
217
|
failwith
|
218
|
(Printf.sprintf
|
219
|
"No variable %s defined when trying to expand %S."
|
220
|
var
|
221
|
str))
|
222
|
str;
|
223
|
Buffer.contents buff
|
224
|
|
225
|
|
226
|
let var_get name env =
|
227
|
var_expand (MapString.find name env) env
|
228
|
|
229
|
|
230
|
let var_choose lst env =
|
231
|
OASISExpr.choose
|
232
|
(fun nm -> var_get nm env)
|
233
|
lst
|
234
|
end
|
235
|
|
236
|
|
237
|
# 237 "myocamlbuild.ml"
|
238
|
module MyOCamlbuildFindlib = struct
|
239
|
(* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *)
|
240
|
|
241
|
|
242
|
(** OCamlbuild extension, copied from
|
243
|
* http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild
|
244
|
* by N. Pouillard and others
|
245
|
*
|
246
|
* Updated on 2009/02/28
|
247
|
*
|
248
|
* Modified by Sylvain Le Gall
|
249
|
*)
|
250
|
open Ocamlbuild_plugin
|
251
|
|
252
|
|
253
|
(* these functions are not really officially exported *)
|
254
|
let run_and_read =
|
255
|
Ocamlbuild_pack.My_unix.run_and_read
|
256
|
|
257
|
|
258
|
let blank_sep_strings =
|
259
|
Ocamlbuild_pack.Lexers.blank_sep_strings
|
260
|
|
261
|
|
262
|
let exec_from_conf exec =
|
263
|
let exec =
|
264
|
let env_filename = Pathname.basename BaseEnvLight.default_filename in
|
265
|
let env = BaseEnvLight.load ~filename:env_filename ~allow_empty:true () in
|
266
|
try
|
267
|
BaseEnvLight.var_get exec env
|
268
|
with Not_found ->
|
269
|
Printf.eprintf "W: Cannot get variable %s\n" exec;
|
270
|
exec
|
271
|
in
|
272
|
let fix_win32 str =
|
273
|
if Sys.os_type = "Win32" then begin
|
274
|
let buff = Buffer.create (String.length str) in
|
275
|
(* Adapt for windowsi, ocamlbuild + win32 has a hard time to handle '\\'.
|
276
|
*)
|
277
|
String.iter
|
278
|
(fun c -> Buffer.add_char buff (if c = '\\' then '/' else c))
|
279
|
str;
|
280
|
Buffer.contents buff
|
281
|
end else begin
|
282
|
str
|
283
|
end
|
284
|
in
|
285
|
fix_win32 exec
|
286
|
|
287
|
let split s ch =
|
288
|
let buf = Buffer.create 13 in
|
289
|
let x = ref [] in
|
290
|
let flush () =
|
291
|
x := (Buffer.contents buf) :: !x;
|
292
|
Buffer.clear buf
|
293
|
in
|
294
|
String.iter
|
295
|
(fun c ->
|
296
|
if c = ch then
|
297
|
flush ()
|
298
|
else
|
299
|
Buffer.add_char buf c)
|
300
|
s;
|
301
|
flush ();
|
302
|
List.rev !x
|
303
|
|
304
|
|
305
|
let split_nl s = split s '\n'
|
306
|
|
307
|
|
308
|
let before_space s =
|
309
|
try
|
310
|
String.before s (String.index s ' ')
|
311
|
with Not_found -> s
|
312
|
|
313
|
(* ocamlfind command *)
|
314
|
let ocamlfind x = S[Sh (exec_from_conf "ocamlfind"); x]
|
315
|
|
316
|
(* This lists all supported packages. *)
|
317
|
let find_packages () =
|
318
|
List.map before_space (split_nl & run_and_read "ocamlfind list")
|
319
|
|
320
|
|
321
|
(* Mock to list available syntaxes. *)
|
322
|
let find_syntaxes () = ["camlp4o"; "camlp4r"]
|
323
|
|
324
|
|
325
|
let well_known_syntax = [
|
326
|
"camlp4.quotations.o";
|
327
|
"camlp4.quotations.r";
|
328
|
"camlp4.exceptiontracer";
|
329
|
"camlp4.extend";
|
330
|
"camlp4.foldgenerator";
|
331
|
"camlp4.listcomprehension";
|
332
|
"camlp4.locationstripper";
|
333
|
"camlp4.macro";
|
334
|
"camlp4.mapgenerator";
|
335
|
"camlp4.metagenerator";
|
336
|
"camlp4.profiler";
|
337
|
"camlp4.tracer"
|
338
|
]
|
339
|
|
340
|
|
341
|
let dispatch =
|
342
|
function
|
343
|
| After_options ->
|
344
|
(* By using Before_options one let command line options have an higher
|
345
|
* priority on the contrary using After_options will guarantee to have
|
346
|
* the higher priority override default commands by ocamlfind ones *)
|
347
|
Options.ocamlc := ocamlfind & A"ocamlc";
|
348
|
Options.ocamlopt := ocamlfind & A"ocamlopt";
|
349
|
Options.ocamldep := ocamlfind & A"ocamldep";
|
350
|
Options.ocamldoc := ocamlfind & A"ocamldoc";
|
351
|
Options.ocamlmktop := ocamlfind & A"ocamlmktop";
|
352
|
Options.ocamlmklib := ocamlfind & A"ocamlmklib"
|
353
|
|
354
|
| After_rules ->
|
355
|
|
356
|
(* When one link an OCaml library/binary/package, one should use
|
357
|
* -linkpkg *)
|
358
|
flag ["ocaml"; "link"; "program"] & A"-linkpkg";
|
359
|
|
360
|
(* For each ocamlfind package one inject the -package option when
|
361
|
* compiling, computing dependencies, generating documentation and
|
362
|
* linking. *)
|
363
|
List.iter
|
364
|
begin fun pkg ->
|
365
|
let base_args = [A"-package"; A pkg] in
|
366
|
(* TODO: consider how to really choose camlp4o or camlp4r. *)
|
367
|
let syn_args = [A"-syntax"; A "camlp4o"] in
|
368
|
let args =
|
369
|
(* Heuristic to identify syntax extensions: whether they end in
|
370
|
".syntax"; some might not.
|
371
|
*)
|
372
|
if Filename.check_suffix pkg "syntax" ||
|
373
|
List.mem pkg well_known_syntax then
|
374
|
syn_args @ base_args
|
375
|
else
|
376
|
base_args
|
377
|
in
|
378
|
flag ["ocaml"; "compile"; "pkg_"^pkg] & S args;
|
379
|
flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S args;
|
380
|
flag ["ocaml"; "doc"; "pkg_"^pkg] & S args;
|
381
|
flag ["ocaml"; "link"; "pkg_"^pkg] & S base_args;
|
382
|
flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S args;
|
383
|
end
|
384
|
(find_packages ());
|
385
|
|
386
|
(* Like -package but for extensions syntax. Morover -syntax is useless
|
387
|
* when linking. *)
|
388
|
List.iter begin fun syntax ->
|
389
|
flag ["ocaml"; "compile"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
|
390
|
flag ["ocaml"; "ocamldep"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
|
391
|
flag ["ocaml"; "doc"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
|
392
|
flag ["ocaml"; "infer_interface"; "syntax_"^syntax] &
|
393
|
S[A"-syntax"; A syntax];
|
394
|
end (find_syntaxes ());
|
395
|
|
396
|
(* The default "thread" tag is not compatible with ocamlfind.
|
397
|
* Indeed, the default rules add the "threads.cma" or "threads.cmxa"
|
398
|
* options when using this tag. When using the "-linkpkg" option with
|
399
|
* ocamlfind, this module will then be added twice on the command line.
|
400
|
*
|
401
|
* To solve this, one approach is to add the "-thread" option when using
|
402
|
* the "threads" package using the previous plugin.
|
403
|
*)
|
404
|
flag ["ocaml"; "pkg_threads"; "compile"] (S[A "-thread"]);
|
405
|
flag ["ocaml"; "pkg_threads"; "doc"] (S[A "-I"; A "+threads"]);
|
406
|
flag ["ocaml"; "pkg_threads"; "link"] (S[A "-thread"]);
|
407
|
flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"]);
|
408
|
flag ["ocaml"; "package(threads)"; "compile"] (S[A "-thread"]);
|
409
|
flag ["ocaml"; "package(threads)"; "doc"] (S[A "-I"; A "+threads"]);
|
410
|
flag ["ocaml"; "package(threads)"; "link"] (S[A "-thread"]);
|
411
|
flag ["ocaml"; "package(threads)"; "infer_interface"] (S[A "-thread"]);
|
412
|
|
413
|
| _ ->
|
414
|
()
|
415
|
end
|
416
|
|
417
|
module MyOCamlbuildBase = struct
|
418
|
(* # 22 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *)
|
419
|
|
420
|
|
421
|
(** Base functions for writing myocamlbuild.ml
|
422
|
@author Sylvain Le Gall
|
423
|
*)
|
424
|
|
425
|
|
426
|
|
427
|
|
428
|
|
429
|
open Ocamlbuild_plugin
|
430
|
module OC = Ocamlbuild_pack.Ocaml_compiler
|
431
|
|
432
|
|
433
|
type dir = string
|
434
|
type file = string
|
435
|
type name = string
|
436
|
type tag = string
|
437
|
|
438
|
|
439
|
(* # 62 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *)
|
440
|
|
441
|
|
442
|
type t =
|
443
|
{
|
444
|
lib_ocaml: (name * dir list * string list) list;
|
445
|
lib_c: (name * dir * file list) list;
|
446
|
flags: (tag list * (spec OASISExpr.choices)) list;
|
447
|
(* Replace the 'dir: include' from _tags by a precise interdepends in
|
448
|
* directory.
|
449
|
*)
|
450
|
includes: (dir * dir list) list;
|
451
|
}
|
452
|
|
453
|
|
454
|
let env_filename =
|
455
|
Pathname.basename
|
456
|
BaseEnvLight.default_filename
|
457
|
|
458
|
|
459
|
let dispatch_combine lst =
|
460
|
fun e ->
|
461
|
List.iter
|
462
|
(fun dispatch -> dispatch e)
|
463
|
lst
|
464
|
|
465
|
|
466
|
let tag_libstubs nm =
|
467
|
"use_lib"^nm^"_stubs"
|
468
|
|
469
|
|
470
|
let nm_libstubs nm =
|
471
|
nm^"_stubs"
|
472
|
|
473
|
|
474
|
let dispatch t e =
|
475
|
let env =
|
476
|
BaseEnvLight.load
|
477
|
~filename:env_filename
|
478
|
~allow_empty:true
|
479
|
()
|
480
|
in
|
481
|
match e with
|
482
|
| Before_options ->
|
483
|
let no_trailing_dot s =
|
484
|
if String.length s >= 1 && s.[0] = '.' then
|
485
|
String.sub s 1 ((String.length s) - 1)
|
486
|
else
|
487
|
s
|
488
|
in
|
489
|
List.iter
|
490
|
(fun (opt, var) ->
|
491
|
try
|
492
|
opt := no_trailing_dot (BaseEnvLight.var_get var env)
|
493
|
with Not_found ->
|
494
|
Printf.eprintf "W: Cannot get variable %s\n" var)
|
495
|
[
|
496
|
Options.ext_obj, "ext_obj";
|
497
|
Options.ext_lib, "ext_lib";
|
498
|
Options.ext_dll, "ext_dll";
|
499
|
]
|
500
|
|
501
|
| After_rules ->
|
502
|
(* Declare OCaml libraries *)
|
503
|
List.iter
|
504
|
(function
|
505
|
| nm, [], intf_modules ->
|
506
|
ocaml_lib nm;
|
507
|
let cmis =
|
508
|
List.map (fun m -> (String.uncapitalize m) ^ ".cmi")
|
509
|
intf_modules in
|
510
|
dep ["ocaml"; "link"; "library"; "file:"^nm^".cma"] cmis
|
511
|
| nm, dir :: tl, intf_modules ->
|
512
|
ocaml_lib ~dir:dir (dir^"/"^nm);
|
513
|
List.iter
|
514
|
(fun dir ->
|
515
|
List.iter
|
516
|
(fun str ->
|
517
|
flag ["ocaml"; "use_"^nm; str] (S[A"-I"; P dir]))
|
518
|
["compile"; "infer_interface"; "doc"])
|
519
|
tl;
|
520
|
let cmis =
|
521
|
List.map (fun m -> dir^"/"^(String.uncapitalize m)^".cmi")
|
522
|
intf_modules in
|
523
|
dep ["ocaml"; "link"; "library"; "file:"^dir^"/"^nm^".cma"]
|
524
|
cmis)
|
525
|
t.lib_ocaml;
|
526
|
|
527
|
(* Declare directories dependencies, replace "include" in _tags. *)
|
528
|
List.iter
|
529
|
(fun (dir, include_dirs) ->
|
530
|
Pathname.define_context dir include_dirs)
|
531
|
t.includes;
|
532
|
|
533
|
(* Declare C libraries *)
|
534
|
List.iter
|
535
|
(fun (lib, dir, headers) ->
|
536
|
(* Handle C part of library *)
|
537
|
flag ["link"; "library"; "ocaml"; "byte"; tag_libstubs lib]
|
538
|
(S[A"-dllib"; A("-l"^(nm_libstubs lib)); A"-cclib";
|
539
|
A("-l"^(nm_libstubs lib))]);
|
540
|
|
541
|
flag ["link"; "library"; "ocaml"; "native"; tag_libstubs lib]
|
542
|
(S[A"-cclib"; A("-l"^(nm_libstubs lib))]);
|
543
|
|
544
|
flag ["link"; "program"; "ocaml"; "byte"; tag_libstubs lib]
|
545
|
(S[A"-dllib"; A("dll"^(nm_libstubs lib))]);
|
546
|
|
547
|
(* When ocaml link something that use the C library, then one
|
548
|
need that file to be up to date.
|
549
|
*)
|
550
|
dep ["link"; "ocaml"; "program"; tag_libstubs lib]
|
551
|
[dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)];
|
552
|
|
553
|
dep ["compile"; "ocaml"; "program"; tag_libstubs lib]
|
554
|
[dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)];
|
555
|
|
556
|
(* TODO: be more specific about what depends on headers *)
|
557
|
(* Depends on .h files *)
|
558
|
dep ["compile"; "c"]
|
559
|
headers;
|
560
|
|
561
|
(* Setup search path for lib *)
|
562
|
flag ["link"; "ocaml"; "use_"^lib]
|
563
|
(S[A"-I"; P(dir)]);
|
564
|
)
|
565
|
t.lib_c;
|
566
|
|
567
|
(* Add flags *)
|
568
|
List.iter
|
569
|
(fun (tags, cond_specs) ->
|
570
|
let spec = BaseEnvLight.var_choose cond_specs env in
|
571
|
let rec eval_specs =
|
572
|
function
|
573
|
| S lst -> S (List.map eval_specs lst)
|
574
|
| A str -> A (BaseEnvLight.var_expand str env)
|
575
|
| spec -> spec
|
576
|
in
|
577
|
flag tags & (eval_specs spec))
|
578
|
t.flags
|
579
|
| _ ->
|
580
|
()
|
581
|
|
582
|
|
583
|
let dispatch_default t =
|
584
|
dispatch_combine
|
585
|
[
|
586
|
dispatch t;
|
587
|
MyOCamlbuildFindlib.dispatch;
|
588
|
]
|
589
|
|
590
|
|
591
|
end
|
592
|
|
593
|
|
594
|
# 594 "myocamlbuild.ml"
|
595
|
open Ocamlbuild_plugin;;
|
596
|
let package_default =
|
597
|
{MyOCamlbuildBase.lib_ocaml = []; lib_c = []; flags = []; includes = []}
|
598
|
;;
|
599
|
|
600
|
let dispatch_default = MyOCamlbuildBase.dispatch_default package_default;;
|
601
|
|
602
|
# 603 "myocamlbuild.ml"
|
603
|
(* OASIS_STOP *)
|
604
|
Ocamlbuild_plugin.dispatch dispatch_default;;
|