171 lines
6.0 KiB
OCaml
171 lines
6.0 KiB
OCaml
(***********************************************************************)
|
|
(* ocamlbuild *)
|
|
(* *)
|
|
(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
|
|
(* *)
|
|
(* Copyright 2007 Institut National de Recherche en Informatique et *)
|
|
(* en Automatique. All rights reserved. This file is distributed *)
|
|
(* under the terms of the Q Public License version 1.0. *)
|
|
(* *)
|
|
(***********************************************************************)
|
|
|
|
|
|
(* Original author: Nicolas Pouillard *)
|
|
open My_std
|
|
open Format
|
|
open Log
|
|
open Pathname.Operators
|
|
open Tags.Operators
|
|
open Tools
|
|
open Flags
|
|
open Command;;
|
|
|
|
|
|
module S = Set.Make(String)
|
|
|
|
let flag_and_dep tags cmd_spec =
|
|
flag tags cmd_spec;
|
|
let ps = Command.fold_pathnames (fun p ps -> p :: ps) (Cmd cmd_spec) [] in
|
|
dep tags ps
|
|
|
|
let stdlib_dir = lazy begin
|
|
let ocamlc_where = !Options.build_dir / (Pathname.mk "ocamlc.where") in
|
|
let () = Command.execute ~quiet:true (Cmd(S[!Options.ocamlc; A"-where"; Sh">"; P ocamlc_where])) in
|
|
String.chomp (read_file ocamlc_where)
|
|
end
|
|
|
|
let pflag_and_dep tags ptag cmd_spec =
|
|
Param_tags.declare ptag
|
|
(fun param ->
|
|
flag_and_dep (Param_tags.make ptag param :: tags) (cmd_spec param))
|
|
|
|
let module_name_of_filename f = String.capitalize (Pathname.remove_extensions f)
|
|
let module_name_of_pathname x =
|
|
module_name_of_filename (Pathname.to_string (Pathname.basename x))
|
|
|
|
let ignore_stdlib x =
|
|
if !Options.nostdlib then false
|
|
else
|
|
let x' = !*stdlib_dir/((String.uncapitalize x)-.-"cmi") in
|
|
Pathname.exists x'
|
|
|
|
let non_dependencies = ref []
|
|
let non_dependency m1 m2 =
|
|
(* non_dependency was not supposed to accept pathnames without extension. *)
|
|
if String.length (Pathname.get_extensions m1) = 0 then
|
|
invalid_arg "non_dependency: no extension";
|
|
non_dependencies := (m1, m2) :: !non_dependencies
|
|
|
|
let path_importance path x =
|
|
if List.mem (path, x) !non_dependencies
|
|
|| (List.mem x !Options.ignore_list) then begin
|
|
let () = dprintf 3 "This module (%s) is ignored by %s" x path in
|
|
`ignored
|
|
end
|
|
else if ignore_stdlib x then `just_try else `mandatory
|
|
|
|
let expand_module include_dirs module_name exts =
|
|
let dirname = Pathname.dirname module_name in
|
|
let basename = Pathname.basename module_name in
|
|
let module_name_cap = dirname/(String.capitalize basename) in
|
|
let module_name_uncap = dirname/(String.uncapitalize basename) in
|
|
List.fold_right begin fun include_dir ->
|
|
List.fold_right begin fun ext acc ->
|
|
include_dir/(module_name_uncap-.-ext) ::
|
|
include_dir/(module_name_cap-.-ext) :: acc
|
|
end exts
|
|
end include_dirs []
|
|
|
|
let string_list_of_file file =
|
|
with_input_file file begin fun ic ->
|
|
Lexers.blank_sep_strings (Lexing.from_channel ic)
|
|
end
|
|
let print_path_list = Pathname.print_path_list
|
|
|
|
let ocaml_ppflags tags =
|
|
let flags = Flags.of_tags (tags++"ocaml"++"pp") in
|
|
let reduced = Command.reduce flags in
|
|
if reduced = N then N else S[A"-pp"; Quote reduced]
|
|
|
|
let ocaml_add_include_flag x acc =
|
|
if x = Pathname.current_dir_name then acc else A"-I" :: A x :: acc
|
|
|
|
let ocaml_include_flags path =
|
|
S (List.fold_right ocaml_add_include_flag (Pathname.include_dirs_of (Pathname.dirname path)) [])
|
|
|
|
let info_libraries = Hashtbl.create 103
|
|
|
|
let libraries = Hashtbl.create 103
|
|
let libraries_of m =
|
|
try Hashtbl.find libraries m with Not_found -> []
|
|
let use_lib m lib = Hashtbl.replace libraries m (lib :: libraries_of m)
|
|
|
|
let ocaml_lib ?(extern=false) ?(byte=true) ?(native=true) ?dir ?tag_name libpath =
|
|
let add_dir x =
|
|
match dir with
|
|
| Some dir -> S[A"-I"; P dir; x]
|
|
| None -> x
|
|
in
|
|
let tag_name =
|
|
match tag_name with
|
|
| Some x -> x
|
|
| None -> "use_" ^ Pathname.basename libpath
|
|
in
|
|
let flag_and_dep tags lib =
|
|
flag tags (add_dir (A lib));
|
|
if not extern then dep tags [lib] (* cannot happen? *)
|
|
in
|
|
Hashtbl.replace info_libraries tag_name (libpath, extern);
|
|
if extern then begin
|
|
if byte then
|
|
flag_and_dep ["ocaml"; tag_name; "link"; "byte"] (libpath^".cma");
|
|
if native then
|
|
flag_and_dep ["ocaml"; tag_name; "link"; "native"] (libpath^".cmxa");
|
|
end else begin
|
|
if not byte && not native then
|
|
invalid_arg "ocaml_lib: ~byte:false or ~native:false only works with ~extern:true";
|
|
end;
|
|
match dir with
|
|
| None -> ()
|
|
| Some dir ->
|
|
List.iter
|
|
(fun x -> flag ["ocaml"; tag_name; x] (S[A"-I"; P dir]))
|
|
["compile"; "doc"; "infer_interface"]
|
|
|
|
let cmi_of = Pathname.update_extensions "cmi"
|
|
|
|
exception Ocamldep_error of string
|
|
|
|
let read_path_dependencies =
|
|
let path_dependencies = Hashtbl.create 103 in
|
|
let read path =
|
|
let module_name = module_name_of_pathname path in
|
|
let depends = path-.-"depends" in
|
|
with_input_file depends begin fun ic ->
|
|
let ocamldep_output =
|
|
try Lexers.ocamldep_output (Lexing.from_channel ic)
|
|
with Lexers.Error msg -> raise (Ocamldep_error(Printf.sprintf "Ocamldep.ocamldep: bad output (%s)" msg)) in
|
|
let deps =
|
|
List.fold_right begin fun (path, deps) acc ->
|
|
let module_name' = module_name_of_pathname path in
|
|
if module_name' = module_name
|
|
then List.union deps acc
|
|
else raise (Ocamldep_error(Printf.sprintf "Ocamldep.ocamldep: multiple files in ocamldep output (%s not expected)" path))
|
|
end ocamldep_output [] in
|
|
let deps =
|
|
if !Options.nostdlib && not (Tags.mem "nopervasives" (tags_of_pathname path)) then
|
|
"Pervasives" :: deps
|
|
else deps in
|
|
let deps' = List.fold_right begin fun dep acc ->
|
|
match path_importance path dep with
|
|
| `ignored -> acc
|
|
| (`just_try | `mandatory) as importance -> (importance, dep) :: acc
|
|
end deps [] in
|
|
Hashtbl.replace path_dependencies path
|
|
(List.union (try Hashtbl.find path_dependencies path with Not_found -> []) deps');
|
|
deps'
|
|
end
|
|
in read
|
|
|
|
let path_dependencies_of = memo read_path_dependencies
|