Merge branch 'master' into rename-build-profile
This commit is contained in:
commit
f163f6197a
|
@ -93,7 +93,14 @@ next
|
||||||
|
|
||||||
- Make `dev` the default build profile (#920, @diml)
|
- Make `dev` the default build profile (#920, @diml)
|
||||||
|
|
||||||
- Version `dune-workspace` and `~/.config/dune/config` files (#..., @diml)
|
- Version `dune-workspace` and `~/.config/dune/config` files (#932, @diml)
|
||||||
|
|
||||||
|
- Add the ability to build an alias non-recursively from the command
|
||||||
|
line by writing `@@alias` (#926, @diml)
|
||||||
|
|
||||||
|
- Add a special `default` alias that defaults to `(alias_rec install)`
|
||||||
|
when not defined by the user and make `@@default` be the default
|
||||||
|
target (#926, @diml)
|
||||||
|
|
||||||
- Add `%{profile}` variable. (#938, @rgrinberg)
|
- Add `%{profile}` variable. (#938, @rgrinberg)
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ $ jbuilder build --only-packages <package-name> @install
|
||||||
|
|
||||||
Jbuilder is able to build a given source code repository against
|
Jbuilder is able to build a given source code repository against
|
||||||
several configurations simultaneously. This helps maintaining packages
|
several configurations simultaneously. This helps maintaining packages
|
||||||
across several versions of OCaml as you can tests them all at once
|
across several versions of OCaml as you can test them all at once
|
||||||
without hassle.
|
without hassle.
|
||||||
|
|
||||||
This feature should make cross-compilation easy, see details in the
|
This feature should make cross-compilation easy, see details in the
|
||||||
|
|
98
bin/main.ml
98
bin/main.ml
|
@ -26,6 +26,7 @@ type common =
|
||||||
; (* Original arguments for the external-lib-deps hint *)
|
; (* Original arguments for the external-lib-deps hint *)
|
||||||
orig_args : string list
|
orig_args : string list
|
||||||
; config : Config.t
|
; config : Config.t
|
||||||
|
; default_target : string
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefix_target common s = common.target_prefix ^ s
|
let prefix_target common s = common.target_prefix ^ s
|
||||||
|
@ -114,8 +115,21 @@ end
|
||||||
|
|
||||||
type target =
|
type target =
|
||||||
| File of Path.t
|
| File of Path.t
|
||||||
|
| Alias of Path.t
|
||||||
| Alias_rec of Path.t
|
| Alias_rec of Path.t
|
||||||
|
|
||||||
|
let parse_alias path ~contexts =
|
||||||
|
let dir = Path.parent_exn path in
|
||||||
|
let name = Path.basename path in
|
||||||
|
match Path.extract_build_context dir with
|
||||||
|
| None -> (contexts, dir, name)
|
||||||
|
| Some ("install", _) ->
|
||||||
|
die "Invalid alias: %s.\n\
|
||||||
|
There are no aliases in %s."
|
||||||
|
(Path.to_string_maybe_quoted Path.(relative build_dir "install"))
|
||||||
|
(Path.to_string_maybe_quoted path)
|
||||||
|
| Some (ctx, dir) -> ([ctx], dir, name)
|
||||||
|
|
||||||
let request_of_targets (setup : Main.setup) targets =
|
let request_of_targets (setup : Main.setup) targets =
|
||||||
let open Build.O in
|
let open Build.O in
|
||||||
let contexts = List.map setup.contexts ~f:(fun c -> c.Context.name) in
|
let contexts = List.map setup.contexts ~f:(fun c -> c.Context.name) in
|
||||||
|
@ -123,19 +137,12 @@ let request_of_targets (setup : Main.setup) targets =
|
||||||
acc >>>
|
acc >>>
|
||||||
match target with
|
match target with
|
||||||
| File path -> Build.path path
|
| File path -> Build.path path
|
||||||
|
| Alias path ->
|
||||||
|
let contexts, dir, name = parse_alias path ~contexts in
|
||||||
|
Build_system.Alias.dep_multi_contexts ~dir ~name
|
||||||
|
~file_tree:setup.file_tree ~contexts
|
||||||
| Alias_rec path ->
|
| Alias_rec path ->
|
||||||
let dir = Path.parent_exn path in
|
let contexts, dir, name = parse_alias path ~contexts in
|
||||||
let name = Path.basename path in
|
|
||||||
let contexts, dir =
|
|
||||||
match Path.extract_build_context dir with
|
|
||||||
| None -> (contexts, dir)
|
|
||||||
| Some ("install", _) ->
|
|
||||||
die "Invalid alias: %s.\n\
|
|
||||||
There are no aliases in %s."
|
|
||||||
(Path.to_string_maybe_quoted Path.(relative build_dir "install"))
|
|
||||||
(Path.to_string_maybe_quoted path)
|
|
||||||
| Some (ctx, dir) -> ([ctx], dir)
|
|
||||||
in
|
|
||||||
Build_system.Alias.dep_rec_multi_contexts ~dir ~name
|
Build_system.Alias.dep_rec_multi_contexts ~dir ~name
|
||||||
~file_tree:setup.file_tree ~contexts)
|
~file_tree:setup.file_tree ~contexts)
|
||||||
|
|
||||||
|
@ -228,6 +235,7 @@ let common =
|
||||||
ignore_promoted_rules,
|
ignore_promoted_rules,
|
||||||
config_file,
|
config_file,
|
||||||
profile,
|
profile,
|
||||||
|
default_target,
|
||||||
orig)
|
orig)
|
||||||
x
|
x
|
||||||
display
|
display
|
||||||
|
@ -290,6 +298,7 @@ let common =
|
||||||
; x
|
; x
|
||||||
; config
|
; config
|
||||||
; build_dir
|
; build_dir
|
||||||
|
; default_target
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
let docs = copts_sect in
|
let docs = copts_sect in
|
||||||
|
@ -478,6 +487,20 @@ let common =
|
||||||
in
|
in
|
||||||
Term.(ret (const merge $ config_file $ no_config))
|
Term.(ret (const merge $ config_file $ no_config))
|
||||||
in
|
in
|
||||||
|
let default_target_default =
|
||||||
|
match Which_program.t with
|
||||||
|
| Dune -> "@@default"
|
||||||
|
| Jbuilder -> "@install"
|
||||||
|
in
|
||||||
|
let default_target =
|
||||||
|
Arg.(value
|
||||||
|
& opt (some string) None
|
||||||
|
& info ["default-target"] ~docs ~docv:"TARGET"
|
||||||
|
~doc:(sprintf
|
||||||
|
{|Set the default target that when none is specified to
|
||||||
|
$(b,dune build). It defaults to %s.|}
|
||||||
|
default_target_default))
|
||||||
|
in
|
||||||
let for_release = "for-release-of-packages" in
|
let for_release = "for-release-of-packages" in
|
||||||
let frop =
|
let frop =
|
||||||
Arg.(value
|
Arg.(value
|
||||||
|
@ -490,33 +513,37 @@ let common =
|
||||||
packages as well as getting reproducible builds.|})
|
packages as well as getting reproducible builds.|})
|
||||||
in
|
in
|
||||||
let merge root only_packages ignore_promoted_rules
|
let merge root only_packages ignore_promoted_rules
|
||||||
(config_file_opt, config_file) profile release =
|
(config_file_opt, config_file) profile default_target release =
|
||||||
let fail opt = incompatible ("-p/--" ^ for_release) opt in
|
let fail opt = incompatible ("-p/--" ^ for_release) opt in
|
||||||
match release, root, only_packages, ignore_promoted_rules,
|
match release, root, only_packages, ignore_promoted_rules,
|
||||||
profile, config_file_opt with
|
profile, default_target, config_file_opt with
|
||||||
| Some _, Some _, _, _, _, _ -> fail "--root"
|
| Some _, Some _, _, _, _, _, _ -> fail "--root"
|
||||||
| Some _, _, Some _, _, _, _ -> fail "--only-packages"
|
| Some _, _, Some _, _, _, _, _ -> fail "--only-packages"
|
||||||
| Some _, _, _, true , _, _ -> fail "--ignore-promoted-rules"
|
| Some _, _, _, true , _, _, _ -> fail "--ignore-promoted-rules"
|
||||||
| Some _, _, _, _, Some _, _ -> fail "--profile"
|
| Some _, _, _, _, Some _, _, _ -> fail "--profile"
|
||||||
| Some _, _, _, _, _, Some s -> fail s
|
| Some _, _, _, _, _, Some s, _ -> fail s
|
||||||
| Some pkgs, None, None, false, None, None ->
|
| Some _, _, _, _, _, _, Some _ -> fail "--default-target"
|
||||||
|
| Some pkgs, None, None, false, None, None, None ->
|
||||||
`Ok (Some ".",
|
`Ok (Some ".",
|
||||||
Some pkgs,
|
Some pkgs,
|
||||||
true,
|
true,
|
||||||
No_config,
|
No_config,
|
||||||
Some "release",
|
Some "release",
|
||||||
|
"@install",
|
||||||
["-p"; pkgs]
|
["-p"; pkgs]
|
||||||
)
|
)
|
||||||
| None, _, _, _, _, _ ->
|
| None, _, _, _, _, _, _ ->
|
||||||
`Ok (root,
|
`Ok (root,
|
||||||
only_packages,
|
only_packages,
|
||||||
ignore_promoted_rules,
|
ignore_promoted_rules,
|
||||||
config_file,
|
config_file,
|
||||||
profile,
|
profile,
|
||||||
|
Option.value default_target ~default:default_target_default,
|
||||||
List.concat
|
List.concat
|
||||||
[ dump_opt "--root" root
|
[ dump_opt "--root" root
|
||||||
; dump_opt "--only-packages" only_packages
|
; dump_opt "--only-packages" only_packages
|
||||||
; dump_opt "--profile" profile
|
; dump_opt "--profile" profile
|
||||||
|
; dump_opt "--default-target" default_target
|
||||||
; if ignore_promoted_rules then
|
; if ignore_promoted_rules then
|
||||||
["--ignore-promoted-rules"]
|
["--ignore-promoted-rules"]
|
||||||
else
|
else
|
||||||
|
@ -534,6 +561,7 @@ let common =
|
||||||
$ ignore_promoted_rules
|
$ ignore_promoted_rules
|
||||||
$ config_file
|
$ config_file
|
||||||
$ profile
|
$ profile
|
||||||
|
$ default_target
|
||||||
$ frop))
|
$ frop))
|
||||||
in
|
in
|
||||||
let x =
|
let x =
|
||||||
|
@ -680,7 +708,13 @@ let resolve_targets ~log common (setup : Main.setup) user_targets =
|
||||||
let targets =
|
let targets =
|
||||||
List.map user_targets ~f:(fun s ->
|
List.map user_targets ~f:(fun s ->
|
||||||
if String.is_prefix s ~prefix:"@" then begin
|
if String.is_prefix s ~prefix:"@" then begin
|
||||||
let s = String.sub s ~pos:1 ~len:(String.length s - 1) in
|
let pos, is_rec =
|
||||||
|
if String.length s >= 2 && s.[1] = '@' then
|
||||||
|
(2, false)
|
||||||
|
else
|
||||||
|
(1, true)
|
||||||
|
in
|
||||||
|
let s = String.sub s ~pos ~len:(String.length s - pos) in
|
||||||
let path = Path.relative Path.root (prefix_target common s) in
|
let path = Path.relative Path.root (prefix_target common s) in
|
||||||
check_path path;
|
check_path path;
|
||||||
if Path.is_root path then
|
if Path.is_root path then
|
||||||
|
@ -688,7 +722,7 @@ let resolve_targets ~log common (setup : Main.setup) user_targets =
|
||||||
else if not (Path.is_managed path) then
|
else if not (Path.is_managed path) then
|
||||||
die "@@ on the command line must be followed by a relative path"
|
die "@@ on the command line must be followed by a relative path"
|
||||||
else
|
else
|
||||||
Ok [Alias_rec path]
|
Ok [if is_rec then Alias_rec path else Alias path]
|
||||||
end else begin
|
end else begin
|
||||||
let path = Path.relative Path.root (prefix_target common s) in
|
let path = Path.relative Path.root (prefix_target common s) in
|
||||||
check_path path;
|
check_path path;
|
||||||
|
@ -725,6 +759,9 @@ 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 ->
|
||||||
|
Log.info log @@ "- alias " ^
|
||||||
|
(Path.to_string_maybe_quoted path)
|
||||||
| Alias_rec path ->
|
| Alias_rec path ->
|
||||||
Log.info log @@ "- recursive alias " ^
|
Log.info log @@ "- recursive alias " ^
|
||||||
(Path.to_string_maybe_quoted path));
|
(Path.to_string_maybe_quoted path));
|
||||||
|
@ -756,9 +793,14 @@ let build_targets =
|
||||||
(Main.setup ~log common >>= fun setup ->
|
(Main.setup ~log common >>= fun setup ->
|
||||||
let targets = resolve_targets_exn ~log common setup targets in
|
let targets = resolve_targets_exn ~log common setup targets in
|
||||||
do_build setup targets) in
|
do_build setup targets) in
|
||||||
|
let default_target =
|
||||||
|
match Which_program.t with
|
||||||
|
| Dune -> "@@default"
|
||||||
|
| Jbuilder -> "@install"
|
||||||
|
in
|
||||||
( Term.(const go
|
( Term.(const go
|
||||||
$ common
|
$ common
|
||||||
$ Arg.(value & pos_all string ["@install"] name_))
|
$ Arg.(value & pos_all string [default_target] name_))
|
||||||
, Term.info "build" ~doc ~man)
|
, Term.info "build" ~doc ~man)
|
||||||
|
|
||||||
let runtest =
|
let runtest =
|
||||||
|
@ -1316,7 +1358,7 @@ let utop =
|
||||||
match resolve_targets_exn ~log common setup [utop_target] with
|
match resolve_targets_exn ~log common setup [utop_target] with
|
||||||
| [] -> die "no libraries defined in %s" dir
|
| [] -> die "no libraries defined in %s" dir
|
||||||
| [File target] -> target
|
| [File target] -> target
|
||||||
| [Alias_rec _] | _::_::_ -> assert false
|
| _ -> assert false
|
||||||
in
|
in
|
||||||
do_build setup [File target] >>| fun () ->
|
do_build setup [File target] >>| fun () ->
|
||||||
(setup.build_system, context, Path.to_string target)
|
(setup.build_system, context, Path.to_string target)
|
||||||
|
@ -1426,10 +1468,10 @@ module Help = struct
|
||||||
Unix systems and $(b,Local Settings/dune/config) in the User home
|
Unix systems and $(b,Local Settings/dune/config) in the User home
|
||||||
directory on Windows. However, it is possible to specify an
|
directory on Windows. However, it is possible to specify an
|
||||||
alternative configuration file with the $(b,--config-file) option.|}
|
alternative configuration file with the $(b,--config-file) option.|}
|
||||||
; `P {|The first line of the file must be of the form (lang dune X.Y) \
|
; `P {|The first line of the file must be of the form (lang dune X.Y)
|
||||||
where X.Y is the version of the dune language used in the file.|}
|
where X.Y is the version of the dune language used in the file.|}
|
||||||
; `P {|The rest of the file must be written in S-expression syntax and be \
|
; `P {|The rest of the file must be written in S-expression syntax and be
|
||||||
composed of a list of stanzas. The following sections describe \
|
composed of a list of stanzas. The following sections describe
|
||||||
the stanzas available.|}
|
the stanzas available.|}
|
||||||
; `S "DISPLAY MODES"
|
; `S "DISPLAY MODES"
|
||||||
; `P {|Syntax: $(b,\(display MODE\))|}
|
; `P {|Syntax: $(b,\(display MODE\))|}
|
||||||
|
|
|
@ -531,6 +531,8 @@ menhir
|
||||||
A ``menhir`` stanza is available to support the menhir_ parser generator. See
|
A ``menhir`` stanza is available to support the menhir_ parser generator. See
|
||||||
the :ref:`menhir-main` section for details.
|
the :ref:`menhir-main` section for details.
|
||||||
|
|
||||||
|
.. _alias-stanza:
|
||||||
|
|
||||||
alias
|
alias
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ In a directory of your choice, write this ``jbuild`` file:
|
||||||
|
|
||||||
(jbuild_version 1)
|
(jbuild_version 1)
|
||||||
|
|
||||||
;; This declare the hello_world executable implemented by hello_world.ml
|
;; This declares the hello_world executable implemented by hello_world.ml
|
||||||
(executable
|
(executable
|
||||||
((name hello_world)))
|
((name hello_world)))
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,9 @@ Terminology
|
||||||
alias in all children directories recursively. Jbuilder defines the
|
alias in all children directories recursively. Jbuilder defines the
|
||||||
following standard aliases:
|
following standard aliases:
|
||||||
|
|
||||||
|
- ``default`` which is the alias build by default when no targets
|
||||||
|
are specified on the command line. See :ref:`default-alias` for
|
||||||
|
details
|
||||||
- ``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
|
||||||
- ``doc`` which depends on the generated HTML
|
- ``doc`` which depends on the generated HTML
|
||||||
|
|
|
@ -68,8 +68,9 @@ directory as this is normally the case.
|
||||||
Interpretation of targets
|
Interpretation of targets
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
This section describes how ``jbuilder`` interprets the targets given on
|
This section describes how ``dune`` interprets the targets given on
|
||||||
the command line.
|
the command line. When no targets are specified, ``dune`` builds the
|
||||||
|
``default`` alias, see :ref:`default-alias` for more details.
|
||||||
|
|
||||||
Resolution
|
Resolution
|
||||||
----------
|
----------
|
||||||
|
@ -121,6 +122,38 @@ So for instance:
|
||||||
the ``foo`` build context
|
the ``foo`` build context
|
||||||
- ``jbuilder build @runtest`` will run the tests for all build contexts
|
- ``jbuilder build @runtest`` will run the tests for all build contexts
|
||||||
|
|
||||||
|
You can also build an alias non-recursively by using ``@@`` instead of
|
||||||
|
``@``. For instance to run tests only from the current directory:
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
dune build @@runtest
|
||||||
|
|
||||||
|
.. _default-alias:
|
||||||
|
|
||||||
|
Default alias
|
||||||
|
-------------
|
||||||
|
|
||||||
|
When no targets are given to ``dune build``, it builds the special
|
||||||
|
``default`` alias. Effectively ``dune build`` is equivalent to:
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
dune build @@default
|
||||||
|
|
||||||
|
When a directory doesn't explicitly define what the ``default`` alias
|
||||||
|
means via an :ref:`alias-stanza` stanza, the following implicit
|
||||||
|
definition is assumed:
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
(alias
|
||||||
|
(name default)
|
||||||
|
(deps (alias_rec install)))
|
||||||
|
|
||||||
|
Which means that by default ``dune build`` will build everything that
|
||||||
|
is installable.
|
||||||
|
|
||||||
Finding external libraries
|
Finding external libraries
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
@ -207,7 +240,7 @@ follows:
|
||||||
build: [["dune" "build" "-p" name "-j" jobs]]
|
build: [["dune" "build" "-p" name "-j" jobs]]
|
||||||
|
|
||||||
``-p pkg`` is a shorthand for ``--root . --only-packages pkg --profile
|
``-p pkg`` is a shorthand for ``--root . --only-packages pkg --profile
|
||||||
release``. ``-p`` is the short version of
|
release --default-target @install``. ``-p`` is the short version of
|
||||||
``--for-release-of-packages``.
|
``--for-release-of-packages``.
|
||||||
|
|
||||||
This has the following effects:
|
This has the following effects:
|
||||||
|
@ -217,6 +250,7 @@ This has the following effects:
|
||||||
- it sets the root to prevent jbuilder from looking it up
|
- it sets the root to prevent jbuilder from looking it up
|
||||||
- it sets the build profile to ``release``
|
- it sets the build profile to ``release``
|
||||||
- it uses whatever concurrency option opam provides
|
- it uses whatever concurrency option opam provides
|
||||||
|
- it sets the default target to ``@install`` rather than ``@@default``
|
||||||
|
|
||||||
Note that ``name`` and ``jobs`` are variables expanded by opam. ``name``
|
Note that ``name`` and ``jobs`` are variables expanded by opam. ``name``
|
||||||
expands to the package name and ``jobs`` to the number of jobs available
|
expands to the package name and ``jobs`` to the number of jobs available
|
||||||
|
|
|
@ -37,6 +37,7 @@ module Repr = struct
|
||||||
| Fail : fail -> (_, _) t
|
| Fail : fail -> (_, _) t
|
||||||
| Memo : 'a memo -> (unit, 'a) t
|
| Memo : 'a memo -> (unit, 'a) t
|
||||||
| Catch : ('a, 'b) t * (exn -> 'b) -> ('a, 'b) t
|
| Catch : ('a, 'b) t * (exn -> 'b) -> ('a, 'b) t
|
||||||
|
| Lazy_no_targets : ('a, 'b) t Lazy.t -> ('a, 'b) t
|
||||||
|
|
||||||
and 'a memo =
|
and 'a memo =
|
||||||
{ name : string
|
{ name : string
|
||||||
|
@ -132,6 +133,8 @@ let rec all = function
|
||||||
>>>
|
>>>
|
||||||
arr (fun (x, y) -> x :: y)
|
arr (fun (x, y) -> x :: y)
|
||||||
|
|
||||||
|
let lazy_no_targets t = Lazy_no_targets t
|
||||||
|
|
||||||
let path p = Paths (Path.Set.singleton p)
|
let path p = Paths (Path.Set.singleton p)
|
||||||
let paths ps = Paths (Path.Set.of_list ps)
|
let paths ps = Paths (Path.Set.of_list ps)
|
||||||
let path_set ps = Paths ps
|
let path_set ps = Paths ps
|
||||||
|
|
|
@ -34,6 +34,10 @@ val fanout4 : ('a, 'b) t -> ('a, 'c) t -> ('a, 'd) t -> ('a, 'e) t -> ('a, 'b *
|
||||||
|
|
||||||
val all : ('a, 'b) t list -> ('a, 'b list) t
|
val all : ('a, 'b) t list -> ('a, 'b list) t
|
||||||
|
|
||||||
|
(** Optimization to avoiding eagerly computing a [Build.t] value,
|
||||||
|
assume it contains no targets. *)
|
||||||
|
val lazy_no_targets : ('a, 'b) t Lazy.t -> ('a, 'b) t
|
||||||
|
|
||||||
(* CR-someday diml: this API is not great, what about:
|
(* CR-someday diml: this API is not great, what about:
|
||||||
|
|
||||||
{[
|
{[
|
||||||
|
@ -202,6 +206,7 @@ module Repr : sig
|
||||||
| Fail : fail -> (_, _) t
|
| Fail : fail -> (_, _) t
|
||||||
| Memo : 'a memo -> (unit, 'a) t
|
| Memo : 'a memo -> (unit, 'a) t
|
||||||
| Catch : ('a, 'b) t * (exn -> 'b) -> ('a, 'b) t
|
| Catch : ('a, 'b) t * (exn -> 'b) -> ('a, 'b) t
|
||||||
|
| Lazy_no_targets : ('a, 'b) t Lazy.t -> ('a, 'b) t
|
||||||
|
|
||||||
and 'a memo =
|
and 'a memo =
|
||||||
{ name : string
|
{ name : string
|
||||||
|
|
|
@ -49,17 +49,23 @@ let inspect_path file_tree path =
|
||||||
else
|
else
|
||||||
None
|
None
|
||||||
|
|
||||||
|
let no_targets_allowed () =
|
||||||
|
Exn.code_error "No targets allowed under a [Build.lazy_no_targets] \
|
||||||
|
or [Build.if_file_exists]" []
|
||||||
|
[@@inline never]
|
||||||
|
|
||||||
let static_deps t ~all_targets ~file_tree =
|
let static_deps t ~all_targets ~file_tree =
|
||||||
let rec loop : type a b. (a, b) t -> Static_deps.t -> Static_deps.t = fun t acc ->
|
let rec loop : type a b. (a, b) t -> Static_deps.t -> bool -> Static_deps.t
|
||||||
|
= fun t acc targets_allowed ->
|
||||||
match t with
|
match t with
|
||||||
| Arr _ -> acc
|
| Arr _ -> acc
|
||||||
| Targets _ -> acc
|
| Targets _ -> if not targets_allowed then no_targets_allowed (); acc
|
||||||
| Store_vfile _ -> acc
|
| Store_vfile _ -> if not targets_allowed then no_targets_allowed (); acc
|
||||||
| Compose (a, b) -> loop a (loop b acc)
|
| Compose (a, b) -> loop a (loop b acc targets_allowed) targets_allowed
|
||||||
| First t -> loop t acc
|
| First t -> loop t acc targets_allowed
|
||||||
| Second t -> loop t acc
|
| Second t -> loop t acc targets_allowed
|
||||||
| Split (a, b) -> loop a (loop b acc)
|
| Split (a, b) -> loop a (loop b acc targets_allowed) targets_allowed
|
||||||
| Fanout (a, b) -> loop a (loop b acc)
|
| Fanout (a, b) -> loop a (loop b acc targets_allowed) targets_allowed
|
||||||
| Paths fns -> { acc with action_deps = Path.Set.union fns acc.action_deps }
|
| Paths fns -> { acc with action_deps = Path.Set.union fns acc.action_deps }
|
||||||
| Paths_for_rule fns ->
|
| Paths_for_rule fns ->
|
||||||
{ acc with rule_deps = Path.Set.union fns acc.rule_deps }
|
{ acc with rule_deps = Path.Set.union fns acc.rule_deps }
|
||||||
|
@ -93,28 +99,34 @@ let static_deps t ~all_targets ~file_tree =
|
||||||
end
|
end
|
||||||
| If_file_exists (p, state) -> begin
|
| If_file_exists (p, state) -> begin
|
||||||
match !state with
|
match !state with
|
||||||
| Decided (_, t) -> loop t acc
|
| Decided (_, t) -> loop t acc false
|
||||||
| Undecided (then_, else_) ->
|
| Undecided (then_, else_) ->
|
||||||
let dir = Path.parent_exn p in
|
let dir = Path.parent_exn p in
|
||||||
let targets = all_targets ~dir in
|
let targets = all_targets ~dir in
|
||||||
if Path.Set.mem targets p then begin
|
if Path.Set.mem targets p then begin
|
||||||
state := Decided (true, then_);
|
state := Decided (true, then_);
|
||||||
loop then_ acc
|
loop then_ acc false
|
||||||
end else begin
|
end else begin
|
||||||
state := Decided (false, else_);
|
state := Decided (false, else_);
|
||||||
loop else_ acc
|
loop else_ acc false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
| Dyn_paths t -> loop t acc
|
| Dyn_paths t -> loop t acc targets_allowed
|
||||||
| Vpath (Vspec.T (p, _)) -> { acc with rule_deps = Path.Set.add acc.rule_deps p }
|
| Vpath (Vspec.T (p, _)) ->
|
||||||
|
{ acc with rule_deps = Path.Set.add acc.rule_deps p }
|
||||||
| Contents p -> { acc with rule_deps = Path.Set.add acc.rule_deps p }
|
| Contents p -> { acc with rule_deps = Path.Set.add acc.rule_deps p }
|
||||||
| Lines_of p -> { acc with rule_deps = Path.Set.add acc.rule_deps p }
|
| Lines_of p -> { acc with rule_deps = Path.Set.add acc.rule_deps p }
|
||||||
| Record_lib_deps _ -> acc
|
| Record_lib_deps _ -> acc
|
||||||
| Fail _ -> acc
|
| Fail _ -> acc
|
||||||
| Memo m -> loop m.t acc
|
| Memo m -> loop m.t acc targets_allowed
|
||||||
| Catch (t, _) -> loop t acc
|
| Catch (t, _) -> loop t acc targets_allowed
|
||||||
|
| Lazy_no_targets t -> loop (Lazy.force t) acc false
|
||||||
in
|
in
|
||||||
loop (Build.repr t) { rule_deps = Path.Set.empty; action_deps = Path.Set.empty }
|
loop (Build.repr t)
|
||||||
|
{ rule_deps = Path.Set.empty
|
||||||
|
; action_deps = Path.Set.empty
|
||||||
|
}
|
||||||
|
true
|
||||||
|
|
||||||
let lib_deps =
|
let lib_deps =
|
||||||
let rec loop : type a b. (a, b) t -> Build.lib_deps -> Build.lib_deps
|
let rec loop : type a b. (a, b) t -> Build.lib_deps -> Build.lib_deps
|
||||||
|
@ -141,6 +153,7 @@ let lib_deps =
|
||||||
loop (get_if_file_exists_exn state) acc
|
loop (get_if_file_exists_exn state) acc
|
||||||
| Memo m -> loop m.t acc
|
| Memo m -> loop m.t acc
|
||||||
| Catch (t, _) -> loop t acc
|
| Catch (t, _) -> loop t acc
|
||||||
|
| Lazy_no_targets t -> loop (Lazy.force t) acc
|
||||||
in
|
in
|
||||||
fun t -> loop (Build.repr t) String.Map.empty
|
fun t -> loop (Build.repr t) String.Map.empty
|
||||||
|
|
||||||
|
@ -183,6 +196,7 @@ let targets =
|
||||||
end
|
end
|
||||||
| Memo m -> loop m.t acc
|
| Memo m -> loop m.t acc
|
||||||
| Catch (t, _) -> loop t acc
|
| Catch (t, _) -> loop t acc
|
||||||
|
| Lazy_no_targets _ -> acc
|
||||||
in
|
in
|
||||||
fun t -> loop (Build.repr t) []
|
fun t -> loop (Build.repr t) []
|
||||||
|
|
||||||
|
|
|
@ -164,8 +164,7 @@ module Internal_rule = struct
|
||||||
|
|
||||||
type t =
|
type t =
|
||||||
{ id : Id.t
|
{ id : Id.t
|
||||||
; rule_deps : Path.Set.t
|
; static_deps : Build_interpret.Static_deps.t Lazy.t
|
||||||
; static_deps : Path.Set.t
|
|
||||||
; targets : Path.Set.t
|
; targets : Path.Set.t
|
||||||
; context : Context.t option
|
; context : Context.t option
|
||||||
; build : (unit, Action.t) Build.t
|
; build : (unit, Action.t) Build.t
|
||||||
|
@ -178,6 +177,12 @@ module Internal_rule = struct
|
||||||
let compare a b = Id.compare a.id b.id
|
let compare a b = Id.compare a.id b.id
|
||||||
|
|
||||||
let loc ~file_tree ~dir t = rule_loc ~file_tree ~dir ~loc:t.loc
|
let loc ~file_tree ~dir t = rule_loc ~file_tree ~dir ~loc:t.loc
|
||||||
|
|
||||||
|
let lib_deps t =
|
||||||
|
(* Forcing this lazy ensures that the various globs and
|
||||||
|
[if_file_exists] are resolved inside the [Build.t] value. *)
|
||||||
|
ignore (Lazy.force t.static_deps : Build_interpret.Static_deps.t);
|
||||||
|
Build_interpret.lib_deps t.build
|
||||||
end
|
end
|
||||||
|
|
||||||
module File_kind = struct
|
module File_kind = struct
|
||||||
|
@ -250,59 +255,78 @@ module Alias0 = struct
|
||||||
let fully_qualified_name t = Path.relative t.dir t.name
|
let fully_qualified_name t = Path.relative t.dir t.name
|
||||||
|
|
||||||
let stamp_file t =
|
let stamp_file t =
|
||||||
Path.relative (Path.insert_after_build_dir_exn t.dir ".aliases") (t.name ^ suffix)
|
Path.relative (Path.insert_after_build_dir_exn t.dir ".aliases")
|
||||||
|
(t.name ^ suffix)
|
||||||
|
|
||||||
let dep t = Build.path (stamp_file t)
|
let dep t = Build.path (stamp_file t)
|
||||||
|
|
||||||
|
let find_dir_specified_on_command_line ~dir ~file_tree =
|
||||||
|
match File_tree.find_dir file_tree dir with
|
||||||
|
| None ->
|
||||||
|
die "From the command line:\n\
|
||||||
|
@{<error>Error@}: Don't know about directory %s!"
|
||||||
|
(Path.to_string_maybe_quoted dir)
|
||||||
|
| Some dir -> dir
|
||||||
|
|
||||||
|
let dep_multi_contexts ~dir ~name ~file_tree ~contexts =
|
||||||
|
ignore
|
||||||
|
(find_dir_specified_on_command_line ~dir ~file_tree : File_tree.Dir.t);
|
||||||
|
Build.paths (List.map contexts ~f:(fun ctx ->
|
||||||
|
let dir = Path.append (Path.(relative build_dir) ctx) dir in
|
||||||
|
stamp_file (make ~dir name)))
|
||||||
|
|
||||||
let is_standard = function
|
let is_standard = function
|
||||||
| "runtest" | "install" | "doc" | "doc-private" | "lint" -> true
|
| "runtest" | "install" | "doc" | "doc-private" | "lint" | "default" -> true
|
||||||
| _ -> false
|
| _ -> false
|
||||||
|
|
||||||
open Build.O
|
open Build.O
|
||||||
|
|
||||||
let dep_rec_internal ~name ~dir ~ctx_dir =
|
let dep_rec_internal ~name ~dir ~ctx_dir =
|
||||||
File_tree.Dir.fold dir ~traverse_ignored_dirs:false ~init:(Build.return true)
|
Build.lazy_no_targets (lazy (
|
||||||
~f:(fun dir acc ->
|
File_tree.Dir.fold dir ~traverse_ignored_dirs:false
|
||||||
let path = Path.append ctx_dir (File_tree.Dir.path dir) in
|
~init:(Build.return true)
|
||||||
let fn = stamp_file (make ~dir:path name) in
|
~f:(fun dir acc ->
|
||||||
acc
|
let path = Path.append ctx_dir (File_tree.Dir.path dir) in
|
||||||
>>>
|
let fn = stamp_file (make ~dir:path name) in
|
||||||
Build.if_file_exists fn
|
acc
|
||||||
~then_:(Build.path fn >>^ fun _ -> false)
|
>>>
|
||||||
~else_:(Build.arr (fun x -> x)))
|
Build.if_file_exists fn
|
||||||
|
~then_:(Build.path fn >>^ fun _ -> false)
|
||||||
|
~else_:(Build.arr (fun x -> x)))))
|
||||||
|
|
||||||
let dep_rec t ~loc ~file_tree =
|
let dep_rec t ~loc ~file_tree =
|
||||||
let ctx_dir, src_dir = Path.extract_build_context_dir t.dir |> Option.value_exn in
|
let ctx_dir, src_dir =
|
||||||
|
Path.extract_build_context_dir t.dir |> Option.value_exn
|
||||||
|
in
|
||||||
match File_tree.find_dir file_tree src_dir with
|
match File_tree.find_dir file_tree src_dir with
|
||||||
| None -> Build.fail { fail = fun () ->
|
| None ->
|
||||||
Loc.fail loc "Don't know about directory %s!" (Path.to_string_maybe_quoted src_dir) }
|
Build.fail { fail = fun () ->
|
||||||
|
Loc.fail loc "Don't know about directory %s!"
|
||||||
|
(Path.to_string_maybe_quoted src_dir) }
|
||||||
| Some dir ->
|
| Some dir ->
|
||||||
dep_rec_internal ~name:t.name ~dir ~ctx_dir
|
dep_rec_internal ~name:t.name ~dir ~ctx_dir
|
||||||
>>^ fun is_empty ->
|
>>^ fun is_empty ->
|
||||||
if is_empty && not (is_standard t.name) then
|
if is_empty && not (is_standard t.name) then
|
||||||
Loc.fail loc "This alias is empty.\n\
|
Loc.fail loc
|
||||||
Alias %S is not defined in %s or any of its descendants."
|
"This alias is empty.\n\
|
||||||
|
Alias %S is not defined in %s or any of its descendants."
|
||||||
t.name (Path.to_string_maybe_quoted src_dir)
|
t.name (Path.to_string_maybe_quoted src_dir)
|
||||||
|
|
||||||
let dep_rec_multi_contexts ~dir:src_dir ~name ~file_tree ~contexts =
|
let dep_rec_multi_contexts ~dir:src_dir ~name ~file_tree ~contexts =
|
||||||
match File_tree.find_dir file_tree src_dir with
|
let open Build.O in
|
||||||
| None ->
|
let dir = find_dir_specified_on_command_line ~dir:src_dir ~file_tree in
|
||||||
|
Build.all (List.map contexts ~f:(fun ctx ->
|
||||||
|
let ctx_dir = Path.(relative build_dir) ctx in
|
||||||
|
dep_rec_internal ~name ~dir ~ctx_dir))
|
||||||
|
>>^ fun is_empty_list ->
|
||||||
|
let is_empty = List.for_all is_empty_list ~f:(fun x -> x) in
|
||||||
|
if is_empty && not (is_standard name) then
|
||||||
die "From the command line:\n\
|
die "From the command line:\n\
|
||||||
@{<error>Error@}: Don't know about directory %s!" (Path.to_string_maybe_quoted src_dir)
|
@{<error>Error@}: Alias %S is empty.\n\
|
||||||
| Some dir ->
|
It is not defined in %s or any of its descendants."
|
||||||
let open Build.O in
|
name (Path.to_string_maybe_quoted src_dir)
|
||||||
Build.all (List.map contexts ~f:(fun ctx ->
|
|
||||||
let ctx_dir = Path.(relative build_dir) ctx in
|
|
||||||
dep_rec_internal ~name ~dir ~ctx_dir))
|
|
||||||
>>^ fun is_empty_list ->
|
|
||||||
let is_empty = List.for_all is_empty_list ~f:(fun x -> x) in
|
|
||||||
if is_empty && not (is_standard name) then
|
|
||||||
die "From the command line:\n\
|
|
||||||
@{<error>Error@}: Alias %s is empty.\n\
|
|
||||||
It is not defined in %s or any of its descendants."
|
|
||||||
name (Path.to_string_maybe_quoted src_dir)
|
|
||||||
|
|
||||||
let default = make "DEFAULT"
|
let default = make "default"
|
||||||
let runtest = make "runtest"
|
let runtest = make "runtest"
|
||||||
let install = make "install"
|
let install = make "install"
|
||||||
let doc = make "doc"
|
let doc = make "doc"
|
||||||
|
@ -502,6 +526,8 @@ module Build_exec = struct
|
||||||
with exn ->
|
with exn ->
|
||||||
on_error exn
|
on_error exn
|
||||||
end
|
end
|
||||||
|
| Lazy_no_targets t ->
|
||||||
|
exec dyn_deps (Lazy.force t) x
|
||||||
| Memo m ->
|
| Memo m ->
|
||||||
match m.state with
|
match m.state with
|
||||||
| Evaluated (x, deps) ->
|
| Evaluated (x, deps) ->
|
||||||
|
@ -659,9 +685,9 @@ let no_rule_found =
|
||||||
die "No rule found for %s" (Utils.describe_target fn)
|
die "No rule found for %s" (Utils.describe_target fn)
|
||||||
in
|
in
|
||||||
fun t fn ->
|
fun t fn ->
|
||||||
match Path.extract_build_context fn with
|
match Utils.analyse_target fn with
|
||||||
| None -> fail fn
|
| Other _ -> fail fn
|
||||||
| Some (ctx, _) ->
|
| Regular (ctx, _) ->
|
||||||
if String.Map.mem t.contexts ctx then
|
if String.Map.mem t.contexts ctx then
|
||||||
fail fn
|
fail fn
|
||||||
else
|
else
|
||||||
|
@ -669,6 +695,15 @@ let no_rule_found =
|
||||||
(Path.to_string_maybe_quoted fn)
|
(Path.to_string_maybe_quoted fn)
|
||||||
ctx
|
ctx
|
||||||
(hint ctx (String.Map.keys t.contexts))
|
(hint ctx (String.Map.keys t.contexts))
|
||||||
|
| Alias (ctx, fn') ->
|
||||||
|
if String.Map.mem t.contexts ctx then
|
||||||
|
fail fn
|
||||||
|
else
|
||||||
|
let fn = Path.append (Path.relative Path.build_dir ctx) fn' in
|
||||||
|
die "Trying to build alias %s but build context %s doesn't exist.%s"
|
||||||
|
(Path.to_string_maybe_quoted fn)
|
||||||
|
ctx
|
||||||
|
(hint ctx (String.Map.keys t.contexts))
|
||||||
|
|
||||||
let rec compile_rule t ?(copy_source=false) pre_rule =
|
let rec compile_rule t ?(copy_source=false) pre_rule =
|
||||||
let { Pre_rule.
|
let { Pre_rule.
|
||||||
|
@ -684,20 +719,19 @@ let rec compile_rule t ?(copy_source=false) pre_rule =
|
||||||
pre_rule
|
pre_rule
|
||||||
in
|
in
|
||||||
let targets = Target.paths target_specs in
|
let targets = Target.paths target_specs in
|
||||||
let { Build_interpret.Static_deps.
|
let static_deps =
|
||||||
rule_deps
|
lazy (Build_interpret.static_deps build ~all_targets:(targets_of t)
|
||||||
; action_deps = static_deps
|
~file_tree:t.file_tree)
|
||||||
} = Build_interpret.static_deps build ~all_targets:(targets_of t)
|
|
||||||
~file_tree:t.file_tree
|
|
||||||
in
|
in
|
||||||
|
|
||||||
let eval_rule () =
|
let eval_rule () =
|
||||||
t.hook Rule_started;
|
t.hook Rule_started;
|
||||||
wait_for_deps t rule_deps
|
wait_for_deps t (Lazy.force static_deps).rule_deps
|
||||||
>>| fun () ->
|
>>| fun () ->
|
||||||
Build_exec.exec t build ()
|
Build_exec.exec t build ()
|
||||||
in
|
in
|
||||||
let exec_rule (rule_evaluation : Exec_status.rule_evaluation) =
|
let exec_rule (rule_evaluation : Exec_status.rule_evaluation) =
|
||||||
|
let static_deps = (Lazy.force static_deps).action_deps in
|
||||||
Fiber.fork_and_join_unit
|
Fiber.fork_and_join_unit
|
||||||
(fun () ->
|
(fun () ->
|
||||||
wait_for_deps t static_deps)
|
wait_for_deps t static_deps)
|
||||||
|
@ -801,7 +835,6 @@ let rec compile_rule t ?(copy_source=false) pre_rule =
|
||||||
{ Internal_rule.
|
{ Internal_rule.
|
||||||
id = Internal_rule.Id.gen ()
|
id = Internal_rule.Id.gen ()
|
||||||
; static_deps
|
; static_deps
|
||||||
; rule_deps
|
|
||||||
; targets
|
; targets
|
||||||
; build
|
; build
|
||||||
; context
|
; context
|
||||||
|
@ -889,7 +922,27 @@ and load_dir_step2_exn t ~dir ~collector ~lazy_generators =
|
||||||
let alias_dir = Path.append (Path.relative alias_dir context_name) sub_dir in
|
let alias_dir = Path.append (Path.relative alias_dir context_name) sub_dir in
|
||||||
let alias_rules, alias_stamp_files =
|
let alias_rules, alias_stamp_files =
|
||||||
let open Build.O in
|
let open Build.O in
|
||||||
String.Map.foldi collector.aliases ~init:([], Path.Set.empty)
|
let aliases = collector.aliases in
|
||||||
|
let aliases =
|
||||||
|
if String.Map.mem collector.aliases "default" then
|
||||||
|
aliases
|
||||||
|
else
|
||||||
|
match Path.extract_build_context_dir dir with
|
||||||
|
| None -> aliases
|
||||||
|
| Some (ctx_dir, src_dir) ->
|
||||||
|
match File_tree.find_dir t.file_tree src_dir with
|
||||||
|
| None -> aliases
|
||||||
|
| Some dir ->
|
||||||
|
String.Map.add aliases "default"
|
||||||
|
{ deps = Path.Set.empty
|
||||||
|
; dyn_deps =
|
||||||
|
(Alias0.dep_rec_internal ~name:"install" ~dir ~ctx_dir
|
||||||
|
>>^ fun (_ : bool) ->
|
||||||
|
Path.Set.empty)
|
||||||
|
; actions = []
|
||||||
|
}
|
||||||
|
in
|
||||||
|
String.Map.foldi aliases ~init:([], Path.Set.empty)
|
||||||
~f:(fun name { Dir_status. deps; dyn_deps; actions } (rules, alias_stamp_files) ->
|
~f:(fun name { Dir_status. deps; dyn_deps; actions } (rules, alias_stamp_files) ->
|
||||||
let base_path = Path.relative alias_dir name in
|
let base_path = Path.relative alias_dir name in
|
||||||
let rules, deps =
|
let rules, deps =
|
||||||
|
@ -1251,7 +1304,8 @@ let rules_for_targets t targets =
|
||||||
Internal_rule.Id.Top_closure.top_closure (rules_for_files t targets)
|
Internal_rule.Id.Top_closure.top_closure (rules_for_files t targets)
|
||||||
~key:(fun (r : Internal_rule.t) -> r.id)
|
~key:(fun (r : Internal_rule.t) -> r.id)
|
||||||
~deps:(fun (r : Internal_rule.t) ->
|
~deps:(fun (r : Internal_rule.t) ->
|
||||||
rules_for_files t (Path.Set.union r.static_deps r.rule_deps))
|
let x = Lazy.force r.static_deps in
|
||||||
|
rules_for_files t (Path.Set.union x.action_deps x.rule_deps))
|
||||||
with
|
with
|
||||||
| Ok l -> l
|
| Ok l -> l
|
||||||
| Error cycle ->
|
| Error cycle ->
|
||||||
|
@ -1273,8 +1327,8 @@ let static_deps_of_request t request =
|
||||||
let all_lib_deps t ~request =
|
let all_lib_deps t ~request =
|
||||||
let targets = static_deps_of_request t request in
|
let targets = static_deps_of_request t request in
|
||||||
List.fold_left (rules_for_targets t targets) ~init:Path.Map.empty
|
List.fold_left (rules_for_targets t targets) ~init:Path.Map.empty
|
||||||
~f:(fun acc (rule : Internal_rule.t) ->
|
~f:(fun acc rule ->
|
||||||
let deps = Build_interpret.lib_deps rule.build in
|
let deps = Internal_rule.lib_deps rule in
|
||||||
if String.Map.is_empty deps then
|
if String.Map.is_empty deps then
|
||||||
acc
|
acc
|
||||||
else
|
else
|
||||||
|
@ -1288,8 +1342,8 @@ let all_lib_deps t ~request =
|
||||||
let all_lib_deps_by_context t ~request =
|
let all_lib_deps_by_context t ~request =
|
||||||
let targets = static_deps_of_request t request in
|
let targets = static_deps_of_request t request in
|
||||||
let rules = rules_for_targets t targets in
|
let rules = rules_for_targets t targets in
|
||||||
List.fold_left rules ~init:[] ~f:(fun acc (rule : Internal_rule.t) ->
|
List.fold_left rules ~init:[] ~f:(fun acc rule ->
|
||||||
let deps = Build_interpret.lib_deps rule.build in
|
let deps = Internal_rule.lib_deps rule in
|
||||||
if String.Map.is_empty deps then
|
if String.Map.is_empty deps then
|
||||||
acc
|
acc
|
||||||
else
|
else
|
||||||
|
@ -1358,9 +1412,10 @@ let build_rules_internal ?(recursive=false) t ~request =
|
||||||
Fiber.fork (fun () ->
|
Fiber.fork (fun () ->
|
||||||
Fiber.Future.wait rule_evaluation
|
Fiber.Future.wait rule_evaluation
|
||||||
>>| fun (action, dyn_deps) ->
|
>>| fun (action, dyn_deps) ->
|
||||||
|
let static_deps = (Lazy.force ir.static_deps).action_deps in
|
||||||
{ Rule.
|
{ Rule.
|
||||||
id = ir.id
|
id = ir.id
|
||||||
; deps = Path.Set.union ir.static_deps dyn_deps
|
; deps = Path.Set.union static_deps dyn_deps
|
||||||
; targets = ir.targets
|
; targets = ir.targets
|
||||||
; context = ir.context
|
; context = ir.context
|
||||||
; action = action
|
; action = action
|
||||||
|
@ -1437,7 +1492,9 @@ let package_deps t pkg files =
|
||||||
Option.value_exn (Fiber.Future.peek rule_evaluation)
|
Option.value_exn (Fiber.Future.peek rule_evaluation)
|
||||||
| Not_started _ -> assert false
|
| Not_started _ -> assert false
|
||||||
in
|
in
|
||||||
Path.Set.fold (Path.Set.union ir.static_deps dyn_deps) ~init:acc ~f:loop
|
Path.Set.fold
|
||||||
|
(Path.Set.union (Lazy.force ir.static_deps).action_deps dyn_deps)
|
||||||
|
~init:acc ~f:loop
|
||||||
end
|
end
|
||||||
in
|
in
|
||||||
let open Build.O in
|
let open Build.O in
|
||||||
|
|
|
@ -129,6 +129,14 @@ module Alias : sig
|
||||||
(** [dep t = Build.path (stamp_file t)] *)
|
(** [dep t = Build.path (stamp_file t)] *)
|
||||||
val dep : t -> ('a, 'a) Build.t
|
val dep : t -> ('a, 'a) Build.t
|
||||||
|
|
||||||
|
(** Implements [@@alias] on the command line *)
|
||||||
|
val dep_multi_contexts
|
||||||
|
: dir:Path.t
|
||||||
|
-> name:string
|
||||||
|
-> file_tree:File_tree.t
|
||||||
|
-> contexts:string list
|
||||||
|
-> (unit, unit) Build.t
|
||||||
|
|
||||||
(** Implements [(alias_rec ...)] in dependency specification *)
|
(** Implements [(alias_rec ...)] in dependency specification *)
|
||||||
val dep_rec
|
val dep_rec
|
||||||
: t
|
: t
|
||||||
|
|
|
@ -271,6 +271,26 @@ module Unexpanded = struct
|
||||||
in
|
in
|
||||||
loop t.ast
|
loop t.ast
|
||||||
|
|
||||||
|
type position = Pos | Neg
|
||||||
|
|
||||||
|
let fold_strings t ~init ~f =
|
||||||
|
let rec loop (t : ast) pos acc =
|
||||||
|
let open Ast in
|
||||||
|
match t with
|
||||||
|
| Standard | Include _ -> acc
|
||||||
|
| Element x -> f pos x acc
|
||||||
|
| Union l -> List.fold_left l ~init:acc ~f:(fun acc x -> loop x pos acc)
|
||||||
|
| Diff (l, r) ->
|
||||||
|
let acc = loop l pos acc in
|
||||||
|
let pos =
|
||||||
|
match pos with
|
||||||
|
| Pos -> Neg
|
||||||
|
| Neg -> Pos
|
||||||
|
in
|
||||||
|
loop r pos acc
|
||||||
|
in
|
||||||
|
loop t.ast Pos init
|
||||||
|
|
||||||
let expand t ~files_contents ~f =
|
let expand t ~files_contents ~f =
|
||||||
let context = t.context in
|
let context = t.context in
|
||||||
let rec expand (t : ast) : ast_expanded =
|
let rec expand (t : ast) : ast_expanded =
|
||||||
|
|
|
@ -76,6 +76,17 @@ module Unexpanded : sig
|
||||||
-> files_contents:Sexp.Ast.t String.Map.t
|
-> files_contents:Sexp.Ast.t String.Map.t
|
||||||
-> f:(String_with_vars.t -> string)
|
-> f:(String_with_vars.t -> string)
|
||||||
-> expanded
|
-> expanded
|
||||||
|
|
||||||
|
type position = Pos | Neg
|
||||||
|
|
||||||
|
(** Fold a function over all strings in a set. The callback receive
|
||||||
|
whether the string is in position or negative position, i.e. on
|
||||||
|
the left or right of a [\] operator. *)
|
||||||
|
val fold_strings
|
||||||
|
: t
|
||||||
|
-> init:'a
|
||||||
|
-> f:(position -> String_with_vars.t -> 'a -> 'a)
|
||||||
|
-> 'a
|
||||||
end with type expanded := t
|
end with type expanded := t
|
||||||
|
|
||||||
module String : S with type value = string and type 'a map = 'a String.Map.t
|
module String : S with type value = string and type 'a map = 'a String.Map.t
|
||||||
|
|
|
@ -272,3 +272,8 @@ let is_var { template; syntax_version = _ } ~name =
|
||||||
match template.parts with
|
match template.parts with
|
||||||
| [Var n] -> name = Var.full_name n
|
| [Var n] -> name = Var.full_name n
|
||||||
| _ -> false
|
| _ -> false
|
||||||
|
|
||||||
|
let text_only t =
|
||||||
|
match t.template.parts with
|
||||||
|
| [Text s] -> Some s
|
||||||
|
| _ -> None
|
||||||
|
|
|
@ -30,6 +30,9 @@ val virt_text : (string * int * int * int) -> string -> t
|
||||||
|
|
||||||
val is_var : t -> name:string -> bool
|
val is_var : t -> name:string -> bool
|
||||||
|
|
||||||
|
(** If [t] contains no variable, returns the contents of [t]. *)
|
||||||
|
val text_only : t -> string option
|
||||||
|
|
||||||
module Mode : sig
|
module Mode : sig
|
||||||
type 'a t =
|
type 'a t =
|
||||||
| Single : Value.t t
|
| Single : Value.t t
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
running in src
|
running in src
|
||||||
$ dune build --display short @plop
|
$ dune build --display short @plop
|
||||||
From the command line:
|
From the command line:
|
||||||
Error: Alias plop is empty.
|
Error: Alias "plop" is empty.
|
||||||
It is not defined in . or any of its descendants.
|
It is not defined in . or any of its descendants.
|
||||||
[1]
|
[1]
|
||||||
$ dune build --display short @truc/x
|
$ dune build --display short @truc/x
|
||||||
|
|
|
@ -1,33 +1,4 @@
|
||||||
$ dune runtest --display short
|
$ dune runtest
|
||||||
ocamldep .bar.eobjs/bar.ml.d
|
|
||||||
ocamldep .foo.objs/foo.ml.d
|
|
||||||
ocamldep .foo.objs/foo.mli.d
|
|
||||||
ocamlc .foo.objs/foo.{cmi,cmti}
|
|
||||||
ocamlopt .foo.objs/foo.{cmx,o}
|
|
||||||
ocamlopt foo.{a,cmxa}
|
|
||||||
ocamlopt foo.cmxs
|
|
||||||
ocamldep .foo_byte.objs/foo_byte.ml.d
|
|
||||||
ocamlc .foo_byte.objs/foo_byte.{cmi,cmo,cmt}
|
|
||||||
ocamlc foo_byte.cma
|
|
||||||
ocamldep ppx-new/.foo_ppx_rewriter_dune.objs/foo_ppx_rewriter_dune.ml.d
|
|
||||||
ocamlc ppx-new/.foo_ppx_rewriter_dune.objs/foo_ppx_rewriter_dune.{cmi,cmo,cmt}
|
|
||||||
ocamlopt ppx-new/.foo_ppx_rewriter_dune.objs/foo_ppx_rewriter_dune.{cmx,o}
|
|
||||||
ocamlopt ppx-new/foo_ppx_rewriter_dune.{a,cmxa}
|
|
||||||
ocamlopt ppx-new/foo_ppx_rewriter_dune.cmxs
|
|
||||||
ocamldep ppx-old/.foo_ppx_rewriter_jbuild.objs/foo_ppx_rewriter_jbuild.ml.d
|
|
||||||
ocamlc ppx-old/.foo_ppx_rewriter_jbuild.objs/foo_ppx_rewriter_jbuild.{cmi,cmo,cmt}
|
|
||||||
ocamlopt ppx-old/.foo_ppx_rewriter_jbuild.objs/foo_ppx_rewriter_jbuild.{cmx,o}
|
|
||||||
ocamlopt ppx-old/foo_ppx_rewriter_jbuild.{a,cmxa}
|
|
||||||
ocamlopt ppx-old/foo_ppx_rewriter_jbuild.cmxs
|
|
||||||
ocamlc .foo.objs/foo.{cmo,cmt}
|
|
||||||
ocamlc foo.cma
|
|
||||||
ocamlc .bar.eobjs/bar.{cmi,cmo,cmt}
|
|
||||||
ocamlopt .bar.eobjs/bar.{cmx,o}
|
|
||||||
ocamlopt bar.exe
|
|
||||||
ocamlc ppx-new/foo_ppx_rewriter_dune.cma
|
|
||||||
ocamlopt .ppx/foo.ppx_rewriter_dune/ppx.exe
|
|
||||||
ocamlc ppx-old/foo_ppx_rewriter_jbuild.cma
|
|
||||||
ocamlopt .ppx/jbuild/foo.ppx_rewriter_jbuild/ppx.exe
|
|
||||||
lib: [
|
lib: [
|
||||||
"_build/install/default/lib/foo/META" {"META"}
|
"_build/install/default/lib/foo/META" {"META"}
|
||||||
"_build/install/default/lib/foo/opam" {"opam"}
|
"_build/install/default/lib/foo/opam" {"opam"}
|
||||||
|
|
Loading…
Reference in New Issue