Add ${!^} and ${!@} and document them

This commit is contained in:
Jeremie Dimino 2017-05-29 19:12:37 +01:00
parent 3241026fff
commit a8a43e4b22
4 changed files with 74 additions and 19 deletions

View File

@ -523,9 +523,11 @@ Jbuilder supports the following variables:
In addition, ``(action ...)`` fields support the following special variables:
- ``@`` expands to the list of target, separated by spaces
- ``!@`` same as ``@`` but with a split semantic (see below)
- ``<`` expands to the first dependency, or the empty string if there are no
dependencies
- ``^`` expands to the list of dependencies, separated by spaces
- ``!^`` same as ``^`` but with a split semantic (see below)
- ``path:<path>`` expands to ``<path>``
- ``exe:<path>`` is the same as ``<path>``, except when cross-compiling, in
which case it will expand to ``<path>`` from the host build context
@ -558,6 +560,39 @@ transparently whether things are installed or not.
Note that aliases are ignored by both ``${<}`` and ``${^}``.
Moreover ``${^}`` and ``${@}`` will always expand to a single
string. For instance in:
.. code:: scheme
(run foo ${^})
even if there are two dependencies ``a`` and ``b``, the produced
command will be equivalent to the shell command:
.. code:: shell
$ foo "a b"
In order to *split* them, you can use ``${!^}`` and ``${!@}``. These
two forms are only available in ``(run ...)`` forms and can only be
used as a whole atom, i.e. they can't be used inside a quoted
atom. Replacing ``${^}`` by ``${!^}`` in the previous example would
produce a command equivalent to this shell command:
.. code:: shell
$ foo "a" "b"
You can also use ``${!^}`` as program name, for instance:
.. code:: scheme
(rule
((targets (result.txt))
(deps (foo.exe (glob_files *.txt)))
(action (run ${!^}))))
Library dependencies
--------------------

View File

@ -3,10 +3,12 @@ open Sexp.Of_sexp
module Env_var_map = Context.Env_var_map
type split_or_concat = Split | Concat
type var_expansion =
| Not_found
| Path of Path.t
| Paths of Path.t list
| Paths of Path.t list * split_or_concat
| Str of string
let expand_str ~dir ~f template =
@ -14,9 +16,21 @@ let expand_str ~dir ~f template =
match f var with
| Not_found -> None
| Path path -> Some (Path.reach ~from:dir path)
| Paths l -> Some (List.map l ~f:(Path.reach ~from:dir) |> String.concat ~sep:" ")
| Paths (l, _) -> Some (List.map l ~f:(Path.reach ~from:dir) |> String.concat ~sep:" ")
| Str s -> Some s)
let expand_str_split ~dir ~f template =
match String_with_vars.just_a_var template with
| None -> [expand_str ~dir ~f template]
| Some var ->
match f var with
| Not_found -> [expand_str ~dir ~f template]
| Path path -> [Path.reach ~from:dir path]
| Str s -> [s]
| Paths (l, Concat) ->
[List.map l ~f:(Path.reach ~from:dir) |> String.concat ~sep:" "]
| Paths (l, Split) -> List.map l ~f:(Path.reach ~from:dir)
let expand_path ~dir ~f template =
match String_with_vars.just_a_var template with
| None -> expand_str ~dir ~f template |> Path.relative dir
@ -24,9 +38,9 @@ let expand_path ~dir ~f template =
match f v with
| Not_found -> expand_str ~dir ~f template |> Path.relative dir
| Path p
| Paths [p] -> p
| Paths ([p], _) -> p
| Str s -> Path.relative dir s
| Paths l ->
| Paths (l, _) ->
List.map l ~f:(Path.reach ~from:dir)
|> String.concat ~sep:" "
|> Path.relative dir
@ -41,17 +55,19 @@ let expand_prog ctx ~dir ~f template =
| None -> Utils.program_not_found ~context:ctx.name s
in
match String_with_vars.just_a_var template with
| None -> resolve (expand_str ~dir ~f template)
| None -> (resolve (expand_str ~dir ~f template), [])
| Some v ->
match f v with
| Not_found -> resolve (expand_str ~dir ~f template)
| Not_found -> (resolve (expand_str ~dir ~f template), [])
| Path p
| Paths [p] -> p
| Str s -> resolve s
| Paths l ->
List.map l ~f:(Path.reach ~from:dir)
|> String.concat ~sep:" "
|> resolve
| Paths ([p], _) -> (p, [])
| Str s -> (resolve s, [])
| Paths (p :: args, Split) -> (p, List.map args ~f:(Path.reach ~from:dir))
| Paths (l, _) ->
(List.map l ~f:(Path.reach ~from:dir)
|> String.concat ~sep:" "
|> resolve,
[])
module Outputs = struct
include Action_intf.Outputs
@ -197,8 +213,9 @@ module Unexpanded = struct
let rec expand ctx dir t ~f : action =
match t with
| Run (prog, args) ->
Run (expand_prog ctx ~dir ~f prog,
List.map args ~f:(fun arg -> expand_str ~dir ~f arg))
let prog, more_args = expand_prog ctx ~dir ~f prog in
Run (prog,
more_args @ List.concat_map args ~f:(expand_str_split ~dir ~f))
| Chdir (fn, t) ->
let fn = expand_path ~dir ~f fn in
Chdir (fn, expand ctx fn t ~f)

View File

@ -1,9 +1,11 @@
open! Import
type split_or_concat = Split | Concat
type var_expansion =
| Not_found
| Path of Path.t
| Paths of Path.t list
| Paths of Path.t list * split_or_concat
| Str of string
module Outputs : module type of struct include Action_intf.Outputs end

View File

@ -550,13 +550,14 @@ module Action = struct
| Some exp -> exp
| None ->
match var_name with
| "@" -> Action.Paths targets
| "@" -> Action.Paths (targets, Concat)
| "!@" -> Action.Paths (targets, Split)
| "<" ->
(match deps with
| [] -> Str "" (* CR-someday jdimino: this should be an error *)
| dep :: _ -> Path dep)
| "^" ->
Paths deps
| "^" -> Paths (deps, Concat)
| "!^" -> Paths (deps, Split)
| "ROOT" -> Path sctx.context.build_dir
| var ->
match expand_var_no_root sctx var with
@ -574,7 +575,7 @@ module Action = struct
~f:(fun ~key:_ ~data:exp acc ->
match exp with
| Action.Path p -> Path.Set.add p acc
| Paths ps -> Path.Set.union acc (Path.Set.of_list ps)
| Paths (ps, _) -> Path.Set.union acc (Path.Set.of_list ps)
| Not_found | Str _ -> acc))
>>>
Build.arr (fun paths -> ((), paths))