Merge pull request #1011 from rgrinberg/refactor-expander-osl

Refactor var expansion
This commit is contained in:
Rudi Grinberg 2018-07-13 16:56:18 +02:00 committed by GitHub
commit 3c639a9be7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 302 additions and 230 deletions

View File

@ -83,7 +83,7 @@ module Unexpanded : sig
: t : t
-> dir:Path.t -> dir:Path.t
-> map_exe:(Path.t -> Path.t) -> map_exe:(Path.t -> Path.t)
-> f:(String_with_vars.Var.t -> Syntax.Version.t -> Value.t list option) -> f:(Value.t list option String_with_vars.expander)
-> Unresolved.t -> Unresolved.t
end end
@ -91,7 +91,7 @@ module Unexpanded : sig
: t : t
-> dir:Path.t -> dir:Path.t
-> map_exe:(Path.t -> Path.t) -> map_exe:(Path.t -> Path.t)
-> f:(String_with_vars.Var.t -> Syntax.Version.t -> Value.t list option) -> f:(Value.t list option String_with_vars.expander)
-> Partial.t -> Partial.t
end end

View File

@ -10,6 +10,10 @@ module Ast = struct
| Union : ('a, 'b) t list -> ('a, 'b) t | Union : ('a, 'b) t list -> ('a, 'b) t
| Diff : ('a, 'b) t * ('a, 'b) t -> ('a, 'b) t | Diff : ('a, 'b) t * ('a, 'b) t -> ('a, 'b) t
| Include : String_with_vars.t -> ('a, unexpanded) t | Include : String_with_vars.t -> ('a, unexpanded) t
let union = function
| [x] -> x
| xs -> Union xs
end end
type 'ast generic = type 'ast generic =
@ -32,7 +36,7 @@ module Parse = struct
peek_exn >>= function peek_exn >>= function
| Atom (loc, A "\\") -> Loc.fail loc "unexpected \\" | Atom (loc, A "\\") -> Loc.fail loc "unexpected \\"
| (Atom (_, A "") | Quoted_string (_, _)) | Template _ -> | (Atom (_, A "") | Quoted_string (_, _)) | Template _ ->
elt >>| fun x -> Element x elt
| Atom (loc, A s) -> begin | Atom (loc, A s) -> begin
match s with match s with
| ":standard" -> | ":standard" ->
@ -43,7 +47,7 @@ module Parse = struct
| _ when s.[0] = ':' -> | _ when s.[0] = ':' ->
Loc.fail loc "undefined symbol %s" s Loc.fail loc "undefined symbol %s" s
| _ -> | _ ->
elt >>| fun x -> Element x elt
end end
| List (_, Atom (loc, A s) :: _) -> begin | List (_, Atom (loc, A s) :: _) -> begin
match s, kind with match s, kind with
@ -88,7 +92,8 @@ end
let t = let t =
let open Stanza.Of_sexp in let open Stanza.Of_sexp in
get_all >>= fun context -> get_all >>= fun context ->
located (Parse.without_include ~elt:(plain_string (fun ~loc s -> (loc, s)))) located (Parse.without_include
~elt:(plain_string (fun ~loc s -> Ast.Element (loc, s))))
>>| fun (loc, ast) -> >>| fun (loc, ast) ->
{ ast; loc = Some loc; context } { ast; loc = Some loc; context }
@ -210,10 +215,12 @@ let field ?(default=standard) name = Sexp.Of_sexp.field name t ~default
module Unexpanded = struct module Unexpanded = struct
type ast = (String_with_vars.t, Ast.unexpanded) Ast.t type ast = (String_with_vars.t, Ast.unexpanded) Ast.t
type t = ast generic type t = ast generic
let t = let t : t Sexp.Of_sexp.t =
let open Stanza.Of_sexp in let open Stanza.Of_sexp in
get_all >>= fun context -> get_all >>= fun context ->
located (Parse.with_include ~elt:String_with_vars.t) located (
Parse.with_include
~elt:(String_with_vars.t >>| fun s -> Ast.Element s))
>>| fun (loc, ast) -> >>| fun (loc, ast) ->
{ ast { ast
; loc = Some loc ; loc = Some loc
@ -239,12 +246,11 @@ module Unexpanded = struct
let field ?(default=standard) name = Stanza.Of_sexp.field name t ~default let field ?(default=standard) name = Stanza.Of_sexp.field name t ~default
let files t ~f = let files t ~f =
let rec loop acc (t : ast) = let rec loop acc (ast : ast) =
let open Ast in let open Ast in
match t with match ast with
| Element _ | Standard -> acc | Element _ | Standard -> acc
| Include fn -> | Include fn -> Path.Set.add acc (f fn)
String.Set.add acc (f fn)
| Union l -> | Union l ->
List.fold_left l ~init:acc ~f:loop List.fold_left l ~init:acc ~f:loop
| Diff (l, r) -> | Diff (l, r) ->
@ -255,7 +261,7 @@ module Unexpanded = struct
| Some (0, _)-> File_tree.Dune_file.Kind.Jbuild | Some (0, _)-> File_tree.Dune_file.Kind.Jbuild
| None | Some (_, _) -> Dune | None | Some (_, _) -> Dune
in in
(syntax, loop String.Set.empty t.ast) (syntax, loop Path.Set.empty t.ast)
let has_special_forms t = let has_special_forms t =
let rec loop (t : ast) = let rec loop (t : ast) =
@ -291,31 +297,41 @@ module Unexpanded = struct
in in
loop t.ast Pos init loop t.ast Pos init
let expand t ~files_contents ~f = let expand t ~dir ~files_contents ~(f : String_with_vars.t -> Value.t list) =
let context = t.context in let context = t.context in
let f_elems s =
let loc = String_with_vars.loc s in
Ast.union
(List.map (f s) ~f:(fun s -> Ast.Element (loc, Value.to_string ~dir s)))
in
let rec expand (t : ast) : ast_expanded = let rec expand (t : ast) : ast_expanded =
let open Ast in let open Ast in
match t with match t with
| Element s -> Element (String_with_vars.loc s, f s) | Element s -> f_elems s
| Standard -> Standard | Standard -> Standard
| Include fn -> | Include fn ->
let sexp = let sexp =
let fn = f fn in let path =
match String.Map.find files_contents fn with match f fn with
| [x] -> Value.to_path ~dir x
| _ ->
Loc.fail (String_with_vars.loc fn)
"An unquoted templated expanded to more than one value. \
A file path is expected in this position."
in
match Path.Map.find files_contents path with
| Some x -> x | Some x -> x
| None -> | None ->
Exn.code_error Exn.code_error
"Ordered_set_lang.Unexpanded.expand" "Ordered_set_lang.Unexpanded.expand"
[ "included-file", Quoted_string fn [ "included-file", Path.sexp_of_t path
; "files", Sexp.To_sexp.(list string) ; "files", Sexp.To_sexp.(list Path.sexp_of_t)
(String.Map.keys files_contents) (Path.Map.keys files_contents)
] ]
in in
let open Stanza.Of_sexp in let open Stanza.Of_sexp in
parse parse
(Parse.without_include (Parse.without_include ~elt:(String_with_vars.t >>| f_elems))
~elt:(String_with_vars.t >>| fun s ->
(String_with_vars.loc s, f s)))
context context
sexp sexp
| Union l -> Union (List.map l ~f:expand) | Union l -> Union (List.map l ~f:expand)

View File

@ -65,16 +65,17 @@ module Unexpanded : sig
(** List of files needed to expand this set *) (** List of files needed to expand this set *)
val files val files
: t : t
-> f:(String_with_vars.t -> string) -> f:(String_with_vars.t -> Path.t)
-> Sexp.syntax * String.Set.t -> Sexp.syntax * Path.Set.t
(** Expand [t] using with the given file contents. [file_contents] is a map from (** Expand [t] using with the given file contents. [file_contents] is a map from
filenames to their parsed contents. Every [(:include fn)] in [t] is replaced by filenames to their parsed contents. Every [(:include fn)] in [t] is replaced by
[Map.find files_contents fn]. Every element is converted to a string using [f]. *) [Map.find files_contents fn]. Every element is converted to a string using [f]. *)
val expand val expand
: t : t
-> files_contents:Sexp.Ast.t String.Map.t -> dir:Path.t
-> f:(String_with_vars.t -> string) -> files_contents:Sexp.Ast.t Path.Map.t
-> f:(String_with_vars.t -> Value.t list)
-> expanded -> expanded
type position = Pos | Neg type position = Pos | Neg

View File

@ -187,7 +187,7 @@ module Map = struct
Syntax.Error.deleted_in (String_with_vars.Var.loc pform) Syntax.Error.deleted_in (String_with_vars.Var.loc pform)
Stanza.syntax syntax_version ~what:(describe pform) ?repl Stanza.syntax syntax_version ~what:(describe pform) ?repl
let expand t ~syntax_version ~pform = let expand t pform syntax_version =
match String_with_vars.Var.payload pform with match String_with_vars.Var.payload pform with
| None -> | None ->
Option.map (expand t.vars ~syntax_version ~pform) ~f:(fun x -> Option.map (expand t.vars ~syntax_version ~pform) ~f:(fun x ->

View File

@ -48,11 +48,7 @@ module Map : sig
val input_file : Path.t -> t val input_file : Path.t -> t
val expand val expand : t -> Expansion.t option String_with_vars.expander
: t
-> syntax_version:Syntax.Version.t
-> pform:String_with_vars.Var.t
-> Expansion.t option
val empty : t val empty : t
end end

View File

@ -158,7 +158,7 @@ let concat_rev = function
| l -> String.concat (List.rev l) ~sep:"" | l -> String.concat (List.rev l) ~sep:""
module Mode = struct module Mode = struct
type 'a t = type _ t =
| Single : Value.t t | Single : Value.t t
| Many : Value.t list t | Many : Value.t list t
@ -264,6 +264,8 @@ let partial_expand
end end
| _ -> loop [] [] template.parts | _ -> loop [] [] template.parts
type 'a expander = Var.t -> Syntax.Version.t -> 'a
let expand t ~mode ~dir ~f = let expand t ~mode ~dir ~f =
match match
partial_expand t ~mode ~dir ~f:(fun var syntax_version -> partial_expand t ~mode ~dir ~f:(fun var syntax_version ->

View File

@ -35,7 +35,7 @@ val is_var : t -> name:string -> bool
val text_only : t -> string option val text_only : t -> string option
module Mode : sig module Mode : sig
type 'a t = type _ t =
| Single : Value.t t | Single : Value.t t
| Many : Value.t list t | Many : Value.t list t
end end
@ -64,16 +64,18 @@ module Var : sig
val describe : t -> string val describe : t -> string
end end
type 'a expander = Var.t -> Syntax.Version.t -> 'a
val expand val expand
: t : t
-> mode:'a Mode.t -> mode:'a Mode.t
-> dir:Path.t -> dir:Path.t
-> f:(Var.t -> Syntax.Version.t -> Value.t list option) -> f:(Value.t list option expander)
-> 'a -> 'a
val partial_expand val partial_expand
: t : t
-> mode:'a Mode.t -> mode:'a Mode.t
-> dir:Path.t -> dir:Path.t
-> f:(Var.t -> Syntax.Version.t -> Value.t list option) -> f:(Value.t list option expander)
-> 'a Partial.t -> 'a Partial.t

View File

@ -95,50 +95,49 @@ let expand_ocaml_config t pform name =
"Unknown ocaml configuration variable %S" "Unknown ocaml configuration variable %S"
name name
let (expand_vars_string, expand_vars_path) = let expand_vars t ~mode ~scope ~dir ?(bindings=Pform.Map.empty) s =
let expand t ~scope ~dir ?(bindings=Pform.Map.empty) s = String_with_vars.expand ~mode ~dir s ~f:(fun pform syntax_version ->
String_with_vars.expand ~mode:Single ~dir s ~f:(fun pform syntax_version -> (match Pform.Map.expand bindings pform syntax_version with
(match Pform.Map.expand bindings ~syntax_version ~pform with | None -> Pform.Map.expand t.pforms pform syntax_version
| None -> Pform.Map.expand t.pforms ~syntax_version ~pform | Some _ as x -> x)
| Some _ as x -> x) |> Option.map ~f:(function
|> Option.map ~f:(function | Pform.Expansion.Var (Values l) -> l
| Pform.Expansion.Var (Values l) -> l | Macro (Ocaml_config, s) -> expand_ocaml_config t pform s
| Macro (Ocaml_config, s) -> expand_ocaml_config t pform s | Var Project_root -> [Value.Dir (Scope.root scope)]
| Var Project_root -> [Value.Dir (Scope.root scope)] | _ ->
| _ -> Loc.fail (String_with_vars.Var.loc pform)
Loc.fail (String_with_vars.Var.loc pform) "%s isn't allowed in this position"
"%s isn't allowed in this position" (String_with_vars.Var.describe pform)))
(String_with_vars.Var.describe pform)))
in let expand_vars_string t ~scope ~dir ?bindings s =
let expand_vars t ~scope ~dir ?bindings s = expand_vars t ~mode:Single ~scope ~dir ?bindings s
expand t ~scope ~dir ?bindings s |> Value.to_string ~dir
|> Value.to_string ~dir
in let expand_vars_path t ~scope ~dir ?bindings s =
let expand_vars_path t ~scope ~dir ?bindings s = expand_vars t ~mode:Single ~scope ~dir ?bindings s
expand t ~scope ~dir ?bindings s |> Value.to_path ~error_loc:(String_with_vars.loc s) ~dir
|> Value.to_path ~error_loc:(String_with_vars.loc s) ~dir
in
(expand_vars, expand_vars_path)
let expand_and_eval_set t ~scope ~dir ?bindings set ~standard = let expand_and_eval_set t ~scope ~dir ?bindings set ~standard =
let open Build.O in let open Build.O in
let f = expand_vars_string t ~scope ~dir ?bindings in
let parse ~loc:_ s = s in let parse ~loc:_ s = s in
let (syntax, files) = Ordered_set_lang.Unexpanded.files set ~f in let (syntax, files) =
match String.Set.to_list files with let f = expand_vars_path t ~scope ~dir ?bindings in
Ordered_set_lang.Unexpanded.files set ~f in
let f = expand_vars t ~mode:Many ~scope ~dir ?bindings in
match Path.Set.to_list files with
| [] -> | [] ->
let set = let set =
Ordered_set_lang.Unexpanded.expand set ~files_contents:String.Map.empty ~f Ordered_set_lang.Unexpanded.expand set ~dir
~files_contents:Path.Map.empty ~f
in in
standard >>^ fun standard -> standard >>^ fun standard ->
Ordered_set_lang.String.eval set ~standard ~parse Ordered_set_lang.String.eval set ~standard ~parse
| files -> | paths ->
let paths = List.map files ~f:(Path.relative dir) in
Build.fanout standard (Build.all (List.map paths ~f:(fun f -> Build.fanout standard (Build.all (List.map paths ~f:(fun f ->
Build.read_sexp f syntax))) Build.read_sexp f syntax)))
>>^ fun (standard, sexps) -> >>^ fun (standard, sexps) ->
let files_contents = List.combine files sexps |> String.Map.of_list_exn in let files_contents = List.combine paths sexps |> Path.Map.of_list_exn in
let set = Ordered_set_lang.Unexpanded.expand set ~files_contents ~f in let set = Ordered_set_lang.Unexpanded.expand set ~dir ~files_contents ~f in
Ordered_set_lang.String.eval set ~standard ~parse Ordered_set_lang.String.eval set ~standard ~parse
module Env = struct module Env = struct
@ -560,39 +559,225 @@ module Scope_key = struct
sprintf "%s@%s" key (Dune_project.Name.encode scope) sprintf "%s@%s" key (Dune_project.Name.encode scope)
end end
type targets =
| Static of Path.t list
| Infer
| Alias
module Expander : sig
module Resolved_forms : sig
type t
(* Failed resolutions *)
val failures : t -> fail list
(* All "name" for %{lib:name:...}/%{lib-available:name} forms *)
val lib_deps : t -> Build.lib_deps
(* Static deps from %{...} variables. For instance %{exe:...} *)
val sdeps : t -> Path.Set.t
(* Dynamic deps from %{...} variables. For instance %{read:...} *)
val ddeps : t -> (unit, Value.t list) Build.t String.Map.t
end
type sctx = t
val with_expander
: sctx
-> dir:Path.t
-> dep_kind:Build.lib_dep_kind
-> scope:Scope.t
-> targets_written_by_user:targets
-> map_exe:(Path.t -> Path.t)
-> bindings:Pform.Map.t
-> f:(Value.t list option String_with_vars.expander -> 'a)
-> 'a * Resolved_forms.t
end = struct
module Resolved_forms = struct
type t =
{ (* Failed resolutions *)
mutable failures : fail list
; (* All "name" for %{lib:name:...}/%{lib-available:name} forms *)
mutable lib_deps : Build.lib_deps
; (* Static deps from %{...} variables. For instance %{exe:...} *)
mutable sdeps : Path.Set.t
; (* Dynamic deps from %{...} variables. For instance %{read:...} *)
mutable ddeps : (unit, Value.t list) Build.t String.Map.t
}
let failures t = t.failures
let lib_deps t = t.lib_deps
let sdeps t = t.sdeps
let ddeps t = t.ddeps
let empty () =
{ failures = []
; lib_deps = String.Map.empty
; sdeps = Path.Set.empty
; ddeps = String.Map.empty
}
let add_lib_dep acc lib kind =
acc.lib_deps <- String.Map.add acc.lib_deps lib kind
let add_fail acc fail =
acc.failures <- fail :: acc.failures;
None
let add_ddep acc ~key dep =
acc.ddeps <- String.Map.add acc.ddeps key dep;
None
end
type sctx = t
let path_exp path = [Value.Path path]
let str_exp str = [Value.String str]
let parse_lib_file ~loc s =
match String.lsplit2 s ~on:':' with
| None ->
Loc.fail loc "invalid %%{lib:...} form: %s" s
| Some x -> x
open Build.O
let expander ~acc sctx ~dir ~dep_kind ~scope ~targets_written_by_user
~map_exe ~bindings pform syntax_version =
let loc = String_with_vars.Var.loc pform in
let key = String_with_vars.Var.full_name pform in
let res =
Pform.Map.expand bindings pform syntax_version
|> Option.bind ~f:(function
| Pform.Expansion.Var (Values l) -> Some l
| Macro (Ocaml_config, s) -> Some (expand_ocaml_config sctx pform s)
| Var Project_root -> Some [Value.Dir (Scope.root scope)]
| Var (First_dep | Deps | Named_local) -> None
| Var Targets ->
begin match targets_written_by_user with
| Infer ->
Loc.fail loc "You cannot use %s with inferred rules."
(String_with_vars.Var.describe pform)
| Alias ->
Loc.fail loc "You cannot use %s in aliases."
(String_with_vars.Var.describe pform)
| Static l ->
Some (Value.L.dirs l) (* XXX hack to signal no dep *)
end
| Macro (Exe, s) -> Some (path_exp (map_exe (Path.relative dir s)))
| Macro (Dep, s) -> Some (path_exp (Path.relative dir s))
| Macro (Bin, s) -> begin
let sctx = host sctx in
match Artifacts.binary (artifacts sctx) s with
| Ok path -> Some (path_exp path)
| Error e ->
Resolved_forms.add_fail acc
({ fail = fun () -> Action.Prog.Not_found.raise e })
end
| Macro (Lib, s) -> begin
let lib_dep, file = parse_lib_file ~loc s in
Resolved_forms.add_lib_dep acc lib_dep dep_kind;
match
Artifacts.file_of_lib (artifacts sctx) ~loc ~lib:lib_dep ~file
with
| Ok path -> Some (path_exp path)
| Error fail -> Resolved_forms.add_fail acc fail
end
| Macro (Libexec, s) -> begin
let sctx = host sctx in
let lib_dep, file = parse_lib_file ~loc s in
Resolved_forms.add_lib_dep acc lib_dep dep_kind;
match
Artifacts.file_of_lib (artifacts sctx) ~loc ~lib:lib_dep ~file
with
| Error fail -> Resolved_forms.add_fail acc fail
| Ok path ->
if not Sys.win32 || Filename.extension s = ".exe" then begin
Some (path_exp path)
end else begin
let path_exe = Path.extend_basename path ~suffix:".exe" in
let dep =
Build.if_file_exists path_exe
~then_:(Build.path path_exe >>^ fun _ ->
path_exp path_exe)
~else_:(Build.path path >>^ fun _ ->
path_exp path)
in
Resolved_forms.add_ddep acc ~key dep
end
end
| Macro (Lib_available, s) -> begin
let lib = s in
Resolved_forms.add_lib_dep acc lib Optional;
Some (str_exp (string_of_bool (
Lib.DB.available (Scope.libs scope) lib)))
end
| Macro (Version, s) -> begin
match Package.Name.Map.find (Scope.project scope).packages
(Package.Name.of_string s) with
| Some p ->
let x =
Pkg_version.read sctx p >>^ function
| None -> [Value.String ""]
| Some s -> [String s]
in
Resolved_forms.add_ddep acc ~key x
| None ->
Resolved_forms.add_fail acc { fail = fun () ->
Loc.fail loc
"Package %S doesn't exist in the current project." s
}
end
| Macro (Read, s) -> begin
let path = Path.relative dir s in
let data =
Build.contents path
>>^ fun s -> [Value.String s]
in
Resolved_forms.add_ddep acc ~key data
end
| Macro (Read_lines, s) -> begin
let path = Path.relative dir s in
let data =
Build.lines_of path
>>^ Value.L.strings
in
Resolved_forms.add_ddep acc ~key data
end
| Macro (Read_strings, s) -> begin
let path = Path.relative dir s in
let data =
Build.strings path
>>^ Value.L.strings
in
Resolved_forms.add_ddep acc ~key data
end
| Macro (Path_no_dep, s) -> Some [Value.Dir (Path.relative dir s)])
in
Option.iter res ~f:(fun v ->
acc.sdeps <- Path.Set.union
(Path.Set.of_list (Value.L.deps_only v)) acc.sdeps
);
res
let with_expander sctx ~dir ~dep_kind ~scope ~targets_written_by_user
~map_exe ~bindings ~f =
let acc = Resolved_forms.empty () in
( f (expander ~acc sctx ~dir ~dep_kind ~scope ~targets_written_by_user ~map_exe ~bindings)
, acc
)
end
module Action = struct module Action = struct
open Build.O open Build.O
module U = Action.Unexpanded module U = Action.Unexpanded
type targets = type nonrec targets = targets =
| Static of Path.t list | Static of Path.t list
| Infer | Infer
| Alias | Alias
type resolved_forms =
{ (* Failed resolutions *)
mutable failures : fail list
; (* All "name" for %{lib:name:...}/%{lib-available:name} forms *)
mutable lib_deps : Build.lib_deps
; (* Static deps from %{...} variables. For instance %{exe:...} *)
mutable sdeps : Path.Set.t
; (* Dynamic deps from %{...} variables. For instance %{read:...} *)
mutable ddeps : (unit, Value.t list) Build.t String.Map.t
}
let add_lib_dep acc lib kind =
acc.lib_deps <- String.Map.add acc.lib_deps lib kind
let add_fail acc fail =
acc.failures <- fail :: acc.failures;
None
let add_ddep acc ~key dep =
acc.ddeps <- String.Map.add acc.ddeps key dep;
None
let path_exp path = [Value.Path path]
let str_exp str = [Value.String str]
let map_exe sctx = let map_exe sctx =
match sctx.host with match sctx.host with
@ -604,140 +789,10 @@ module Action = struct
Path.append host.context.build_dir exe Path.append host.context.build_dir exe
| _ -> exe | _ -> exe
let parse_lib_file ~loc s =
match String.lsplit2 s ~on:':' with
| None ->
Loc.fail loc "invalid %%{lib:...} form: %s" s
| Some x -> x
let expand_step1 sctx ~dir ~dep_kind ~scope ~targets_written_by_user let expand_step1 sctx ~dir ~dep_kind ~scope ~targets_written_by_user
~map_exe ~bindings t = ~map_exe ~bindings t =
let acc = Expander.with_expander sctx ~dir ~dep_kind ~scope ~targets_written_by_user ~map_exe ~bindings
{ failures = [] ~f:(fun f -> U.partial_expand t ~dir ~map_exe ~f)
; lib_deps = String.Map.empty
; sdeps = Path.Set.empty
; ddeps = String.Map.empty
}
in
let expand pform syntax_version =
let loc = String_with_vars.Var.loc pform in
let key = String_with_vars.Var.full_name pform in
let res =
Pform.Map.expand bindings ~syntax_version ~pform
|> Option.bind ~f:(function
| Pform.Expansion.Var (Values l) -> Some l
| Macro (Ocaml_config, s) -> Some (expand_ocaml_config sctx pform s)
| Var Project_root -> Some [Value.Dir (Scope.root scope)]
| Var (First_dep | Deps | Named_local) -> None
| Var Targets ->
begin match targets_written_by_user with
| Infer ->
Loc.fail loc "You cannot use %s with inferred rules."
(String_with_vars.Var.describe pform)
| Alias ->
Loc.fail loc "You cannot use %s in aliases."
(String_with_vars.Var.describe pform)
| Static l ->
Some (Value.L.dirs l) (* XXX hack to signal no dep *)
end
| Macro (Exe, s) -> Some (path_exp (map_exe (Path.relative dir s)))
| Macro (Dep, s) -> Some (path_exp (Path.relative dir s))
| Macro (Bin, s) -> begin
let sctx = host sctx in
match Artifacts.binary (artifacts sctx) s with
| Ok path -> Some (path_exp path)
| Error e ->
add_fail acc
({ fail = fun () -> Action.Prog.Not_found.raise e })
end
| Macro (Lib, s) -> begin
let lib_dep, file = parse_lib_file ~loc s in
add_lib_dep acc lib_dep dep_kind;
match
Artifacts.file_of_lib (artifacts sctx) ~loc ~lib:lib_dep ~file
with
| Ok path -> Some (path_exp path)
| Error fail -> add_fail acc fail
end
| Macro (Libexec, s) -> begin
let sctx = host sctx in
let lib_dep, file = parse_lib_file ~loc s in
add_lib_dep acc lib_dep dep_kind;
match
Artifacts.file_of_lib (artifacts sctx) ~loc ~lib:lib_dep ~file
with
| Error fail -> add_fail acc fail
| Ok path ->
if not Sys.win32 || Filename.extension s = ".exe" then begin
Some (path_exp path)
end else begin
let path_exe = Path.extend_basename path ~suffix:".exe" in
let dep =
Build.if_file_exists path_exe
~then_:(Build.path path_exe >>^ fun _ ->
path_exp path_exe)
~else_:(Build.path path >>^ fun _ ->
path_exp path)
in
add_ddep acc ~key dep
end
end
| Macro (Lib_available, s) -> begin
let lib = s in
add_lib_dep acc lib Optional;
Some (str_exp (string_of_bool (
Lib.DB.available (Scope.libs scope) lib)))
end
| Macro (Version, s) -> begin
match Package.Name.Map.find (Scope.project scope).packages
(Package.Name.of_string s) with
| Some p ->
let x =
Pkg_version.read sctx p >>^ function
| None -> [Value.String ""]
| Some s -> [String s]
in
add_ddep acc ~key x
| None ->
add_fail acc { fail = fun () ->
Loc.fail loc
"Package %S doesn't exist in the current project." s
}
end
| Macro (Read, s) -> begin
let path = Path.relative dir s in
let data =
Build.contents path
>>^ fun s -> [Value.String s]
in
add_ddep acc ~key data
end
| Macro (Read_lines, s) -> begin
let path = Path.relative dir s in
let data =
Build.lines_of path
>>^ Value.L.strings
in
add_ddep acc ~key data
end
| Macro (Read_strings, s) -> begin
let path = Path.relative dir s in
let data =
Build.strings path
>>^ Value.L.strings
in
add_ddep acc ~key data
end
| Macro (Path_no_dep, s) -> Some [Value.Dir (Path.relative dir s)])
in
Option.iter res ~f:(fun v ->
acc.sdeps <- Path.Set.union
(Path.Set.of_list (Value.L.deps_only v)) acc.sdeps
);
res
in
let t = U.partial_expand t ~dir ~map_exe ~f:expand in
(t, acc)
let expand_step2 ~dir ~dynamic_expansions ~bindings let expand_step2 ~dir ~dynamic_expansions ~bindings
~(deps_written_by_user : Path.t Jbuild.Bindings.t) ~(deps_written_by_user : Path.t Jbuild.Bindings.t)
@ -748,7 +803,7 @@ module Action = struct
match String.Map.find dynamic_expansions key with match String.Map.find dynamic_expansions key with
| Some _ as opt -> opt | Some _ as opt -> opt
| None -> | None ->
Option.map (Pform.Map.expand bindings ~syntax_version ~pform) ~f:(function Option.map (Pform.Map.expand bindings pform syntax_version) ~f:(function
| Var Named_local -> | Var Named_local ->
begin match Jbuild.Bindings.find deps_written_by_user key with begin match Jbuild.Bindings.find deps_written_by_user key with
| None -> | None ->
@ -823,13 +878,13 @@ module Action = struct
sprintf "- %s" (Utils.describe_target target)) sprintf "- %s" (Utils.describe_target target))
|> String.concat ~sep:"\n")); |> String.concat ~sep:"\n"));
let build = let build =
Build.record_lib_deps_simple forms.lib_deps Build.record_lib_deps_simple (Expander.Resolved_forms.lib_deps forms)
>>> >>>
Build.path_set (Path.Set.union deps forms.sdeps) Build.path_set (Path.Set.union deps (Expander.Resolved_forms.sdeps forms))
>>> >>>
Build.arr (fun paths -> ((), paths)) Build.arr (fun paths -> ((), paths))
>>> >>>
let ddeps = String.Map.to_list forms.ddeps in let ddeps = String.Map.to_list (Expander.Resolved_forms.ddeps forms) in
Build.first (Build.all (List.map ddeps ~f:snd)) Build.first (Build.all (List.map ddeps ~f:snd))
>>^ (fun (vals, deps_written_by_user) -> >>^ (fun (vals, deps_written_by_user) ->
let dynamic_expansions = let dynamic_expansions =
@ -854,7 +909,7 @@ module Action = struct
>>> >>>
Build.action_dyn () ~dir ~targets Build.action_dyn () ~dir ~targets
in in
match forms.failures with match Expander.Resolved_forms.failures forms with
| [] -> build | [] -> build
| fail :: _ -> Build.fail fail >>> build | fail :: _ -> Build.fail fail >>> build
end end