Merge pull request #268 from janestreet/new-alias-semantic
Sort out recursive/non-recursive aliases
This commit is contained in:
commit
a63276f5b3
13
CHANGES.md
13
CHANGES.md
|
@ -1,3 +1,16 @@
|
||||||
|
next
|
||||||
|
----
|
||||||
|
|
||||||
|
- Change the semantic of aliases: there are no longer aliases that are
|
||||||
|
recursive such as `install` or `runtest`. All aliases are
|
||||||
|
non-recursive. However, when requesting an alias from the command
|
||||||
|
line, this request the construction of the alias in the specified
|
||||||
|
directory and all its children recursively. This allows users to get
|
||||||
|
the same behavior as previous recursive aliases for their own
|
||||||
|
aliases, such as `example`. Inside jbuild files, one can use `(deps
|
||||||
|
(... (alias_rec xxx) ...))` to get the same behavior as on the
|
||||||
|
command line.
|
||||||
|
|
||||||
1.0+beta14 (11/10/2017)
|
1.0+beta14 (11/10/2017)
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
|
54
bin/main.ml
54
bin/main.ml
|
@ -70,8 +70,23 @@ module Main = struct
|
||||||
?filter_out_optional_stanzas_with_missing_deps ()
|
?filter_out_optional_stanzas_with_missing_deps ()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
type target =
|
||||||
|
| File of Path.t
|
||||||
|
| Alias_rec of Alias.t
|
||||||
|
|
||||||
|
let request_of_targets (setup : Main.setup) targets =
|
||||||
|
let open Build.O in
|
||||||
|
List.fold_left targets ~init:(Build.return ()) ~f:(fun acc target ->
|
||||||
|
acc >>>
|
||||||
|
match target with
|
||||||
|
| File path -> Build.path path
|
||||||
|
| Alias_rec alias ->
|
||||||
|
Alias.dep_rec ~loc:(Loc.in_file "<command-line>")
|
||||||
|
~file_tree:setup.file_tree alias)
|
||||||
|
|
||||||
let do_build (setup : Main.setup) targets =
|
let do_build (setup : Main.setup) targets =
|
||||||
Build_system.do_build_exn setup.build_system targets
|
Build_system.do_build_exn setup.build_system
|
||||||
|
~request:(request_of_targets setup targets)
|
||||||
|
|
||||||
let find_root () =
|
let find_root () =
|
||||||
let cwd = Sys.getcwd () in
|
let cwd = Sys.getcwd () in
|
||||||
|
@ -338,10 +353,6 @@ let resolve_package_install setup pkg =
|
||||||
| Error () ->
|
| Error () ->
|
||||||
die "Unknown package %s!%s" pkg (hint pkg (String_map.keys setup.packages))
|
die "Unknown package %s!%s" pkg (hint pkg (String_map.keys setup.packages))
|
||||||
|
|
||||||
type target =
|
|
||||||
| File of Path.t
|
|
||||||
| Alias of Path.t * Alias.t
|
|
||||||
|
|
||||||
let target_hint (setup : Main.setup) path =
|
let target_hint (setup : Main.setup) path =
|
||||||
assert (Path.is_local path);
|
assert (Path.is_local path);
|
||||||
let sub_dir = Path.parent path in
|
let sub_dir = Path.parent path in
|
||||||
|
@ -379,9 +390,7 @@ let resolve_targets ~log common (setup : Main.setup) user_targets =
|
||||||
if Path.is_root path then
|
if Path.is_root path then
|
||||||
die "@@ on the command line must be followed by a valid alias name"
|
die "@@ on the command line must be followed by a valid alias name"
|
||||||
else
|
else
|
||||||
let dir = Path.parent path in
|
[Alias_rec (Alias.of_path path)]
|
||||||
let name = Path.basename path in
|
|
||||||
[Alias (path, Alias.make ~dir name)]
|
|
||||||
else
|
else
|
||||||
let path = Path.relative Path.root (prefix_target common s) in
|
let path = Path.relative Path.root (prefix_target common s) in
|
||||||
let can't_build path =
|
let can't_build path =
|
||||||
|
@ -420,13 +429,13 @@ let resolve_targets ~log common (setup : Main.setup) user_targets =
|
||||||
List.iter targets ~f:(function
|
List.iter targets ~f:(function
|
||||||
| File path ->
|
| File path ->
|
||||||
Log.info log @@ "- " ^ (Path.to_string path)
|
Log.info log @@ "- " ^ (Path.to_string path)
|
||||||
| Alias (path, _) ->
|
| Alias_rec alias ->
|
||||||
Log.info log @@ "- alias " ^ (Path.to_string path));
|
let path = Alias.fully_qualified_name alias in
|
||||||
|
Log.info log @@ "- recursive alias " ^
|
||||||
|
(Path.to_string_maybe_quoted path));
|
||||||
flush stdout;
|
flush stdout;
|
||||||
end;
|
end;
|
||||||
List.map targets ~f:(function
|
targets
|
||||||
| File path -> path
|
|
||||||
| Alias (_, alias) -> Alias.file alias)
|
|
||||||
|
|
||||||
let build_targets =
|
let build_targets =
|
||||||
let doc = "Build the given targets, or all installable targets if none are given." in
|
let doc = "Build the given targets, or all installable targets if none are given." in
|
||||||
|
@ -471,7 +480,7 @@ let runtest =
|
||||||
let targets =
|
let targets =
|
||||||
List.map dirs ~f:(fun dir ->
|
List.map dirs ~f:(fun dir ->
|
||||||
let dir = Path.(relative root) (prefix_target common dir) in
|
let dir = Path.(relative root) (prefix_target common dir) in
|
||||||
Alias.file (Alias.runtest ~dir))
|
Alias_rec (Alias.runtest ~dir))
|
||||||
in
|
in
|
||||||
do_build setup targets) in
|
do_build setup targets) in
|
||||||
( Term.(const go
|
( Term.(const go
|
||||||
|
@ -522,9 +531,10 @@ let external_lib_deps =
|
||||||
(Main.setup ~log common ~filter_out_optional_stanzas_with_missing_deps:false
|
(Main.setup ~log common ~filter_out_optional_stanzas_with_missing_deps:false
|
||||||
>>= fun setup ->
|
>>= fun setup ->
|
||||||
let targets = resolve_targets ~log common setup targets in
|
let targets = resolve_targets ~log common setup targets in
|
||||||
|
let request = request_of_targets setup targets in
|
||||||
let failure =
|
let failure =
|
||||||
String_map.fold ~init:false
|
String_map.fold ~init:false
|
||||||
(Build_system.all_lib_deps_by_context setup.build_system targets)
|
(Build_system.all_lib_deps_by_context setup.build_system ~request)
|
||||||
~f:(fun ~key:context_name ~data:lib_deps acc ->
|
~f:(fun ~key:context_name ~data:lib_deps acc ->
|
||||||
let internals =
|
let internals =
|
||||||
Jbuild.Stanzas.lib_names
|
Jbuild.Stanzas.lib_names
|
||||||
|
@ -623,12 +633,12 @@ let rules =
|
||||||
Future.Scheduler.go ~log
|
Future.Scheduler.go ~log
|
||||||
(Main.setup ~log common ~filter_out_optional_stanzas_with_missing_deps:false
|
(Main.setup ~log common ~filter_out_optional_stanzas_with_missing_deps:false
|
||||||
>>= fun setup ->
|
>>= fun setup ->
|
||||||
let targets =
|
let request =
|
||||||
match targets with
|
match targets with
|
||||||
| [] -> Build_system.all_targets setup.build_system
|
| [] -> Build.paths (Build_system.all_targets setup.build_system)
|
||||||
| _ -> resolve_targets ~log common setup targets
|
| _ -> resolve_targets ~log common setup targets |> request_of_targets setup
|
||||||
in
|
in
|
||||||
Build_system.build_rules setup.build_system targets ~recursive >>= fun rules ->
|
Build_system.build_rules setup.build_system ~request ~recursive >>= fun rules ->
|
||||||
let print oc =
|
let print oc =
|
||||||
let ppf = Format.formatter_of_out_channel oc in
|
let ppf = Format.formatter_of_out_channel oc in
|
||||||
Sexp.prepare_formatter ppf;
|
Sexp.prepare_formatter ppf;
|
||||||
|
@ -918,10 +928,10 @@ let utop =
|
||||||
let target =
|
let target =
|
||||||
match resolve_targets ~log common setup [utop_target] with
|
match resolve_targets ~log common setup [utop_target] with
|
||||||
| [] -> die "no libraries defined in %s" dir
|
| [] -> die "no libraries defined in %s" dir
|
||||||
| [target] -> target
|
| [File target] -> target
|
||||||
| _::_::_ -> assert false
|
| [Alias_rec _] | _::_::_ -> assert false
|
||||||
in
|
in
|
||||||
do_build setup [target] >>| fun () ->
|
do_build setup [File target] >>| fun () ->
|
||||||
(setup.build_system, context, Path.to_string target)
|
(setup.build_system, context, Path.to_string target)
|
||||||
) |> Future.Scheduler.go ~log in
|
) |> Future.Scheduler.go ~log in
|
||||||
Build_system.dump_trace build_system;
|
Build_system.dump_trace build_system;
|
||||||
|
|
|
@ -843,6 +843,10 @@ syntax:
|
||||||
- ``(file <filename>)`` or simply ``<filename>``: depend on this file
|
- ``(file <filename>)`` or simply ``<filename>``: depend on this file
|
||||||
- ``(alias <alias-name>)``: depend on the construction of this alias, for
|
- ``(alias <alias-name>)``: depend on the construction of this alias, for
|
||||||
instance: ``(alias src/runtest)``
|
instance: ``(alias src/runtest)``
|
||||||
|
- ``(alias_rec <alias-name>)``: depend on the construction of this
|
||||||
|
alias recursively in all children directories wherever it is
|
||||||
|
defined. For instance: ``(alias_rec src/runtest)`` might depend on
|
||||||
|
``(alias src/runtest)``, ``(alias src/foo/bar/runtest)``, ...
|
||||||
- ``(glob_files <glob>)``: depend on all files matched by ``<glob>``, see the
|
- ``(glob_files <glob>)``: depend on all files matched by ``<glob>``, see the
|
||||||
:ref:`glob <glob>` for details
|
:ref:`glob <glob>` for details
|
||||||
- ``(files_recursively_in <dir>)``: depend on all files in the subtree with root
|
- ``(files_recursively_in <dir>)``: depend on all files in the subtree with root
|
||||||
|
|
|
@ -43,11 +43,12 @@ Terminology
|
||||||
- **build context root**: the root of a build context named ``foo`` is
|
- **build context root**: the root of a build context named ``foo`` is
|
||||||
``<root>/_build/<foo>``
|
``<root>/_build/<foo>``
|
||||||
|
|
||||||
- **alias**: an alias is a build target that doesn't produce any file
|
- **alias**: an alias is a build target that doesn't produce any file
|
||||||
and has configurable dependencies. Alias are per-directory and some
|
and has configurable dependencies. Aliases are
|
||||||
are recursive; asking an alias to be built in a given directory will
|
per-directory. However, on the command line, asking for an alias to
|
||||||
trigger the construction of the alias in all children directories
|
be built in a given directory will trigger the construction of the
|
||||||
recursively. The most interesting ones are:
|
alias in all children directories recursively. Jbuilder defines the
|
||||||
|
following standard aliases:
|
||||||
|
|
||||||
- ``runtest`` which runs user defined tests
|
- ``runtest`` which runs user defined tests
|
||||||
- ``install`` which depends on everything that should be installed
|
- ``install`` which depends on everything that should be installed
|
||||||
|
|
|
@ -125,8 +125,9 @@ Aliases
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Targets starting with a ``@`` are interpreted as aliases. For instance
|
Targets starting with a ``@`` are interpreted as aliases. For instance
|
||||||
``@src/runtest`` means the alias ``src/runtest``. If you want to refer
|
``@src/runtest`` means the alias ``runtest`` in all descendant of
|
||||||
to a target starting with a ``@``, simply write: ``./@foo``.
|
``src`` where it is defined. If you want to refer to a target starting
|
||||||
|
with a ``@``, simply write: ``./@foo``.
|
||||||
|
|
||||||
Note that an alias not pointing to the ``_build`` directory always
|
Note that an alias not pointing to the ``_build`` directory always
|
||||||
depends on all the corresponding aliases in build contexts.
|
depends on all the corresponding aliases in build contexts.
|
||||||
|
|
77
src/alias.ml
77
src/alias.ml
|
@ -3,12 +3,14 @@ open! Import
|
||||||
(** Fully qualified name *)
|
(** Fully qualified name *)
|
||||||
module Fq_name : sig
|
module Fq_name : sig
|
||||||
type t
|
type t
|
||||||
|
val pp : Format.formatter -> t -> unit
|
||||||
val make : Path.t -> t
|
val make : Path.t -> t
|
||||||
val path : t -> Path.t
|
val path : t -> Path.t
|
||||||
end = struct
|
end = struct
|
||||||
type t = Path.t
|
type t = Path.t
|
||||||
let make t = t
|
let make t = t
|
||||||
let path t = t
|
let path t = t
|
||||||
|
let pp = Path.pp
|
||||||
end
|
end
|
||||||
|
|
||||||
type t =
|
type t =
|
||||||
|
@ -16,6 +18,10 @@ type t =
|
||||||
; file : Path.t
|
; file : Path.t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pp fmt t =
|
||||||
|
Format.fprintf fmt "@[<2>{ name@ =@ %a@ ;@ file@ =@ %a }@]"
|
||||||
|
Path.pp (Fq_name.path t.name) Path.pp t.file
|
||||||
|
|
||||||
let aliases_path = Path.(relative root) "_build/.aliases"
|
let aliases_path = Path.(relative root) "_build/.aliases"
|
||||||
|
|
||||||
let suffix = "-" ^ String.make 32 '0'
|
let suffix = "-" ^ String.make 32 '0'
|
||||||
|
@ -32,12 +38,43 @@ let of_path path =
|
||||||
let name t = Path.basename (Fq_name.path t.name)
|
let name t = Path.basename (Fq_name.path t.name)
|
||||||
let dir t = Path.parent (Fq_name.path t.name)
|
let dir t = Path.parent (Fq_name.path t.name)
|
||||||
|
|
||||||
|
let fully_qualified_name t = Fq_name.path t.name
|
||||||
|
|
||||||
let make name ~dir =
|
let make name ~dir =
|
||||||
assert (not (String.contains name '/'));
|
assert (not (String.contains name '/'));
|
||||||
of_path (Path.relative dir name)
|
of_path (Path.relative dir name)
|
||||||
|
|
||||||
let dep t = Build.path t.file
|
let dep t = Build.path t.file
|
||||||
|
|
||||||
|
let is_standard = function
|
||||||
|
| "runtest" | "install" | "doc" -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let dep_rec ~loc ~file_tree t =
|
||||||
|
let path = Path.parent (Fq_name.path t.name) |> Path.drop_build_context in
|
||||||
|
let name = Path.basename (Fq_name.path t.name) in
|
||||||
|
match File_tree.find_dir file_tree path with
|
||||||
|
| None -> Build.fail { fail = fun () ->
|
||||||
|
Loc.fail loc "Don't know about directory %s!" (Path.to_string_maybe_quoted path) }
|
||||||
|
| Some dir ->
|
||||||
|
let open Build.O in
|
||||||
|
File_tree.Dir.fold dir ~traverse_ignored_dirs:false ~init:(Build.return true)
|
||||||
|
~f:(fun dir acc ->
|
||||||
|
let path = File_tree.Dir.path dir in
|
||||||
|
let t = of_path (Path.relative path name) in
|
||||||
|
acc
|
||||||
|
>>>
|
||||||
|
Build.if_file_exists t.file
|
||||||
|
~then_:(Build.path t.file
|
||||||
|
>>^
|
||||||
|
fun _ -> false)
|
||||||
|
~else_:(Build.arr (fun x -> x)))
|
||||||
|
>>^ fun is_empty ->
|
||||||
|
if is_empty && not (is_standard name) then
|
||||||
|
Loc.fail loc "This alias is empty.\n\
|
||||||
|
Alias %S is not defined in %s or any of its descendants."
|
||||||
|
name (Path.to_string_maybe_quoted path)
|
||||||
|
|
||||||
let file t = t.file
|
let file t = t.file
|
||||||
|
|
||||||
let file_with_digest_suffix t ~digest =
|
let file_with_digest_suffix t ~digest =
|
||||||
|
@ -77,20 +114,29 @@ let runtest = make "runtest"
|
||||||
let install = make "install"
|
let install = make "install"
|
||||||
let doc = make "doc"
|
let doc = make "doc"
|
||||||
|
|
||||||
let recursive_aliases =
|
|
||||||
[ default
|
|
||||||
; runtest
|
|
||||||
; install
|
|
||||||
; doc
|
|
||||||
]
|
|
||||||
|
|
||||||
module Store = struct
|
module Store = struct
|
||||||
type entry =
|
type entry =
|
||||||
{ alias : t
|
{ alias : t
|
||||||
; mutable deps : Path.Set.t
|
; mutable deps : Path.Set.t
|
||||||
}
|
}
|
||||||
|
let pp_entry fmt entry =
|
||||||
|
let pp_deps fmt deps =
|
||||||
|
Format.pp_print_list Path.pp fmt (Path.Set.elements deps) in
|
||||||
|
Format.fprintf fmt "@[<2>{@ alias@ =@ %a@ ;@ deps@ = (%a)@ }@]"
|
||||||
|
pp entry.alias pp_deps entry.deps
|
||||||
|
|
||||||
type t = (Fq_name.t, entry) Hashtbl.t
|
type t = (Fq_name.t, entry) Hashtbl.t
|
||||||
|
|
||||||
|
let pp fmt (t : t) =
|
||||||
|
let bindings = Hashtbl.fold ~init:[] ~f:(fun ~key ~data acc ->
|
||||||
|
(key, data)::acc
|
||||||
|
) t in
|
||||||
|
let pp_bindings fmt b =
|
||||||
|
Format.pp_print_list (fun fmt (k, v) ->
|
||||||
|
Format.fprintf fmt "@[<2>(%a@ %a)@]" Fq_name.pp k pp_entry v
|
||||||
|
) fmt b in
|
||||||
|
Format.fprintf fmt "Store.t@ @[@<2>(%a)@]" pp_bindings bindings
|
||||||
|
|
||||||
let create () = Hashtbl.create 1024
|
let create () = Hashtbl.create 1024
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -104,22 +150,7 @@ let add_deps store t deps =
|
||||||
}
|
}
|
||||||
| Some e -> e.deps <- Path.Set.union deps e.deps
|
| Some e -> e.deps <- Path.Set.union deps e.deps
|
||||||
|
|
||||||
type tree = Node of Path.t * tree list
|
let rules store =
|
||||||
|
|
||||||
let rec setup_rec_alias store ~make_alias ~prefix ~tree:(Node (dir, children)) =
|
|
||||||
let alias = make_alias ~dir:(Path.append prefix dir) in
|
|
||||||
add_deps store alias (List.map children ~f:(fun child ->
|
|
||||||
setup_rec_alias store ~make_alias ~prefix ~tree:child));
|
|
||||||
alias.file
|
|
||||||
|
|
||||||
let setup_rec_aliases store ~prefix ~tree =
|
|
||||||
List.iter recursive_aliases ~f:(fun make_alias ->
|
|
||||||
ignore (setup_rec_alias store ~make_alias ~prefix ~tree : Path.t))
|
|
||||||
|
|
||||||
let rules store ~prefixes ~tree =
|
|
||||||
List.iter prefixes ~f:(fun prefix ->
|
|
||||||
setup_rec_aliases store ~prefix ~tree);
|
|
||||||
|
|
||||||
(* For each alias @_build/blah/../x, add a dependency: @../x --> @_build/blah/../x *)
|
(* For each alias @_build/blah/../x, add a dependency: @../x --> @_build/blah/../x *)
|
||||||
Hashtbl.fold store ~init:[] ~f:(fun ~key:_ ~data:{ Store. alias; _ } acc ->
|
Hashtbl.fold store ~init:[] ~f:(fun ~key:_ ~data:{ Store. alias; _ } acc ->
|
||||||
match Path.extract_build_context (Fq_name.path alias.name) with
|
match Path.extract_build_context (Fq_name.path alias.name) with
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
|
open Import
|
||||||
|
|
||||||
type t
|
type t
|
||||||
|
|
||||||
|
val pp : t Fmt.t
|
||||||
|
|
||||||
val make : string -> dir:Path.t -> t
|
val make : string -> dir:Path.t -> t
|
||||||
|
|
||||||
|
val of_path : Path.t -> t
|
||||||
|
|
||||||
(** The following always holds:
|
(** The following always holds:
|
||||||
|
|
||||||
{[
|
{[
|
||||||
|
@ -11,6 +17,8 @@ val make : string -> dir:Path.t -> t
|
||||||
val name : t -> string
|
val name : t -> string
|
||||||
val dir : t -> Path.t
|
val dir : t -> Path.t
|
||||||
|
|
||||||
|
val fully_qualified_name : t -> Path.t
|
||||||
|
|
||||||
val default : dir:Path.t -> t
|
val default : dir:Path.t -> t
|
||||||
val runtest : dir:Path.t -> t
|
val runtest : dir:Path.t -> t
|
||||||
val install : dir:Path.t -> t
|
val install : dir:Path.t -> t
|
||||||
|
@ -18,6 +26,10 @@ val doc : dir:Path.t -> t
|
||||||
|
|
||||||
val dep : t -> ('a, 'a) Build.t
|
val dep : t -> ('a, 'a) Build.t
|
||||||
|
|
||||||
|
(** Implements [(alias_rec ...)] in dependency specification and
|
||||||
|
[@alias] on the command line. *)
|
||||||
|
val dep_rec : loc:Loc.t -> file_tree:File_tree.t -> t -> (unit, unit) Build.t
|
||||||
|
|
||||||
(** File that represent the alias in the filesystem. It is a file under
|
(** File that represent the alias in the filesystem. It is a file under
|
||||||
[_build/.aliases]. *)
|
[_build/.aliases]. *)
|
||||||
val file : t -> Path.t
|
val file : t -> Path.t
|
||||||
|
@ -43,15 +55,12 @@ val name_of_file : Path.t -> string option
|
||||||
|
|
||||||
module Store : sig
|
module Store : sig
|
||||||
type t
|
type t
|
||||||
|
|
||||||
|
val pp : t Fmt.t
|
||||||
|
|
||||||
val create : unit -> t
|
val create : unit -> t
|
||||||
end
|
end
|
||||||
|
|
||||||
val add_deps : Store.t -> t -> Path.t list -> unit
|
val add_deps : Store.t -> t -> Path.t list -> unit
|
||||||
|
|
||||||
type tree = Node of Path.t * tree list
|
val rules : Store.t -> Build_interpret.Rule.t list
|
||||||
|
|
||||||
val rules
|
|
||||||
: Store.t
|
|
||||||
-> prefixes:Path.t list
|
|
||||||
-> tree:tree
|
|
||||||
-> Build_interpret.Rule.t list
|
|
||||||
|
|
|
@ -125,6 +125,7 @@ type t =
|
||||||
[(deps (filename + contents), targets (filename only), action)] *)
|
[(deps (filename + contents), targets (filename only), action)] *)
|
||||||
trace : (Path.t, Digest.t) Hashtbl.t
|
trace : (Path.t, Digest.t) Hashtbl.t
|
||||||
; mutable local_mkdirs : Path.Local.Set.t
|
; mutable local_mkdirs : Path.Local.Set.t
|
||||||
|
; all_targets_by_dir : Pset.t Pmap.t Lazy.t
|
||||||
}
|
}
|
||||||
|
|
||||||
let all_targets t = Hashtbl.fold t.files ~init:[] ~f:(fun ~key ~data:_ acc -> key :: acc)
|
let all_targets t = Hashtbl.fold t.files ~init:[] ~f:(fun ~key ~data:_ acc -> key :: acc)
|
||||||
|
@ -304,6 +305,9 @@ module Build_exec = struct
|
||||||
let dyn_deps = ref Pset.empty in
|
let dyn_deps = ref Pset.empty in
|
||||||
let action = exec dyn_deps (Build.repr t) x in
|
let action = exec dyn_deps (Build.repr t) x in
|
||||||
(action, !dyn_deps)
|
(action, !dyn_deps)
|
||||||
|
|
||||||
|
let exec_nop bs t x =
|
||||||
|
snd (exec bs (Build.O.(>>^) t (fun () -> Action.Progn [])) x)
|
||||||
end
|
end
|
||||||
|
|
||||||
(* This variable is filled during the creation of the build system. Once the build system
|
(* This variable is filled during the creation of the build system. Once the build system
|
||||||
|
@ -603,14 +607,14 @@ let dump_trace t = Trace.dump t.trace
|
||||||
|
|
||||||
let create ~contexts ~file_tree ~rules =
|
let create ~contexts ~file_tree ~rules =
|
||||||
let all_source_files =
|
let all_source_files =
|
||||||
File_tree.fold file_tree ~init:Pset.empty ~f:(fun dir acc ->
|
File_tree.fold file_tree ~init:Pset.empty ~traverse_ignored_dirs:true
|
||||||
let path = File_tree.Dir.path dir in
|
~f:(fun dir acc ->
|
||||||
Cont
|
let path = File_tree.Dir.path dir in
|
||||||
(Pset.union acc
|
Pset.union acc
|
||||||
(File_tree.Dir.files dir
|
(File_tree.Dir.files dir
|
||||||
|> String_set.elements
|
|> String_set.elements
|
||||||
|> List.map ~f:(Path.relative path)
|
|> List.map ~f:(Path.relative path)
|
||||||
|> Pset.of_list)))
|
|> Pset.of_list))
|
||||||
in
|
in
|
||||||
let all_copy_targets =
|
let all_copy_targets =
|
||||||
List.fold_left contexts ~init:Pset.empty ~f:(fun acc (ctx : Context.t) ->
|
List.fold_left contexts ~init:Pset.empty ~f:(fun acc (ctx : Context.t) ->
|
||||||
|
@ -638,6 +642,7 @@ let create ~contexts ~file_tree ~rules =
|
||||||
; files = Hashtbl.create 1024
|
; files = Hashtbl.create 1024
|
||||||
; trace = Trace.load ()
|
; trace = Trace.load ()
|
||||||
; local_mkdirs = Path.Local.Set.empty
|
; local_mkdirs = Path.Local.Set.empty
|
||||||
|
; all_targets_by_dir
|
||||||
} in
|
} in
|
||||||
List.iter rules ~f:(compile_rule t ~all_targets_by_dir ~copy_source:false);
|
List.iter rules ~f:(compile_rule t ~all_targets_by_dir ~copy_source:false);
|
||||||
setup_copy_rules t ~all_targets_by_dir
|
setup_copy_rules t ~all_targets_by_dir
|
||||||
|
@ -717,13 +722,34 @@ let remove_old_artifacts t =
|
||||||
walk (Config.local_install_dir ~context:ctx.name);
|
walk (Config.local_install_dir ~context:ctx.name);
|
||||||
)
|
)
|
||||||
|
|
||||||
let do_build_exn t targets =
|
let eval_request t ~request ~process_target =
|
||||||
remove_old_artifacts t;
|
let { Build_interpret.Static_deps.
|
||||||
all_unit (List.map targets ~f:(fun fn -> wait_for_file t fn ~targeting:fn))
|
rule_deps
|
||||||
|
; action_deps = static_deps
|
||||||
|
} = Build_interpret.static_deps request ~all_targets_by_dir:t.all_targets_by_dir
|
||||||
|
in
|
||||||
|
|
||||||
let do_build t targets =
|
let process_targets ts =
|
||||||
|
Future.all_unit (List.map (Pset.elements ts) ~f:process_target)
|
||||||
|
in
|
||||||
|
|
||||||
|
Future.both
|
||||||
|
(process_targets static_deps)
|
||||||
|
(Future.all_unit (List.map (Pset.elements rule_deps) ~f:(fun fn ->
|
||||||
|
wait_for_file t fn ~targeting:fn))
|
||||||
|
>>= fun () ->
|
||||||
|
let dyn_deps = Build_exec.exec_nop t request () in
|
||||||
|
process_targets (Pset.diff dyn_deps static_deps))
|
||||||
|
>>| fun ((), ()) -> ()
|
||||||
|
|
||||||
|
let do_build_exn t ~request =
|
||||||
|
remove_old_artifacts t;
|
||||||
|
eval_request t ~request ~process_target:(fun fn ->
|
||||||
|
wait_for_file t fn ~targeting:fn)
|
||||||
|
|
||||||
|
let do_build t ~request =
|
||||||
try
|
try
|
||||||
Ok (do_build_exn t targets)
|
Ok (do_build_exn t ~request)
|
||||||
with Build_error.E e ->
|
with Build_error.E e ->
|
||||||
Error e
|
Error e
|
||||||
|
|
||||||
|
@ -760,7 +786,16 @@ let rules_for_targets t targets =
|
||||||
Path.to_string (Pset.choose rule.Internal_rule.targets))
|
Path.to_string (Pset.choose rule.Internal_rule.targets))
|
||||||
|> String.concat ~sep:"\n-> ")
|
|> String.concat ~sep:"\n-> ")
|
||||||
|
|
||||||
let all_lib_deps t targets =
|
let static_deps_of_request t request =
|
||||||
|
let { Build_interpret.Static_deps.
|
||||||
|
rule_deps
|
||||||
|
; action_deps
|
||||||
|
} = Build_interpret.static_deps request ~all_targets_by_dir:t.all_targets_by_dir
|
||||||
|
in
|
||||||
|
Pset.elements (Pset.union rule_deps action_deps)
|
||||||
|
|
||||||
|
let all_lib_deps t ~request =
|
||||||
|
let targets = static_deps_of_request t request in
|
||||||
List.fold_left (rules_for_targets t targets) ~init:Pmap.empty
|
List.fold_left (rules_for_targets t targets) ~init:Pmap.empty
|
||||||
~f:(fun acc rule ->
|
~f:(fun acc rule ->
|
||||||
let lib_deps = Build_interpret.lib_deps rule.Internal_rule.build in
|
let lib_deps = Build_interpret.lib_deps rule.Internal_rule.build in
|
||||||
|
@ -771,7 +806,8 @@ let all_lib_deps t targets =
|
||||||
| None, Some b -> Some b
|
| None, Some b -> Some b
|
||||||
| Some a, Some b -> Some (Build.merge_lib_deps a b)))
|
| Some a, Some b -> Some (Build.merge_lib_deps a b)))
|
||||||
|
|
||||||
let all_lib_deps_by_context t targets =
|
let all_lib_deps_by_context t ~request =
|
||||||
|
let targets = static_deps_of_request t request in
|
||||||
List.fold_left (rules_for_targets t targets) ~init:[] ~f:(fun acc rule ->
|
List.fold_left (rules_for_targets t targets) ~init:[] ~f:(fun acc rule ->
|
||||||
let lib_deps = Build_interpret.lib_deps rule.Internal_rule.build in
|
let lib_deps = Build_interpret.lib_deps rule.Internal_rule.build in
|
||||||
Path.Map.fold lib_deps ~init:acc ~f:(fun ~key:path ~data:lib_deps acc ->
|
Path.Map.fold lib_deps ~init:acc ~f:(fun ~key:path ~data:lib_deps acc ->
|
||||||
|
@ -817,7 +853,7 @@ module Rule_closure =
|
||||||
rules_for_files graph (Pset.elements t.deps)
|
rules_for_files graph (Pset.elements t.deps)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
let build_rules t ?(recursive=false) targets =
|
let build_rules ?(recursive=false) t ~request =
|
||||||
let rules_seen = ref Id_set.empty in
|
let rules_seen = ref Id_set.empty in
|
||||||
let rules = ref [] in
|
let rules = ref [] in
|
||||||
let rec loop fn =
|
let rec loop fn =
|
||||||
|
@ -863,7 +899,10 @@ let build_rules t ?(recursive=false) targets =
|
||||||
return ()
|
return ()
|
||||||
end
|
end
|
||||||
in
|
in
|
||||||
Future.all_unit (List.map targets ~f:loop)
|
let targets = ref Pset.empty in
|
||||||
|
eval_request t ~request ~process_target:(fun fn ->
|
||||||
|
targets := Pset.add fn !targets;
|
||||||
|
loop fn)
|
||||||
>>= fun () ->
|
>>= fun () ->
|
||||||
Future.all !rules
|
Future.all !rules
|
||||||
>>| fun rules ->
|
>>| fun rules ->
|
||||||
|
@ -872,7 +911,10 @@ let build_rules t ?(recursive=false) targets =
|
||||||
Pset.fold r.targets ~init:acc ~f:(fun fn acc ->
|
Pset.fold r.targets ~init:acc ~f:(fun fn acc ->
|
||||||
Pmap.add acc ~key:fn ~data:r))
|
Pmap.add acc ~key:fn ~data:r))
|
||||||
in
|
in
|
||||||
match Rule_closure.top_closure rules (rules_for_files rules targets) with
|
match
|
||||||
|
Rule_closure.top_closure rules
|
||||||
|
(rules_for_files rules (Pset.elements !targets))
|
||||||
|
with
|
||||||
| Ok l -> l
|
| Ok l -> l
|
||||||
| Error cycle ->
|
| Error cycle ->
|
||||||
die "dependency cycle detected:\n %s"
|
die "dependency cycle detected:\n %s"
|
||||||
|
|
|
@ -23,16 +23,28 @@ module Build_error : sig
|
||||||
end
|
end
|
||||||
|
|
||||||
(** Do the actual build *)
|
(** Do the actual build *)
|
||||||
val do_build : t -> Path.t list -> (unit Future.t, Build_error.t) result
|
val do_build
|
||||||
val do_build_exn : t -> Path.t list -> unit Future.t
|
: t
|
||||||
|
-> request:(unit, unit) Build.t
|
||||||
|
-> (unit Future.t, Build_error.t) result
|
||||||
|
val do_build_exn
|
||||||
|
: t
|
||||||
|
-> request:(unit, unit) Build.t
|
||||||
|
-> unit Future.t
|
||||||
|
|
||||||
(** Return all the library dependencies (as written by the user) needed to build these
|
(** Return all the library dependencies (as written by the user)
|
||||||
targets *)
|
needed to build this request *)
|
||||||
val all_lib_deps : t -> Path.t list -> Build.lib_deps Path.Map.t
|
val all_lib_deps
|
||||||
|
: t
|
||||||
|
-> request:(unit, unit) Build.t
|
||||||
|
-> Build.lib_deps Path.Map.t
|
||||||
|
|
||||||
(** Return all the library dependencies required to build these targets, by context
|
(** Return all the library dependencies required to build this
|
||||||
name *)
|
request, by context name *)
|
||||||
val all_lib_deps_by_context : t -> Path.t list -> Build.lib_deps String_map.t
|
val all_lib_deps_by_context
|
||||||
|
: t
|
||||||
|
-> request:(unit, unit) Build.t
|
||||||
|
-> Build.lib_deps String_map.t
|
||||||
|
|
||||||
(** List of all buildable targets *)
|
(** List of all buildable targets *)
|
||||||
val all_targets : t -> Path.t list
|
val all_targets : t -> Path.t list
|
||||||
|
@ -58,9 +70,9 @@ end
|
||||||
[recursive] is [true], return all the rules needed to build the
|
[recursive] is [true], return all the rules needed to build the
|
||||||
given targets and their transitive dependencies. *)
|
given targets and their transitive dependencies. *)
|
||||||
val build_rules
|
val build_rules
|
||||||
: t
|
: ?recursive:bool (* default false *)
|
||||||
-> ?recursive:bool (* default false *)
|
-> t
|
||||||
-> Path.t list
|
-> request:(unit, unit) Build.t
|
||||||
-> Rule.t list Future.t
|
-> Rule.t list Future.t
|
||||||
|
|
||||||
val all_targets_ever_built
|
val all_targets_ever_built
|
||||||
|
|
|
@ -1,31 +1,25 @@
|
||||||
open! Import
|
open! Import
|
||||||
|
|
||||||
type 'a fold_callback_result =
|
|
||||||
| Cont of 'a
|
|
||||||
| Dont_recurse_in of String_set.t * 'a
|
|
||||||
|
|
||||||
module Dir = struct
|
module Dir = struct
|
||||||
type t =
|
type t =
|
||||||
{ path : Path.t
|
{ path : Path.t
|
||||||
; files : String_set.t
|
; files : String_set.t
|
||||||
; sub_dirs : t String_map.t
|
; sub_dirs : t String_map.t
|
||||||
|
; ignored : bool
|
||||||
}
|
}
|
||||||
|
|
||||||
let path t = t.path
|
let path t = t.path
|
||||||
let files t = t.files
|
let files t = t.files
|
||||||
let sub_dirs t = t.sub_dirs
|
let sub_dirs t = t.sub_dirs
|
||||||
|
let ignored t = t.ignored
|
||||||
|
|
||||||
let rec fold t ~init ~f =
|
let rec fold t ~traverse_ignored_dirs ~init:acc ~f =
|
||||||
match f t init with
|
if not traverse_ignored_dirs && t.ignored then
|
||||||
| Cont init ->
|
acc
|
||||||
String_map.fold t.sub_dirs ~init ~f:(fun ~key:_ ~data:t acc ->
|
else
|
||||||
fold t ~init:acc ~f)
|
let acc = f t acc in
|
||||||
| Dont_recurse_in (forbidden, init) ->
|
String_map.fold t.sub_dirs ~init:acc ~f:(fun ~key:_ ~data:t acc ->
|
||||||
String_map.fold t.sub_dirs ~init ~f:(fun ~key:sub_dir ~data:t acc ->
|
fold t ~traverse_ignored_dirs ~init:acc ~f)
|
||||||
if String_set.mem sub_dir forbidden then
|
|
||||||
acc
|
|
||||||
else
|
|
||||||
fold t ~init:acc ~f)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
type t =
|
type t =
|
||||||
|
@ -40,38 +34,59 @@ let ignore_file fn ~is_directory =
|
||||||
(is_directory && (fn.[0] = '.' || fn.[0] = '_')) ||
|
(is_directory && (fn.[0] = '.' || fn.[0] = '_')) ||
|
||||||
(fn.[0] = '.' && fn.[1] = '#')
|
(fn.[0] = '.' && fn.[1] = '#')
|
||||||
|
|
||||||
let load path =
|
let load ?(extra_ignored_subtrees=Path.Set.empty) path =
|
||||||
let rec walk path : Dir.t =
|
let rec walk path ~ignored : Dir.t =
|
||||||
let files, sub_dirs =
|
let files, sub_dirs =
|
||||||
Path.readdir path
|
Path.readdir path
|
||||||
|> List.filter_map ~f:(fun fn ->
|
|> List.filter_map ~f:(fun fn ->
|
||||||
let path = Path.relative path fn in
|
let path = Path.relative path fn in
|
||||||
let is_directory = Path.exists path && Path.is_directory path in
|
let is_directory =
|
||||||
|
try Path.is_directory path with _ -> false
|
||||||
|
in
|
||||||
if ignore_file fn ~is_directory then
|
if ignore_file fn ~is_directory then
|
||||||
None
|
None
|
||||||
|
else if is_directory then
|
||||||
|
Some (Inr (fn, path))
|
||||||
else
|
else
|
||||||
Some (fn, path, is_directory))
|
Some (Inl fn))
|
||||||
|> List.partition_map ~f:(fun (fn, path, is_directory) ->
|
|> List.partition_map ~f:(fun x -> x)
|
||||||
if is_directory then
|
in
|
||||||
Inr (fn, walk path)
|
let files = String_set.of_list files in
|
||||||
else
|
let ignored_sub_dirs =
|
||||||
Inl fn)
|
if not ignored && String_set.mem "jbuild-ignore" files then
|
||||||
|
String_set.of_list
|
||||||
|
(Io.lines_of_file (Path.to_string (Path.relative path "jbuild-ignore")))
|
||||||
|
else
|
||||||
|
String_set.empty
|
||||||
|
in
|
||||||
|
let sub_dirs =
|
||||||
|
List.map sub_dirs ~f:(fun (fn, path) ->
|
||||||
|
let ignored =
|
||||||
|
ignored
|
||||||
|
|| String_set.mem fn ignored_sub_dirs
|
||||||
|
|| Path.Set.mem path extra_ignored_subtrees
|
||||||
|
in
|
||||||
|
(fn, walk path ~ignored))
|
||||||
|
|> String_map.of_alist_exn
|
||||||
in
|
in
|
||||||
{ path
|
{ path
|
||||||
; files = String_set.of_list files
|
; files
|
||||||
; sub_dirs = String_map.of_alist_exn sub_dirs
|
; sub_dirs
|
||||||
|
; ignored
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
let root = walk path in
|
let root = walk path ~ignored:false in
|
||||||
let dirs =
|
let dirs =
|
||||||
Dir.fold root ~init:Path.Map.empty ~f:(fun dir acc ->
|
Dir.fold root ~init:Path.Map.empty ~traverse_ignored_dirs:true
|
||||||
Cont (Path.Map.add acc ~key:dir.path ~data:dir))
|
~f:(fun dir acc ->
|
||||||
|
Path.Map.add acc ~key:dir.path ~data:dir)
|
||||||
in
|
in
|
||||||
{ root
|
{ root
|
||||||
; dirs
|
; dirs
|
||||||
}
|
}
|
||||||
|
|
||||||
let fold t ~init ~f = Dir.fold t.root ~init ~f
|
let fold t ~traverse_ignored_dirs ~init ~f =
|
||||||
|
Dir.fold t.root ~traverse_ignored_dirs ~init ~f
|
||||||
|
|
||||||
let find_dir t path =
|
let find_dir t path =
|
||||||
Path.Map.find path t.dirs
|
Path.Map.find path t.dirs
|
||||||
|
@ -89,8 +104,8 @@ let files_recursively_in t ?(prefix_with=Path.root) path =
|
||||||
match find_dir t path with
|
match find_dir t path with
|
||||||
| None -> Path.Set.empty
|
| None -> Path.Set.empty
|
||||||
| Some dir ->
|
| Some dir ->
|
||||||
Dir.fold dir ~init:Path.Set.empty ~f:(fun dir acc ->
|
Dir.fold dir ~init:Path.Set.empty ~traverse_ignored_dirs:true
|
||||||
let path = Path.append prefix_with (Dir.path dir) in
|
~f:(fun dir acc ->
|
||||||
Cont
|
let path = Path.append prefix_with (Dir.path dir) in
|
||||||
(String_set.fold (Dir.files dir) ~init:acc ~f:(fun fn acc ->
|
String_set.fold (Dir.files dir) ~init:acc ~f:(fun fn acc ->
|
||||||
Path.Set.add (Path.relative path fn) acc)))
|
Path.Set.add (Path.relative path fn) acc))
|
||||||
|
|
|
@ -1,23 +1,34 @@
|
||||||
open! Import
|
open! Import
|
||||||
|
|
||||||
|
|
||||||
module Dir : sig
|
module Dir : sig
|
||||||
type t
|
type t
|
||||||
|
|
||||||
val path : t -> Path.t
|
val path : t -> Path.t
|
||||||
val files : t -> String_set.t
|
val files : t -> String_set.t
|
||||||
val sub_dirs : t -> t String_map.t
|
val sub_dirs : t -> t String_map.t
|
||||||
|
|
||||||
|
(** Whether this directory is ignored by a [jbuild-ignore] file in
|
||||||
|
one of its ancestor directories. *)
|
||||||
|
val ignored : t -> bool
|
||||||
|
|
||||||
|
val fold
|
||||||
|
: t
|
||||||
|
-> traverse_ignored_dirs:bool
|
||||||
|
-> init:'a
|
||||||
|
-> f:(t -> 'a -> 'a)
|
||||||
|
-> 'a
|
||||||
end
|
end
|
||||||
|
|
||||||
type t
|
type t
|
||||||
|
|
||||||
val load : Path.t -> t
|
val load : ?extra_ignored_subtrees:Path.Set.t -> Path.t -> t
|
||||||
|
|
||||||
type 'a fold_callback_result =
|
val fold
|
||||||
| Cont of 'a
|
: t
|
||||||
| Dont_recurse_in of String_set.t * 'a
|
-> traverse_ignored_dirs:bool
|
||||||
|
-> init:'a
|
||||||
val fold : t -> init:'a -> f:(Dir.t -> 'a -> 'a fold_callback_result) -> 'a
|
-> f:(Dir.t -> 'a -> 'a)
|
||||||
|
-> 'a
|
||||||
|
|
||||||
val root : t -> Dir.t
|
val root : t -> Dir.t
|
||||||
|
|
||||||
|
|
|
@ -1104,7 +1104,7 @@ end
|
||||||
let gen ~contexts ?(filter_out_optional_stanzas_with_missing_deps=true)
|
let gen ~contexts ?(filter_out_optional_stanzas_with_missing_deps=true)
|
||||||
?only_packages conf =
|
?only_packages conf =
|
||||||
let open Future in
|
let open Future in
|
||||||
let { Jbuild_load. file_tree; tree; jbuilds; packages } = conf in
|
let { Jbuild_load. file_tree; jbuilds; packages } = conf in
|
||||||
let aliases = Alias.Store.create () in
|
let aliases = Alias.Store.create () in
|
||||||
let dirs_with_dot_opam_files =
|
let dirs_with_dot_opam_files =
|
||||||
String_map.fold packages ~init:Path.Set.empty
|
String_map.fold packages ~init:Path.Set.empty
|
||||||
|
@ -1150,7 +1150,5 @@ let gen ~contexts ?(filter_out_optional_stanzas_with_missing_deps=true)
|
||||||
|> Future.all
|
|> Future.all
|
||||||
>>| fun l ->
|
>>| fun l ->
|
||||||
let rules, context_names_and_stanzas = List.split l in
|
let rules, context_names_and_stanzas = List.split l in
|
||||||
(Alias.rules aliases
|
(Alias.rules aliases @ List.concat rules,
|
||||||
~prefixes:(Path.root :: List.map contexts ~f:(fun c -> c.Context.build_dir)) ~tree
|
|
||||||
@ List.concat rules,
|
|
||||||
String_map.of_alist_exn context_names_and_stanzas)
|
String_map.of_alist_exn context_names_and_stanzas)
|
||||||
|
|
|
@ -504,3 +504,7 @@ let open_out_gen = `Use_Io
|
||||||
module No_io = struct
|
module No_io = struct
|
||||||
module Io = struct end
|
module Io = struct end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Fmt = struct
|
||||||
|
type 'a t = Format.formatter -> 'a -> unit
|
||||||
|
end
|
||||||
|
|
|
@ -200,6 +200,7 @@ module Dep_conf = struct
|
||||||
type t =
|
type t =
|
||||||
| File of String_with_vars.t
|
| File of String_with_vars.t
|
||||||
| Alias of String_with_vars.t
|
| Alias of String_with_vars.t
|
||||||
|
| Alias_rec of String_with_vars.t
|
||||||
| Glob_files of String_with_vars.t
|
| Glob_files of String_with_vars.t
|
||||||
| Files_recursively_in of String_with_vars.t
|
| Files_recursively_in of String_with_vars.t
|
||||||
|
|
||||||
|
@ -211,6 +212,7 @@ module Dep_conf = struct
|
||||||
sum
|
sum
|
||||||
[ cstr "file" (fun x -> File x)
|
[ cstr "file" (fun x -> File x)
|
||||||
; cstr "alias" (fun x -> Alias x)
|
; cstr "alias" (fun x -> Alias x)
|
||||||
|
; cstr "alias_rec" (fun x -> Alias_rec x)
|
||||||
; cstr "glob_files" (fun x -> Glob_files x)
|
; cstr "glob_files" (fun x -> Glob_files x)
|
||||||
; cstr "files_recursively_in" (fun x -> Files_recursively_in x)
|
; cstr "files_recursively_in" (fun x -> Files_recursively_in x)
|
||||||
]
|
]
|
||||||
|
@ -226,6 +228,8 @@ module Dep_conf = struct
|
||||||
List [Atom "file" ; String_with_vars.sexp_of_t t]
|
List [Atom "file" ; String_with_vars.sexp_of_t t]
|
||||||
| Alias t ->
|
| Alias t ->
|
||||||
List [Atom "alias" ; String_with_vars.sexp_of_t t]
|
List [Atom "alias" ; String_with_vars.sexp_of_t t]
|
||||||
|
| Alias_rec t ->
|
||||||
|
List [Atom "alias_rec" ; String_with_vars.sexp_of_t t]
|
||||||
| Glob_files t ->
|
| Glob_files t ->
|
||||||
List [Atom "glob_files" ; String_with_vars.sexp_of_t t]
|
List [Atom "glob_files" ; String_with_vars.sexp_of_t t]
|
||||||
| Files_recursively_in t ->
|
| Files_recursively_in t ->
|
||||||
|
|
|
@ -93,6 +93,7 @@ module Dep_conf : sig
|
||||||
type t =
|
type t =
|
||||||
| File of String_with_vars.t
|
| File of String_with_vars.t
|
||||||
| Alias of String_with_vars.t
|
| Alias of String_with_vars.t
|
||||||
|
| Alias_rec of String_with_vars.t
|
||||||
| Glob_files of String_with_vars.t
|
| Glob_files of String_with_vars.t
|
||||||
| Files_recursively_in of String_with_vars.t
|
| Files_recursively_in of String_with_vars.t
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,6 @@ end
|
||||||
|
|
||||||
type conf =
|
type conf =
|
||||||
{ file_tree : File_tree.t
|
{ file_tree : File_tree.t
|
||||||
; tree : Alias.tree
|
|
||||||
; jbuilds : Jbuilds.t
|
; jbuilds : Jbuilds.t
|
||||||
; packages : Package.t String_map.t
|
; packages : Package.t String_map.t
|
||||||
}
|
}
|
||||||
|
@ -164,41 +163,27 @@ let load ~dir ~scope =
|
||||||
| Ocaml_script ->
|
| Ocaml_script ->
|
||||||
Script { dir; scope }
|
Script { dir; scope }
|
||||||
|
|
||||||
let load ?(extra_ignored_subtrees=Path.Set.empty) () =
|
let load ?extra_ignored_subtrees () =
|
||||||
let ftree = File_tree.load Path.root in
|
let ftree = File_tree.load Path.root ?extra_ignored_subtrees in
|
||||||
let packages, ignored_subtrees =
|
let packages =
|
||||||
File_tree.fold ftree ~init:([], extra_ignored_subtrees) ~f:(fun dir (pkgs, ignored) ->
|
File_tree.fold ftree ~traverse_ignored_dirs:false ~init:[] ~f:(fun dir pkgs ->
|
||||||
let path = File_tree.Dir.path dir in
|
let path = File_tree.Dir.path dir in
|
||||||
let files = File_tree.Dir.files dir in
|
let files = File_tree.Dir.files dir in
|
||||||
let pkgs =
|
String_set.fold files ~init:pkgs ~f:(fun fn acc ->
|
||||||
String_set.fold files ~init:pkgs ~f:(fun fn acc ->
|
match Filename.split_extension fn with
|
||||||
match Filename.split_extension fn with
|
| (pkg, ".opam") when pkg <> "" ->
|
||||||
| (pkg, ".opam") when pkg <> "" ->
|
let version_from_opam_file =
|
||||||
let version_from_opam_file =
|
let opam = Opam_file.load (Path.relative path fn |> Path.to_string) in
|
||||||
let opam = Opam_file.load (Path.relative path fn |> Path.to_string) in
|
match Opam_file.get_field opam "version" with
|
||||||
match Opam_file.get_field opam "version" with
|
| Some (String (_, s)) -> Some s
|
||||||
| Some (String (_, s)) -> Some s
|
| _ -> None
|
||||||
| _ -> None
|
in
|
||||||
in
|
(pkg,
|
||||||
(pkg,
|
{ Package. name = pkg
|
||||||
{ Package. name = pkg
|
; path
|
||||||
; path
|
; version_from_opam_file
|
||||||
; version_from_opam_file
|
}) :: acc
|
||||||
}) :: acc
|
| _ -> acc))
|
||||||
| _ -> acc)
|
|
||||||
in
|
|
||||||
if String_set.mem "jbuild-ignore" files then
|
|
||||||
let ignore_set =
|
|
||||||
String_set.of_list
|
|
||||||
(Io.lines_of_file (Path.to_string (Path.relative path "jbuild-ignore")))
|
|
||||||
in
|
|
||||||
Dont_recurse_in
|
|
||||||
(ignore_set,
|
|
||||||
(pkgs,
|
|
||||||
String_set.fold ignore_set ~init:ignored ~f:(fun fn acc ->
|
|
||||||
Path.Set.add (Path.relative path fn) acc)))
|
|
||||||
else
|
|
||||||
Cont (pkgs, ignored))
|
|
||||||
in
|
in
|
||||||
let packages =
|
let packages =
|
||||||
String_map.of_alist_multi packages
|
String_map.of_alist_multi packages
|
||||||
|
@ -219,32 +204,27 @@ let load ?(extra_ignored_subtrees=Path.Set.empty) () =
|
||||||
|> Path.Map.map ~f:Scope.make
|
|> Path.Map.map ~f:Scope.make
|
||||||
in
|
in
|
||||||
let rec walk dir jbuilds scope =
|
let rec walk dir jbuilds scope =
|
||||||
let path = File_tree.Dir.path dir in
|
if File_tree.Dir.ignored dir then
|
||||||
let files = File_tree.Dir.files dir in
|
jbuilds
|
||||||
let sub_dirs = File_tree.Dir.sub_dirs dir in
|
else begin
|
||||||
let scope = Path.Map.find_default path scopes ~default:scope in
|
let path = File_tree.Dir.path dir in
|
||||||
let jbuilds =
|
let files = File_tree.Dir.files dir in
|
||||||
if String_set.mem "jbuild" files then
|
let sub_dirs = File_tree.Dir.sub_dirs dir in
|
||||||
let jbuild = load ~dir:path ~scope in
|
let scope = Path.Map.find_default path scopes ~default:scope in
|
||||||
jbuild :: jbuilds
|
let jbuilds =
|
||||||
else
|
if String_set.mem "jbuild" files then
|
||||||
jbuilds
|
let jbuild = load ~dir:path ~scope in
|
||||||
in
|
jbuild :: jbuilds
|
||||||
let children, jbuilds =
|
else
|
||||||
String_map.fold sub_dirs ~init:([], jbuilds)
|
jbuilds
|
||||||
~f:(fun ~key:_ ~data:dir (children, jbuilds) ->
|
in
|
||||||
if Path.Set.mem (File_tree.Dir.path dir) ignored_subtrees then
|
String_map.fold sub_dirs ~init:jbuilds
|
||||||
(children, jbuilds)
|
~f:(fun ~key:_ ~data:dir jbuilds ->
|
||||||
else
|
walk dir jbuilds scope)
|
||||||
let child, jbuilds = walk dir jbuilds scope in
|
end
|
||||||
(child :: children, jbuilds))
|
|
||||||
in
|
|
||||||
(Alias.Node (path, children), jbuilds)
|
|
||||||
in
|
in
|
||||||
let root = File_tree.root ftree in
|
let jbuilds = walk (File_tree.root ftree) [] Scope.empty in
|
||||||
let tree, jbuilds = walk root [] Scope.empty in
|
|
||||||
{ file_tree = ftree
|
{ file_tree = ftree
|
||||||
; tree
|
|
||||||
; jbuilds
|
; jbuilds
|
||||||
; packages
|
; packages
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ end
|
||||||
|
|
||||||
type conf =
|
type conf =
|
||||||
{ file_tree : File_tree.t
|
{ file_tree : File_tree.t
|
||||||
; tree : Alias.tree
|
|
||||||
; jbuilds : Jbuilds.t
|
; jbuilds : Jbuilds.t
|
||||||
; packages : Package.t String_map.t
|
; packages : Package.t String_map.t
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ type setup =
|
||||||
; stanzas : (Path.t * Jbuild.Scope.t * Jbuild.Stanzas.t) list String_map.t
|
; stanzas : (Path.t * Jbuild.Scope.t * Jbuild.Stanzas.t) list String_map.t
|
||||||
; contexts : Context.t list
|
; contexts : Context.t list
|
||||||
; packages : Package.t String_map.t
|
; packages : Package.t String_map.t
|
||||||
|
; file_tree : File_tree.t
|
||||||
}
|
}
|
||||||
|
|
||||||
let package_install_file { packages; _ } pkg =
|
let package_install_file { packages; _ } pkg =
|
||||||
|
@ -54,6 +55,7 @@ let setup ?(log=Log.no_log) ?filter_out_optional_stanzas_with_missing_deps
|
||||||
; stanzas
|
; stanzas
|
||||||
; contexts
|
; contexts
|
||||||
; packages = conf.packages
|
; packages = conf.packages
|
||||||
|
; file_tree = conf.file_tree
|
||||||
}
|
}
|
||||||
|
|
||||||
let external_lib_deps ?log ~packages () =
|
let external_lib_deps ?log ~packages () =
|
||||||
|
@ -71,7 +73,8 @@ let external_lib_deps ?log ~packages () =
|
||||||
| Some stanzas ->
|
| Some stanzas ->
|
||||||
let internals = Jbuild.Stanzas.lib_names stanzas in
|
let internals = Jbuild.Stanzas.lib_names stanzas in
|
||||||
Path.Map.map
|
Path.Map.map
|
||||||
(Build_system.all_lib_deps setup.build_system install_files)
|
(Build_system.all_lib_deps setup.build_system
|
||||||
|
~request:(Build.paths install_files))
|
||||||
~f:(String_map.filter ~f:(fun name _ ->
|
~f:(String_map.filter ~f:(fun name _ ->
|
||||||
not (String_set.mem name internals))))
|
not (String_set.mem name internals))))
|
||||||
|
|
||||||
|
@ -211,7 +214,8 @@ let bootstrap () =
|
||||||
~extra_ignored_subtrees:ignored_during_bootstrap
|
~extra_ignored_subtrees:ignored_during_bootstrap
|
||||||
()
|
()
|
||||||
>>= fun { build_system = bs; _ } ->
|
>>= fun { build_system = bs; _ } ->
|
||||||
Build_system.do_build_exn bs [Path.(relative root) (pkg ^ ".install")])
|
Build_system.do_build_exn bs
|
||||||
|
~request:(Build.path (Path.(relative root) (pkg ^ ".install"))))
|
||||||
in
|
in
|
||||||
try
|
try
|
||||||
main ()
|
main ()
|
||||||
|
|
|
@ -7,6 +7,7 @@ type setup =
|
||||||
stanzas : (Path.t * Scope.t * Stanzas.t) list String_map.t
|
stanzas : (Path.t * Scope.t * Stanzas.t) list String_map.t
|
||||||
; contexts : Context.t list
|
; contexts : Context.t list
|
||||||
; packages : Package.t String_map.t
|
; packages : Package.t String_map.t
|
||||||
|
; file_tree : File_tree.t
|
||||||
}
|
}
|
||||||
|
|
||||||
(* Returns [Error ()] if [pkg] is unknown *)
|
(* Returns [Error ()] if [pkg] is unknown *)
|
||||||
|
|
|
@ -424,3 +424,5 @@ let rm_rf =
|
||||||
let change_extension ~ext t =
|
let change_extension ~ext t =
|
||||||
let t = try Filename.chop_extension t with Not_found -> t in
|
let t = try Filename.chop_extension t with Not_found -> t in
|
||||||
t ^ ext
|
t ^ ext
|
||||||
|
|
||||||
|
let pp = Format.pp_print_string
|
||||||
|
|
|
@ -111,3 +111,5 @@ val rm_rf : t -> unit
|
||||||
|
|
||||||
(** Changes the extension of the filename (or adds an extension if there was none) *)
|
(** Changes the extension of the filename (or adds an extension if there was none) *)
|
||||||
val change_extension : ext:string -> t -> t
|
val change_extension : ext:string -> t -> t
|
||||||
|
|
||||||
|
val pp : t Fmt.t
|
||||||
|
|
|
@ -406,15 +406,21 @@ module Deps = struct
|
||||||
open Build.O
|
open Build.O
|
||||||
open Dep_conf
|
open Dep_conf
|
||||||
|
|
||||||
|
let make_alias t ~scope ~dir s =
|
||||||
|
Alias.of_path (Path.relative dir (expand_vars t ~scope ~dir s))
|
||||||
|
|
||||||
let dep t ~scope ~dir = function
|
let dep t ~scope ~dir = function
|
||||||
| File s ->
|
| File s ->
|
||||||
let path = Path.relative dir (expand_vars t ~scope ~dir s) in
|
let path = Path.relative dir (expand_vars t ~scope ~dir s) in
|
||||||
Build.path path
|
Build.path path
|
||||||
>>^ fun _ -> [path]
|
>>^ fun () -> [path]
|
||||||
| Alias s ->
|
| Alias s ->
|
||||||
let path = Alias.file (Alias.make ~dir (expand_vars t ~scope ~dir s)) in
|
Alias.dep (make_alias t ~scope ~dir s)
|
||||||
Build.path path
|
>>^ fun () -> []
|
||||||
>>^ fun _ -> []
|
| Alias_rec s ->
|
||||||
|
Alias.dep_rec ~loc:(String_with_vars.loc s) ~file_tree:t.file_tree
|
||||||
|
(make_alias t ~scope ~dir s)
|
||||||
|
>>^ fun () -> []
|
||||||
| Glob_files s -> begin
|
| Glob_files s -> begin
|
||||||
let path = Path.relative dir (expand_vars t ~scope ~dir s) in
|
let path = Path.relative dir (expand_vars t ~scope ~dir s) in
|
||||||
match Glob_lexer.parse_string (Path.basename path) with
|
match Glob_lexer.parse_string (Path.basename path) with
|
||||||
|
|
|
@ -71,3 +71,10 @@
|
||||||
(action
|
(action
|
||||||
(chdir test-cases/copy_files
|
(chdir test-cases/copy_files
|
||||||
(setenv JBUILDER ${bin:jbuilder} (run ${exe:cram.exe} run.t))))))
|
(setenv JBUILDER ${bin:jbuilder} (run ${exe:cram.exe} run.t))))))
|
||||||
|
|
||||||
|
(alias
|
||||||
|
((name runtest)
|
||||||
|
(deps ((files_recursively_in test-cases/aliases)))
|
||||||
|
(action
|
||||||
|
(chdir test-cases/aliases
|
||||||
|
(setenv JBUILDER ${bin:jbuilder} (run ${exe:cram.exe} run.t))))))
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
(jbuild_version 1)
|
||||||
|
|
||||||
|
(alias
|
||||||
|
((name just-in-src)
|
||||||
|
(deps ((alias src/x)))))
|
||||||
|
|
||||||
|
(alias
|
||||||
|
((name everywhere)
|
||||||
|
(deps ((alias_rec x)))))
|
|
@ -0,0 +1,22 @@
|
||||||
|
$ $JBUILDER clean -j1 --root .
|
||||||
|
$ $JBUILDER build -j1 --root . @just-in-src
|
||||||
|
running in src
|
||||||
|
$ $JBUILDER clean -j1 --root .
|
||||||
|
$ $JBUILDER build -j1 --root . @everywhere
|
||||||
|
running in src/foo/bar
|
||||||
|
running in src/foo/baz
|
||||||
|
running in src
|
||||||
|
$ $JBUILDER clean -j1 --root .
|
||||||
|
$ $JBUILDER build -j1 --root . @x
|
||||||
|
running in src/foo/bar
|
||||||
|
running in src/foo/baz
|
||||||
|
running in src
|
||||||
|
$ $JBUILDER build -j1 --root . @plop
|
||||||
|
File "<command-line>", line 1, characters 0-0:
|
||||||
|
Error: This alias is empty.
|
||||||
|
Alias "plop" is not defined in . or any of its descendants.
|
||||||
|
[1]
|
||||||
|
$ $JBUILDER build -j1 --root . @truc/x
|
||||||
|
File "<command-line>", line 1, characters 0-0:
|
||||||
|
Error: Don't know about directory truc!
|
||||||
|
[1]
|
|
@ -0,0 +1,5 @@
|
||||||
|
(jbuild_version 1)
|
||||||
|
|
||||||
|
(alias
|
||||||
|
((name x)
|
||||||
|
(action (chdir ${ROOT} (echo "running in ${path-no-dep:.}\n")))))
|
|
@ -0,0 +1,5 @@
|
||||||
|
(jbuild_version 1)
|
||||||
|
|
||||||
|
(alias
|
||||||
|
((name x)
|
||||||
|
(action (chdir ${ROOT} (echo "running in ${path-no-dep:.}\n")))))
|
|
@ -0,0 +1,5 @@
|
||||||
|
(jbuild_version 1)
|
||||||
|
|
||||||
|
(alias
|
||||||
|
((name x)
|
||||||
|
(action (chdir ${ROOT} (echo "running in ${path-no-dep:.}\n")))))
|
|
@ -1,29 +1,29 @@
|
||||||
$ $JBUILDER build -j1 --root . --dev bin/technologic.bc.js @install lib/x.cma.js lib/x__Y.cmo.js bin/z.cmo.js
|
$ $JBUILDER build -j1 --root . --dev bin/technologic.bc.js @install lib/x.cma.js lib/x__Y.cmo.js bin/z.cmo.js
|
||||||
ocamlopt .ppx/js_of_ocaml-ppx/ppx.exe
|
|
||||||
ocamlc lib/stubs.o
|
ocamlc lib/stubs.o
|
||||||
|
ocamlopt .ppx/js_of_ocaml-ppx/ppx.exe
|
||||||
ocamlc lib/x__.{cmi,cmo,cmt}
|
ocamlc lib/x__.{cmi,cmo,cmt}
|
||||||
ppx bin/technologic.pp.ml
|
ocamlmklib lib/dllx_stubs.so,lib/libx_stubs.a
|
||||||
ppx bin/z.pp.ml
|
|
||||||
ppx lib/x.pp.ml
|
ppx lib/x.pp.ml
|
||||||
ppx lib/y.pp.ml
|
ppx lib/y.pp.ml
|
||||||
ocamlmklib lib/dllx_stubs.so,lib/libx_stubs.a
|
ppx bin/technologic.pp.ml
|
||||||
|
ppx bin/z.pp.ml
|
||||||
ocamlopt lib/x__.{cmx,o}
|
ocamlopt lib/x__.{cmx,o}
|
||||||
ocamldep bin/technologic.depends.ocamldep-output
|
|
||||||
ocamldep lib/x.depends.ocamldep-output
|
ocamldep lib/x.depends.ocamldep-output
|
||||||
|
ocamldep bin/technologic.depends.ocamldep-output
|
||||||
|
ocamlc lib/x__Y.{cmi,cmo,cmt}
|
||||||
js_of_ocaml .js/js_of_ocaml/js_of_ocaml.cma.js
|
js_of_ocaml .js/js_of_ocaml/js_of_ocaml.cma.js
|
||||||
js_of_ocaml .js/stdlib/stdlib.cma.js
|
js_of_ocaml .js/stdlib/stdlib.cma.js
|
||||||
ocamlc lib/x__Y.{cmi,cmo,cmt}
|
|
||||||
js_of_ocaml lib/x__Y.cmo.js
|
js_of_ocaml lib/x__Y.cmo.js
|
||||||
ocamlopt lib/x__Y.{cmx,o}
|
ocamlopt lib/x__Y.{cmx,o}
|
||||||
ocamlc lib/x.{cmi,cmo,cmt}
|
ocamlc lib/x.{cmi,cmo,cmt}
|
||||||
ocamlopt lib/x.{cmx,o}
|
ocamlopt lib/x.{cmx,o}
|
||||||
ocamlc bin/z.{cmi,cmo,cmt}
|
|
||||||
ocamlc lib/x.cma
|
ocamlc lib/x.cma
|
||||||
|
ocamlc bin/z.{cmi,cmo,cmt}
|
||||||
ocamlopt lib/x.{a,cmxa}
|
ocamlopt lib/x.{a,cmxa}
|
||||||
js_of_ocaml bin/z.cmo.js
|
|
||||||
ocamlc bin/technologic.{cmi,cmo,cmt}
|
|
||||||
js_of_ocaml lib/x.cma.js
|
js_of_ocaml lib/x.cma.js
|
||||||
js_of_ocaml bin/technologic.bc.runtime.js
|
js_of_ocaml bin/technologic.bc.runtime.js
|
||||||
|
js_of_ocaml bin/z.cmo.js
|
||||||
|
ocamlc bin/technologic.{cmi,cmo,cmt}
|
||||||
ocamlopt lib/x.cmxs
|
ocamlopt lib/x.cmxs
|
||||||
js_of_ocaml bin/technologic.cmo.js
|
js_of_ocaml bin/technologic.cmo.js
|
||||||
jsoo_link bin/technologic.bc.js
|
jsoo_link bin/technologic.bc.js
|
||||||
|
@ -34,17 +34,17 @@
|
||||||
fix it
|
fix it
|
||||||
$ $JBUILDER build -j1 --root . bin/technologic.bc.js @install
|
$ $JBUILDER build -j1 --root . bin/technologic.bc.js @install
|
||||||
ocamlc lib/x__.{cmi,cmo,cmt}
|
ocamlc lib/x__.{cmi,cmo,cmt}
|
||||||
ocamlc lib/x__Y.{cmi,cmo,cmt}
|
|
||||||
ocamlopt lib/x__.{cmx,o}
|
ocamlopt lib/x__.{cmx,o}
|
||||||
ocamlc lib/x.{cmi,cmo,cmt}
|
ocamlc lib/x__Y.{cmi,cmo,cmt}
|
||||||
ocamlopt lib/x__Y.{cmx,o}
|
ocamlopt lib/x__Y.{cmx,o}
|
||||||
|
ocamlc lib/x.{cmi,cmo,cmt}
|
||||||
|
ocamlopt lib/x.{cmx,o}
|
||||||
ocamlc lib/x.cma
|
ocamlc lib/x.cma
|
||||||
ocamlc bin/z.{cmi,cmo,cmt}
|
ocamlc bin/z.{cmi,cmo,cmt}
|
||||||
ocamlopt lib/x.{cmx,o}
|
|
||||||
ocamlc bin/technologic.{cmi,cmo,cmt}
|
|
||||||
ocamlopt lib/x.{a,cmxa}
|
ocamlopt lib/x.{a,cmxa}
|
||||||
ocamlc bin/technologic.bc
|
ocamlc bin/technologic.{cmi,cmo,cmt}
|
||||||
ocamlopt lib/x.cmxs
|
ocamlopt lib/x.cmxs
|
||||||
|
ocamlc bin/technologic.bc
|
||||||
js_of_ocaml bin/technologic.bc.js
|
js_of_ocaml bin/technologic.bc.js
|
||||||
$ $NODE ./_build/default/bin/technologic.bc.js
|
$ $NODE ./_build/default/bin/technologic.bc.js
|
||||||
buy it
|
buy it
|
||||||
|
|
Loading…
Reference in New Issue