myocamlbuild.ml 17 KB

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