Merge pull request #956 from rgrinberg/lowercase-builtin-vars

Lowercase builtin vars
This commit is contained in:
Rudi Grinberg 2018-07-08 18:17:13 +07:00 committed by GitHub
commit 1b53107b66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 583 additions and 273 deletions

View File

@ -22,7 +22,7 @@ Stanzas
(rule (rule
(targets foo.ml) (targets foo.ml)
(deps generator/gen.exe) (deps generator/gen.exe)
(action (run ${<} -o ${@}))) (action (run %{<} -o %{@})))
The following sections describe the available stanzas and their meaning. The following sections describe the available stanzas and their meaning.
@ -336,16 +336,16 @@ compilation mode binary kind extensions
---------------- ------------- ----------------- ---------------- ------------- -----------------
byte exe .bc and .bc.js byte exe .bc and .bc.js
native/best exe .exe native/best exe .exe
byte object .bc${ext_obj} byte object .bc%{ext_obj}
native/best object .exe${ext_obj} native/best object .exe%{ext_obj}
byte shared_object .bc${ext_dll} byte shared_object .bc%{ext_dll}
native/best shared_object ${ext_dll} native/best shared_object %{ext_dll}
================ ============= ================= ================ ============= =================
Where ``${ext_obj}`` and ``${ext_dll}`` are the extensions for object Where ``%{ext_obj}`` and ``%{ext_dll}`` are the extensions for object
and shared object files. Their value depends on the OS, for instance and shared object files. Their value depends on the OS, for instance
on Unix ``${ext_obj}`` is usually ``.o`` and ``${ext_dll}`` is usually on Unix ``%{ext_obj}`` is usually ``.o`` and ``%{ext_dll}`` is usually
``.so`` while on Windows ``${ext_obj}`` is ``.obj`` and ``${ext_dll}`` ``.so`` while on Windows ``%{ext_obj}`` is ``.obj`` and ``%{ext_dll}``
is ``.dll``. is ``.dll``.
Note that when ``(byte exe)`` is specified but neither ``(best exe)`` Note that when ``(byte exe)`` is specified but neither ``(best exe)``
@ -459,7 +459,7 @@ For instance:
(rule (rule
(targets b (targets b
(deps a (deps a
(action (copy ${<} ${@}))))) (action (copy %{<} %{@})))))
In this example it is obvious by inspecting the action what the In this example it is obvious by inspecting the action what the
dependencies and targets are. When this is the case you can use the dependencies and targets are. When this is the case you can use the
@ -483,7 +483,7 @@ stanza is rejected by dune:
.. code:: scheme .. code:: scheme
(rule (copy a b.${read:file})) (rule (copy a b.%{read:file}))
ocamllex ocamllex
-------- --------
@ -495,7 +495,7 @@ ocamllex
(rule (rule
(targets <name>.ml) (targets <name>.ml)
(deps <name>.mll) (deps <name>.mll)
(action (chdir ${ROOT} (run ${bin:ocamllex} -q -o ${<})))) (action (chdir %{root} (run %{bin:ocamllex} -q -o %{<}))))
To use a different rule mode, use the long form: To use a different rule mode, use the long form:
@ -515,7 +515,7 @@ ocamlyacc
(rule (rule
(targets <name>.ml <name>.mli) (targets <name>.ml <name>.mli)
(deps <name>.mly) (deps <name>.mly)
(action (chdir ${ROOT} (run ${bin:ocamlyacc} ${<})))) (action (chdir %{root} (run %{bin:ocamlyacc} %{<}))))
To use a different rule mode, use the long form: To use a different rule mode, use the long form:
@ -573,7 +573,7 @@ The typical use of the ``alias`` stanza is to define tests:
(alias (alias
(name runtest) (name runtest)
(action (run ${exe:my-test-program.exe} blah))) (action (run %{exe:my-test-program.exe} blah)))
See the section about :ref:`running-tests` for details. See the section about :ref:`running-tests` for details.
@ -825,18 +825,18 @@ Variables are expanded after the set language is interpreted.
Variables expansion Variables expansion
------------------- -------------------
Some fields can contains variables of the form ``$(var)`` or ``${var}`` that are Some fields can contains variables of the form ``$(var)`` or ``%{var}`` that are
expanded by dune. expanded by dune.
Dune supports the following variables: Dune supports the following variables:
- ``ROOT`` is the relative path to the root of the build - ``root`` is the relative path to the root of the build
context. Note that ``ROOT`` depends on the worksace context. Note that ``root`` depends on the workspace
configuration. As such you shouldn't use ``ROOT`` to denote the configuration. As such you shouldn't use ``root`` to denote the
root of your project. Use ``SCOPE_ROOT`` instead for this purpose root of your project. Use ``project_root`` instead for this purpose
- ``SCOPE_ROOT`` is the root of the current scope. It is typically - ``project_root`` is the root of the current scope. It is typically
the toplevel directory of your project and as long as you have at the toplevel directory of your project and as long as you have at
least one ``<package>.opam`` file there, ``SCOPE_ROOT`` is least one ``<package>.opam`` file there, ``project_root`` is
independent of the workspace configuration independent of the workspace configuration
- ``CC`` is the C compiler command line (list made of the compiler - ``CC`` is the C compiler command line (list made of the compiler
name followed by its flags) that was used to compile OCaml in the name followed by its flags) that was used to compile OCaml in the
@ -844,13 +844,13 @@ Dune supports the following variables:
- ``CXX`` is the C++ compiler command line being used in the - ``CXX`` is the C++ compiler command line being used in the
current build context current build context
- ``ocaml_bin`` is the path where ``ocamlc`` lives - ``ocaml_bin`` is the path where ``ocamlc`` lives
- ``OCAML`` is the ``ocaml`` binary - ``ocaml`` is the ``ocaml`` binary
- ``OCAMLC`` is the ``ocamlc`` binary - ``ocamlc`` is the ``ocamlc`` binary
- ``OCAMLOPT`` is the ``ocamlopt`` binary - ``ocamlopt`` is the ``ocamlopt`` binary
- ``ocaml_version`` is the version of the compiler used in the - ``ocaml_version`` is the version of the compiler used in the
current build context current build context
- ``ocaml_where`` is the output of ``ocamlc -where`` - ``ocaml_where`` is the output of ``ocamlc -where``
- ``ARCH_SIXTYFOUR`` is ``true`` if using a compiler targeting a - ``arch_sixtyfour`` is ``true`` if using a compiler targeting a
64 bit architecture and ``false`` otherwise 64 bit architecture and ``false`` otherwise
- ``null`` is ``/dev/null`` on Unix or ``nul`` on Windows - ``null`` is ``/dev/null`` on Unix or ``nul`` on Windows
- ``ext_obj``, ``ext_asm``, ``ext_lib``, ``ext_dll`` and ``ext_exe`` - ``ext_obj``, ``ext_asm``, ``ext_lib``, ``ext_dll`` and ``ext_exe``
@ -878,8 +878,8 @@ In addition, ``(action ...)`` fields support the following special variables:
is installed by a package in the workspace (see `install`_ stanzas), is installed by a package in the workspace (see `install`_ stanzas),
the locally built binary will be used, otherwise it will be searched the locally built binary will be used, otherwise it will be searched
in the ``PATH`` of the current build context. Note that ``(run in the ``PATH`` of the current build context. Note that ``(run
${bin:program} ...)`` and ``(run program ...)`` behave in the same %{bin:program} ...)`` and ``(run program ...)`` behave in the same
way. ``${bin:...}`` is only necessary when you are using ``(bash way. ``%{bin:...}`` is only necessary when you are using ``(bash
...)`` or ``(system ...)`` ...)`` or ``(system ...)``
- ``lib:<public-library-name>:<file>`` expands to a path to file ``<file>`` of - ``lib:<public-library-name>:<file>`` expands to a path to file ``<file>`` of
library ``<public-library-name>``. If ``<public-library-name>`` is available library ``<public-library-name>``. If ``<public-library-name>`` is available
@ -906,10 +906,10 @@ In addition, ``(action ...)`` fields support the following special variables:
- ``read-strings:<path>`` expands to the list of lines in the given - ``read-strings:<path>`` expands to the list of lines in the given
file, unescaped using OCaml lexical convention file, unescaped using OCaml lexical convention
The ``${<kind>:...}`` forms are what allows you to write custom rules that work The ``%{<kind>:...}`` forms are what allows you to write custom rules that work
transparently whether things are installed or not. transparently whether things are installed or not.
Note that aliases are ignored by both ``${<}`` and ``${^}``. Note that aliases are ignored by both ``%{<}`` and ``%{^}``.
The intent of this last form is to reliably read a list of strings The intent of this last form is to reliably read a list of strings
generated by an OCaml program via: generated by an OCaml program via:
@ -920,13 +920,13 @@ generated by an OCaml program via:
#. Expansion of lists #. Expansion of lists
Forms that expands to list of items, such as ``${CC}``, ``${^}``, Forms that expands to list of items, such as ``%{cc}``, ``%{^}``,
``${@}`` or ``${read-lines:...}``, are suitable to be used in, say, ``%{@}`` or ``%{read-lines:...}``, are suitable to be used in, say,
``(run <prog> <arguments>)``. For instance in: ``(run <prog> <arguments>)``. For instance in:
.. code:: scheme .. code:: scheme
(run foo ${^}) (run foo %{^})
if there are two dependencies ``a`` and ``b``, the produced command if there are two dependencies ``a`` and ``b``, the produced command
will be equivalent to the shell command: will be equivalent to the shell command:
@ -940,7 +940,7 @@ you have to quote the variable as in:
.. code:: scheme .. code:: scheme
(run foo "${^}") (run foo "%{^}")
which is equivalent to the following shell command: which is equivalent to the following shell command:
@ -949,7 +949,7 @@ which is equivalent to the following shell command:
$ foo "a b" $ foo "a b"
(the items of the list are concatenated with space). (the items of the list are concatenated with space).
Note that, since ``${^}`` is a list of items, the first one may be Note that, since ``%{^}`` is a list of items, the first one may be
used as a program name, for instance: used as a program name, for instance:
.. code:: scheme .. code:: scheme
@ -957,7 +957,7 @@ used as a program name, for instance:
(rule (rule
(targets result.txt) (targets result.txt)
(deps foo.exe (glob_files *.txt)) (deps foo.exe (glob_files *.txt))
(action (run ${^}))) (action (run %{^})))
Here is another example: Here is another example:
@ -966,7 +966,7 @@ Here is another example:
(rule (rule
(targets foo.exe) (targets foo.exe)
(deps foo.c) (deps foo.c)
(action (run ${CC} -o ${@} ${<} -lfoolib))) (action (run %{cc} -o %{@} %{<} -lfoolib)))
Library dependencies Library dependencies
@ -1052,10 +1052,10 @@ you had setup a rule for every file of the form:
(rule (rule
(targets file.pp.ml) (targets file.pp.ml)
(deps file.ml) (deps file.ml)
(action (with-stdout-to ${@} (chdir ${ROOT} <action>)))) (action (with-stdout-to %{@} (chdir %{root} <action>))))
The equivalent of a ``-pp <command>`` option passed to the OCaml compiler is The equivalent of a ``-pp <command>`` option passed to the OCaml compiler is
``(system "<command> ${<}")``. ``(system "<command> %{<}")``.
Preprocessing with ppx rewriters Preprocessing with ppx rewriters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -1105,8 +1105,8 @@ For instance:
.. code:: scheme .. code:: scheme
(preprocess (per_module (preprocess (per_module
(((action (run ./pp.sh X=1 ${<})) (foo bar))) (((action (run ./pp.sh X=1 %{<})) (foo bar)))
(((action (run ./pp.sh X=2 ${<})) (baz))))) (((action (run ./pp.sh X=2 %{<})) (baz)))))
.. _deps-field: .. _deps-field:
@ -1231,7 +1231,7 @@ in ``src/foo/dune`` will be run from ``_build/<context>/src/foo``.
The argument of ``(action ...)`` fields is a small DSL that is interpreted by The argument of ``(action ...)`` fields is a small DSL that is interpreted by
dune directly and doesn't require an external shell. All atoms in the DSL dune directly and doesn't require an external shell. All atoms in the DSL
support `Variables expansion`_. Moreover, you don't need to specify dependencies support `Variables expansion`_. Moreover, you don't need to specify dependencies
explicitly for the special ``${<kind>:...}`` forms, these are recognized and explicitly for the special ``%{<kind>:...}`` forms, these are recognized and
automatically handled by dune. automatically handled by dune.
The DSL is currently quite limited, so if you want to do something complicated The DSL is currently quite limited, so if you want to do something complicated
@ -1289,15 +1289,15 @@ called ``copy-and-add-line-directive``. However, most of time one
wants this behavior rather than a bare copy, so it was renamed to wants this behavior rather than a bare copy, so it was renamed to
something shorter. something shorter.
Note: expansion of the special ``${<kind>:...}`` is done relative to the current Note: expansion of the special ``%{<kind>:...}`` is done relative to the current
working directory of the part of the DSL being executed. So for instance if you working directory of the part of the DSL being executed. So for instance if you
have this action in a ``src/foo/dune``: have this action in a ``src/foo/dune``:
.. code:: scheme .. code:: scheme
(action (chdir ../../.. (echo ${path:dune}))) (action (chdir ../../.. (echo %{path:dune})))
Then ``${path:dune}`` will expand to ``src/foo/dune``. When you run various Then ``%{path:dune}`` will expand to ``src/foo/dune``. When you run various
tools, they often use the filename given on the command line in error messages. tools, they often use the filename given on the command line in error messages.
As a result, if you execute the command from the original directory, it will As a result, if you execute the command from the original directory, it will
only see the basename. only see the basename.
@ -1310,7 +1310,7 @@ To understand why this is important, let's consider this dune file living in
(rule (rule
(targets blah.ml) (targets blah.ml)
(deps blah.mll) (deps blah.mll)
(action (run ocamllex -o ${@} ${<}))) (action (run ocamllex -o %{@} %{<})))
Here the command that will be executed is: Here the command that will be executed is:
@ -1334,7 +1334,7 @@ of your project. What you should write instead is:
(rule (rule
(targets blah.ml) (targets blah.ml)
(deps blah.mll) (deps blah.mll)
(action (chdir ${ROOT} (run ocamllex -o ${@} ${<})))) (action (chdir %{root} (run ocamllex -o %{@} %{<}))))
Locks Locks
----- -----
@ -1357,13 +1357,13 @@ same lock:
(name runtest) (name runtest)
(deps foo) (deps foo)
(locks m) (locks m)
(action (run test.exe ${<}))) (action (run test.exe %{<})))
(alias (alias
(name runtest) (name runtest)
(deps bar) (deps bar)
(locks m) (locks m)
(action (run test.exe ${<}))) (action (run test.exe %{<})))
Dune will make sure that the executions of ``test.exe foo`` and Dune will make sure that the executions of ``test.exe foo`` and
``test.exe bar`` are serialized. ``test.exe bar`` are serialized.
@ -1383,7 +1383,7 @@ simply use an absolute filename:
(name runtest) (name runtest)
(deps foo) (deps foo)
(locks /tcp-port/1042) (locks /tcp-port/1042)
(action (run test.exe ${<}))) (action (run test.exe %{<})))
.. _ocaml-syntax: .. _ocaml-syntax:

View File

@ -173,6 +173,14 @@ Jbuild Dune
``${path:file}`` ``%{dep:file}`` ``${path:file}`` ``%{dep:file}``
``${SCOPE_ROOT}`` ``%{project_root}`` ``${SCOPE_ROOT}`` ``%{project_root}``
``${findlib:..}`` ``%{lib:..}`` ``${findlib:..}`` ``%{lib:..}``
``${CPP}`` ``%{cpp}``
``${CC}`` ``%{cc}``
``${CXX}`` ``%{cxx}``
``${OCAML}`` ``%{ocaml}``
``${OCAMLC}`` ``%{ocamlc}``
``${OCAMLOPT}`` ``%{ocamlopt}``
``${ARCH_SIXTYFOUR}`` ``%{arch_sixtyfour}``
``${MAKE}`` ``%{make}``
======================== ============ ======================== ============
Removed Variables Removed Variables

View File

@ -337,6 +337,9 @@ end
let prog_and_args_of_values p ~dir = let prog_and_args_of_values p ~dir =
match p with match p with
| [] -> (Unresolved.Program.Search "", []) | [] -> (Unresolved.Program.Search "", [])
| Value.Dir p :: _ ->
die "%s is a directory and cannot be used as an executable"
(Path.to_string_maybe_quoted p)
| Value.Path p :: xs -> (This p, Value.L.to_strings ~dir xs) | Value.Path p :: xs -> (This p, Value.L.to_strings ~dir xs)
| String s :: xs -> | String s :: xs ->
(Unresolved.Program.of_string ~dir s, Value.L.to_strings ~dir xs) (Unresolved.Program.of_string ~dir s, Value.L.to_strings ~dir xs)

View File

@ -201,7 +201,7 @@ module Gen(P : Install_rules.Params) = struct
let copy_files_rules (def: Copy_files.t) ~src_dir ~dir ~scope = let copy_files_rules (def: Copy_files.t) ~src_dir ~dir ~scope =
let loc = String_with_vars.loc def.glob in let loc = String_with_vars.loc def.glob in
let glob_in_src = let glob_in_src =
let src_glob = SC.expand_vars sctx ~dir def.glob ~scope in let src_glob = SC.expand_vars_string sctx ~dir def.glob ~scope in
Path.relative src_dir src_glob ~error_loc:loc Path.relative src_dir src_glob ~error_loc:loc
in in
(* The following condition is required for merlin to work. (* The following condition is required for merlin to work.
@ -1042,7 +1042,7 @@ module Gen(P : Install_rules.Params) = struct
| Copy_files { glob; _ } -> | Copy_files { glob; _ } ->
let src_dir = let src_dir =
let loc = String_with_vars.loc glob in let loc = String_with_vars.loc glob in
let src_glob = SC.expand_vars sctx ~dir glob ~scope in let src_glob = SC.expand_vars_string sctx ~dir glob ~scope in
Path.parent_exn (Path.relative src_dir src_glob ~error_loc:loc) Path.parent_exn (Path.relative src_dir src_glob ~error_loc:loc)
in in
Some Some

View File

@ -1238,7 +1238,7 @@ module Rule = struct
; action = ; action =
(loc, (loc,
Chdir Chdir
(S.virt_var __POS__ "ROOT", (S.virt_var __POS__ "root",
Run (S.virt_text __POS__ "ocamllex", Run (S.virt_text __POS__ "ocamllex",
[ S.virt_text __POS__ "-q" [ S.virt_text __POS__ "-q"
; S.virt_text __POS__ "-o" ; S.virt_text __POS__ "-o"
@ -1259,7 +1259,7 @@ module Rule = struct
; action = ; action =
(loc, (loc,
Chdir Chdir
(S.virt_var __POS__ "ROOT", (S.virt_var __POS__ "root",
Run (S.virt_text __POS__ "ocamlyacc", Run (S.virt_text __POS__ "ocamlyacc",
[S.virt_var __POS__ "first-dep"]))) [S.virt_var __POS__ "first-dep"])))
; mode ; mode

View File

@ -61,7 +61,7 @@ module Run (P : PARAMS) = struct
let sources ms = let sources ms =
List.map ~f:source ms List.map ~f:source ms
(* Expand special variables, such as ${ROOT}, in the stanza's flags. *) (* Expand special variables, such as %{root}, in the stanza's flags. *)
let flags = let flags =
SC.expand_and_eval_set SC.expand_and_eval_set

185
src/pform.ml Normal file
View File

@ -0,0 +1,185 @@
open Import
module Var = struct
type t =
| Values of Value.t list
| Project_root
| First_dep
| Deps
| Targets
let to_value_no_deps_or_targets t ~scope =
match t with
| Values v -> Some v
| Project_root -> Some [Value.Dir (Scope.root scope)]
| First_dep
| Deps
| Targets -> None
end
module Macro = struct
type t =
| Exe
| Dep
| Bin
| Lib
| Libexec
| Lib_available
| Version
| Read
| Read_strings
| Read_lines
| Path_no_dep
end
type 'a t =
| No_info of 'a
| Since of 'a * Syntax.Version.t
| Deleted_in of 'a * Syntax.Version.t
| Renamed_in of Syntax.Version.t * string
module Map = struct
type nonrec 'a t = 'a t String.Map.t
let values v = No_info (Var.Values v)
let renamed_in ~new_name ~version = Renamed_in (version, new_name)
let deleted_in ~version kind = Deleted_in (kind, version)
let since ~version v = Since (v, version)
let static_vars =
[ "first-dep", since ~version:(1, 0) Var.First_dep
; "targets", since ~version:(1, 0) Var.Targets
; "deps", since ~version:(1, 0) Var.Deps
; "project_root", since ~version:(1, 0) Var.Project_root
; "<", renamed_in ~version:(1, 0) ~new_name:"first-dep"
; "@", renamed_in ~version:(1, 0) ~new_name:"targets"
; "^", renamed_in ~version:(1, 0) ~new_name:"deps"
; "SCOPE_ROOT", renamed_in ~version:(1, 0) ~new_name:"project_root"
]
let macros =
let macro kind = No_info kind in
let open Macro in
[ "exe", macro Exe
; "bin", macro Bin
; "lib", macro Lib
; "libexec", macro Libexec
; "lib-available", macro Lib_available
; "version", macro Version
; "read", macro Read
; "read-lines", macro Read_lines
; "read-strings", macro Read_strings
; "dep", since ~version:(1, 0) Dep
; "path", renamed_in ~version:(1, 0) ~new_name:"dep"
; "findlib", renamed_in ~version:(1, 0) ~new_name:"lib"
; "path-no-dep", deleted_in ~version:(1, 0) Path_no_dep
]
|> String.Map.of_list_exn
let create_vars ~(context : Context.t) ~cxx_flags =
let ocamlopt =
match context.ocamlopt with
| None -> Path.relative context.ocaml_bin "ocamlopt"
| Some p -> p
in
let string s = values [Value.String s] in
let path p = values [Value.Path p] in
let make =
match Bin.make with
| None -> string "make"
| Some p -> path p
in
let cflags = context.ocamlc_cflags in
let strings s = values (Value.L.strings s) in
let lowercased =
[ "cpp" , strings (context.c_compiler :: cflags @ ["-E"])
; "cc" , strings (context.c_compiler :: cflags)
; "cxx" , strings (context.c_compiler :: cxx_flags)
; "ocaml" , path context.ocaml
; "ocamlc" , path context.ocamlc
; "ocamlopt" , path ocamlopt
; "arch_sixtyfour" , string (string_of_bool context.arch_sixtyfour)
; "make" , make
; "root" , values [Value.Dir context.build_dir]
] in
let uppercased =
List.map lowercased ~f:(fun (k, _) ->
(String.uppercase k, renamed_in ~new_name:k ~version:(1, 0))) in
let vars =
[ "-verbose" , values []
; "pa_cpp" , strings (context.c_compiler :: cflags
@ ["-undef"; "-traditional";
"-x"; "c"; "-E"])
; "ocaml_bin" , path context.ocaml_bin
; "ocaml_version" , string context.version_string
; "ocaml_where" , string (Path.to_string context.stdlib_dir)
; "null" , string (Path.to_string Config.dev_null)
; "ext_obj" , string context.ext_obj
; "ext_asm" , string context.ext_asm
; "ext_lib" , string context.ext_lib
; "ext_dll" , string context.ext_dll
; "ext_exe" , string context.ext_exe
; "profile" , string context.profile
]
in
let ocaml_config =
List.map (Ocaml_config.to_list context.ocaml_config) ~f:(fun (k, v) ->
("ocaml-config:" ^ k,
match (v : Ocaml_config.Value.t) with
| Bool x -> string (string_of_bool x)
| Int x -> string (string_of_int x)
| String x -> string x
| Words x -> strings x
| Prog_and_args x -> strings (x.prog :: x.args)))
in
[ ocaml_config
; static_vars
; lowercased
; uppercased
; vars
]
|> List.concat
|> String.Map.of_list_exn
let static_vars = String.Map.of_list_exn static_vars
let rec expand t ~syntax_version ~var =
let name = String_with_vars.Var.name var in
Option.bind (String.Map.find t name) ~f:(fun v ->
let what var =
String_with_vars.Var.to_string (
if String_with_vars.Var.is_macro var then
String_with_vars.Var.with_payload var ~payload:(Some "..")
else
var)
in
match v with
| No_info v -> Some v
| Since (v, min_version) ->
if syntax_version >= min_version then
Some v
else
Syntax.Error.since (String_with_vars.Var.loc var)
Stanza.syntax min_version
~what:(what var)
| Renamed_in (in_version, new_name) -> begin
if syntax_version >= in_version then
Syntax.Error.renamed_in (String_with_vars.Var.loc var)
Stanza.syntax syntax_version
~what:(what var)
~to_:(what (String_with_vars.Var.with_name var ~name:new_name))
else
expand t ~syntax_version:in_version
~var:(String_with_vars.Var.with_name var ~name:new_name)
end
| Deleted_in (v, in_version) ->
if syntax_version < in_version then
Some v
else
Syntax.Error.deleted_in (String_with_vars.Var.loc var)
Stanza.syntax syntax_version ~what:(what var))
end

48
src/pform.mli Normal file
View File

@ -0,0 +1,48 @@
module Var : sig
type t =
| Values of Value.t list
| Project_root
| First_dep
| Deps
| Targets
val to_value_no_deps_or_targets : t -> scope:Scope.t -> Value.t list option
end
module Macro : sig
type t =
| Exe
| Dep
| Bin
| Lib
| Libexec
| Lib_available
| Version
| Read
| Read_strings
| Read_lines
| Path_no_dep
end
type 'a t =
| No_info of 'a
| Since of 'a * Syntax.Version.t
| Deleted_in of 'a * Syntax.Version.t
| Renamed_in of Syntax.Version.t * string
module Map : sig
type 'a var
type 'a t
val create_vars : context:Context.t -> cxx_flags:string list -> Var.t t
val macros : Macro.t t
val static_vars : Var.t t
val expand
: 'a t
-> syntax_version:Syntax.Version.t
-> var:String_with_vars.Var.t
-> 'a option
end with type 'a var := 'a t

View File

@ -398,7 +398,7 @@ let get_ppx_driver sctx ~loc ~scope ~dir_kind pps =
Ok (ppx_driver_exe sctx libs ~dir_kind, driver) Ok (ppx_driver_exe sctx libs ~dir_kind, driver)
let target_var = String_with_vars.virt_var __POS__ "targets" let target_var = String_with_vars.virt_var __POS__ "targets"
let root_var = String_with_vars.virt_var __POS__ "ROOT" let root_var = String_with_vars.virt_var __POS__ "root"
let cookie_library_name lib_name = let cookie_library_name lib_name =
match lib_name with match lib_name with

View File

@ -75,7 +75,7 @@ let report_with_backtrace exn =
Format.fprintf ppf "@{<error>Internal error, please report upstream \ Format.fprintf ppf "@{<error>Internal error, please report upstream \
including the contents of _build/log.@}\n\ including the contents of _build/log.@}\n\
Description:%a\n" Description:%a\n"
(Usexp.pp Dune) sexp Usexp.pp_quoted sexp
} }
| Unix.Unix_error (err, func, fname) -> | Unix.Unix_error (err, func, fname) ->
{ p with pp = fun ppf -> { p with pp = fun ppf ->

View File

@ -37,6 +37,24 @@ module Make(H : Hashable.S) = struct
fold t ~init ~f:(fun ~key ~data acc -> f key data acc) fold t ~init ~f:(fun ~key ~data acc -> f key data acc)
let fold t ~init ~f = foldi t ~init ~f:(fun _ x -> f x) let fold t ~init ~f = foldi t ~init ~f:(fun _ x -> f x)
end end
let of_list l =
let h = create (List.length l) in
let rec loop = function
| [] -> Result.Ok h
| (k, v) :: xs ->
begin match find h k with
| None -> add h k v; loop xs
| Some v' -> Error (k, v', v)
end
in
loop l
let of_list_exn l =
match of_list l with
| Result.Ok h -> h
| Error (_, _, _) ->
Exn.code_error "Hashtbl.of_list_exn duplicate keys" []
end end
open MoreLabels.Hashtbl open MoreLabels.Hashtbl

View File

@ -8,4 +8,6 @@ module type S = sig
val fold : 'a t -> init:'b -> f:('a -> 'b -> 'b) -> 'b val fold : 'a t -> init:'b -> f:('a -> 'b -> 'b) -> 'b
val foldi : 'a t -> init:'b -> f:(key -> 'a -> 'b -> 'b) -> 'b val foldi : 'a t -> init:'b -> f:(key -> 'a -> 'b -> 'b) -> 'b
val of_list_exn : (key * 'a) list -> 'a t
end end

View File

@ -16,6 +16,8 @@ let compare a b = Ordering.of_int (String.compare a b)
module T = struct module T = struct
type t = StringLabels.t type t = StringLabels.t
let compare = compare let compare = compare
let equal (x : t) (y : t) = x = y
let hash (s : t) = Hashtbl.hash s
end end
let capitalize = capitalize_ascii let capitalize = capitalize_ascii
@ -201,6 +203,7 @@ let maybe_quoted s =
module Set = Set.Make(T) module Set = Set.Make(T)
module Map = Map.Make(T) module Map = Map.Make(T)
module Table = Hashtbl.Make(T)
let enumerate_gen s = let enumerate_gen s =
let s = " " ^ s ^ " " in let s = " " ^ s ^ " " in

View File

@ -53,3 +53,4 @@ val enumerate_or : string list -> string
module Set : Set.S with type elt = t module Set : Set.S with type elt = t
module Map : Map.S with type key = t module Map : Map.S with type key = t
module Table : Hashtbl.S with type key = t

View File

@ -196,18 +196,34 @@ module Var = struct
let loc (t : t) = t.loc let loc (t : t) = t.loc
type kind = type kind =
| Single of string | Var of string
| Pair of string * string | Macro of string * string
let destruct { loc = _ ; name; payload; syntax = _ } = let destruct { loc = _ ; name; payload; syntax = _ } =
match payload with match payload with
| None -> Single name | None -> Var name
| Some p -> Pair (name, p) | Some p -> Macro (name, p)
let name { name; _ } = name
let full_name t = let full_name t =
match destruct t with match destruct t with
| Single s -> s | Var s -> s
| Pair (k, v) -> k ^ ":" ^ v | Macro (k, v) -> k ^ ":" ^ v
let to_string = string_of_var
let pp fmt t = Format.pp_print_string fmt (to_string t)
let sexp_of_t t = Sexp.atom (to_string t)
let with_payload t ~payload =
{ t with payload }
let with_name t ~name =
{ t with name }
let is_macro t = Option.is_some t.payload
end end
let partial_expand let partial_expand
@ -262,8 +278,8 @@ let expand t ~mode ~dir ~f =
begin match var.syntax with begin match var.syntax with
| Percent -> | Percent ->
begin match Var.destruct var with begin match Var.destruct var with
| Single v -> Loc.fail var.loc "unknown variable %S" v | Var v -> Loc.fail var.loc "unknown variable %S" v
| Pair _ -> Loc.fail var.loc "unknown form %s" (string_of_var var) | Macro _ -> Loc.fail var.loc "unknown form %s" (string_of_var var)
end end
| Dollar_brace | Dollar_brace
| Dollar_paren -> Some [Value.String (string_of_var var)] | Dollar_paren -> Some [Value.String (string_of_var var)]

View File

@ -49,14 +49,27 @@ end
module Var : sig module Var : sig
type t type t
val pp : t Fmt.t
val sexp_of_t : t -> Sexp.t
val name : t -> string
val loc : t -> Loc.t val loc : t -> Loc.t
val full_name : t -> string val full_name : t -> string
type kind = type kind =
| Single of string | Var of string
| Pair of string * string | Macro of string * string
val destruct : t -> kind val destruct : t -> kind
val to_string : t -> string
val with_name : t -> name:string -> t
val with_payload : t -> payload:string option -> t
val is_macro : t -> bool
end end
val expand val expand

View File

@ -45,7 +45,8 @@ type t =
; artifacts : Artifacts.t ; artifacts : Artifacts.t
; stanzas_to_consider_for_install : Installable.t list ; stanzas_to_consider_for_install : Installable.t list
; cxx_flags : string list ; cxx_flags : string list
; vars : Value.t list String.Map.t ; vars : Pform.Var.t Pform.Map.t
; macros : Pform.Macro.t Pform.Map.t
; chdir : (Action.t, Action.t) Build.t ; chdir : (Action.t, Action.t) Build.t
; host : t option ; host : t option
; libs_by_package : (Package.t * Lib.Set.t) Package.Name.Map.t ; libs_by_package : (Package.t * Lib.Set.t) Package.Name.Map.t
@ -84,26 +85,34 @@ let installed_libs t = t.installed_libs
let find_scope_by_dir t dir = Scope.DB.find_by_dir t.scopes dir let find_scope_by_dir t dir = Scope.DB.find_by_dir t.scopes dir
let find_scope_by_name t name = Scope.DB.find_by_name t.scopes name let find_scope_by_name t name = Scope.DB.find_by_name t.scopes name
let expand_var_no_root t var = String.Map.find t.vars var let expand_vars t ~syntax_version ~var =
if String_with_vars.Var.is_macro var then
Loc.fail (String_with_vars.Var.loc var)
"macros of the form %%{name:..} cannot be expanded here"
else
Pform.Map.expand t.vars ~syntax_version ~var
let (expand_vars, expand_vars_path) = let expand_macro t ~syntax_version ~var =
if String_with_vars.Var.is_macro var then
Pform.Map.expand t.macros ~syntax_version ~var
else
Exn.code_error "expand_macro can't expand variables"
[ "var", String_with_vars.Var.sexp_of_t var ]
let (expand_vars_string, expand_vars_path) =
let expand t ~scope ~dir ?(extra_vars=String.Map.empty) s = let expand t ~scope ~dir ?(extra_vars=String.Map.empty) s =
String_with_vars.expand ~mode:Single ~dir s ~f:(fun v syntax_version -> String_with_vars.expand ~mode:Single ~dir s ~f:(fun var syntax_version ->
match String_with_vars.Var.full_name v with match expand_vars t ~syntax_version ~var with
| "ROOT" -> Some [Value.Path t.context.build_dir] | None ->
| "SCOPE_ROOT" -> String.Map.find extra_vars (String_with_vars.Var.full_name var)
if syntax_version >= (1, 0) then | Some v ->
Loc.fail (String_with_vars.Var.loc v) begin match Pform.Var.to_value_no_deps_or_targets ~scope v with
"Variable %%{SCOPE_ROOT} has been renamed to %%{project_root} \ | Some _ as v -> v
in dune files" | None ->
else Loc.fail (String_with_vars.Var.loc var)
Some [Value.Path (Scope.root scope)] "Variable %a is not allowed in this context"
| "project_root" when syntax_version >= (1, 0) -> String_with_vars.Var.pp var
Some [Value.Path (Scope.root scope)] end)
| var ->
(match expand_var_no_root t var with
| Some _ as x -> x
| None -> String.Map.find extra_vars var))
in in
let expand_vars t ~scope ~dir ?extra_vars s = let expand_vars t ~scope ~dir ?extra_vars s =
expand t ~scope ~dir ?extra_vars s expand t ~scope ~dir ?extra_vars s
@ -117,7 +126,7 @@ let (expand_vars, expand_vars_path) =
let expand_and_eval_set t ~scope ~dir ?extra_vars set ~standard = let expand_and_eval_set t ~scope ~dir ?extra_vars set ~standard =
let open Build.O in let open Build.O in
let f = expand_vars t ~scope ~dir ?extra_vars in let f = expand_vars_string t ~scope ~dir ?extra_vars 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) = Ordered_set_lang.Unexpanded.files set ~f in
match String.Set.to_list files with match String.Set.to_list files with
@ -280,61 +289,7 @@ let create
List.filter context.ocamlc_cflags List.filter context.ocamlc_cflags
~f:(fun s -> not (String.is_prefix s ~prefix:"-std=")) ~f:(fun s -> not (String.is_prefix s ~prefix:"-std="))
in in
let vars = let vars = Pform.Map.create_vars ~context ~cxx_flags in
let ocamlopt =
match context.ocamlopt with
| None -> Path.relative context.ocaml_bin "ocamlopt"
| Some p -> p
in
let string s = [Value.String s] in
let path p = [Value.Path p] in
let make =
match Bin.make with
| None -> string "make"
| Some p -> path p
in
let cflags = context.ocamlc_cflags in
let strings = Value.L.strings in
let vars =
[ "-verbose" , []
; "CPP" , strings (context.c_compiler :: cflags @ ["-E"])
; "PA_CPP" , strings (context.c_compiler :: cflags
@ ["-undef"; "-traditional";
"-x"; "c"; "-E"])
; "CC" , strings (context.c_compiler :: cflags)
; "CXX" , strings (context.c_compiler :: cxx_flags)
; "ocaml_bin" , path context.ocaml_bin
; "OCAML" , path context.ocaml
; "OCAMLC" , path context.ocamlc
; "OCAMLOPT" , path ocamlopt
; "ocaml_version" , string context.version_string
; "ocaml_where" , string (Path.to_string context.stdlib_dir)
; "ARCH_SIXTYFOUR" , string (string_of_bool context.arch_sixtyfour)
; "MAKE" , make
; "null" , string (Path.to_string Config.dev_null)
; "ext_obj" , string context.ext_obj
; "ext_asm" , string context.ext_asm
; "ext_lib" , string context.ext_lib
; "ext_dll" , string context.ext_dll
; "ext_exe" , string context.ext_exe
; "profile" , string context.profile
]
in
let vars =
vars @
List.map (Ocaml_config.to_list context.ocaml_config) ~f:(fun (k, v) ->
("ocaml-config:" ^ k,
match (v : Ocaml_config.Value.t) with
| Bool x -> string (string_of_bool x)
| Int x -> string (string_of_int x)
| String x -> string x
| Words x -> strings x
| Prog_and_args x -> strings (x.prog :: x.args)))
in
match String.Map.of_list vars with
| Ok x -> x
| Error _ -> assert false
in
let t = let t =
{ context { context
; host ; host
@ -349,6 +304,7 @@ let create
; artifacts ; artifacts
; cxx_flags ; cxx_flags
; vars ; vars
; macros = Pform.Map.macros
; chdir = Build.arr (fun (action : Action.t) -> ; chdir = Build.arr (fun (action : Action.t) ->
match action with match action with
| Chdir _ -> action | Chdir _ -> action
@ -528,7 +484,7 @@ module Deps = struct
Build.source_tree ~dir:path ~file_tree:t.file_tree Build.source_tree ~dir:path ~file_tree:t.file_tree
>>^ Path.Set.to_list >>^ Path.Set.to_list
| Package p -> | Package p ->
let pkg = Package.Name.of_string (expand_vars t ~scope ~dir p) in let pkg = Package.Name.of_string (expand_vars_string t ~scope ~dir p) in
Alias.dep (Alias.package_install ~context:t.context ~pkg) Alias.dep (Alias.package_install ~context:t.context ~pkg)
>>^ fun () -> [] >>^ fun () -> []
| Universe -> | Universe ->
@ -636,40 +592,20 @@ module Action = struct
; ddeps = String.Map.empty ; ddeps = String.Map.empty
} }
in in
let expand var syntax_version = let expand_form s var syntax_version =
let loc = String_with_vars.Var.loc var in let loc = String_with_vars.Var.loc var in
let key = String_with_vars.Var.full_name var in let key = String_with_vars.Var.full_name var in
let path_with_dep s = begin match expand_macro sctx ~syntax_version ~var with
Some (path_exp (Path.relative dir s) ) | Some Pform.Macro.Exe -> Some (path_exp (map_exe (Path.relative dir s)))
in | Some Dep -> Some (path_exp (Path.relative dir s))
match String_with_vars.Var.destruct var with | Some Bin -> begin
| Pair ("exe", s) -> Some (path_exp (map_exe (Path.relative dir s)))
| Pair ("path", s) when syntax_version < (1, 0) ->
path_with_dep s
| Pair ("dep", s) when syntax_version >= (1, 0) ->
path_with_dep s
| Pair ("dep", s) ->
Loc.fail
loc
"${dep:%s} is not supported in jbuild files.\n\
Hint: Did you mean ${path:%s} instead?"
s
s
| Pair ("bin", s) -> begin
let sctx = host sctx in let sctx = host sctx in
match Artifacts.binary (artifacts sctx) s with match Artifacts.binary (artifacts sctx) s with
| Ok path -> Some (path_exp path) | Ok path -> Some (path_exp path)
| Error e -> | Error e ->
add_fail acc ({ fail = fun () -> Action.Prog.Not_found.raise e }) add_fail acc ({ fail = fun () -> Action.Prog.Not_found.raise e })
end end
| Pair ("findlib", s) when syntax_version >= (1, 0) -> | Some Lib -> begin
Loc.fail
loc
"The findlib special variable is not supported in jbuild files, \
please use lib instead:\n%%{lib:%s} in dune files"
s
| Pair ("findlib", s)
| Pair ("lib", s) -> begin
let lib_dep, file = parse_lib_file ~loc s in let lib_dep, file = parse_lib_file ~loc s in
add_lib_dep acc lib_dep dep_kind; add_lib_dep acc lib_dep dep_kind;
match match
@ -678,7 +614,7 @@ module Action = struct
| Ok path -> Some (path_exp path) | Ok path -> Some (path_exp path)
| Error fail -> add_fail acc fail | Error fail -> add_fail acc fail
end end
| Pair ("libexec" , s) -> begin | Some Libexec -> begin
let sctx = host sctx in let sctx = host sctx in
let lib_dep, file = parse_lib_file ~loc s in let lib_dep, file = parse_lib_file ~loc s in
add_lib_dep acc lib_dep dep_kind; add_lib_dep acc lib_dep dep_kind;
@ -699,11 +635,13 @@ module Action = struct
add_ddep acc ~key dep add_ddep acc ~key dep
end end
end end
| Pair ("lib-available", lib) -> | Some Lib_available -> begin
add_lib_dep acc lib Optional; let lib = s in
Some (str_exp (string_of_bool ( add_lib_dep acc lib Optional;
Lib.DB.available (Scope.libs scope) lib))) Some (str_exp (string_of_bool (
| Pair ("version", s) -> begin Lib.DB.available (Scope.libs scope) lib)))
end
| Some Version -> begin
match Package.Name.Map.find (Scope.project scope).packages match Package.Name.Map.find (Scope.project scope).packages
(Package.Name.of_string s) with (Package.Name.of_string s) with
| Some p -> | Some p ->
@ -718,7 +656,7 @@ module Action = struct
Loc.fail loc "Package %S doesn't exist in the current project." s Loc.fail loc "Package %S doesn't exist in the current project." s
} }
end end
| Pair ("read", s) -> begin | Some Read -> begin
let path = Path.relative dir s in let path = Path.relative dir s in
let data = let data =
Build.contents path Build.contents path
@ -726,7 +664,7 @@ module Action = struct
in in
add_ddep acc ~key data add_ddep acc ~key data
end end
| Pair ("read-lines", s) -> begin | Some Read_lines -> begin
let path = Path.relative dir s in let path = Path.relative dir s in
let data = let data =
Build.lines_of path Build.lines_of path
@ -734,7 +672,7 @@ module Action = struct
in in
add_ddep acc ~key data add_ddep acc ~key data
end end
| Pair ("read-strings", s) -> begin | Some Read_strings -> begin
let path = Path.relative dir s in let path = Path.relative dir s in
let data = let data =
Build.strings path Build.strings path
@ -742,62 +680,46 @@ module Action = struct
in in
add_ddep acc ~key data add_ddep acc ~key data
end end
| _ -> | Some Path_no_dep -> Some [Value.Dir (Path.relative dir s)]
match expand_var_no_root sctx key with | None ->
| Some _ as x -> x Loc.fail (String_with_vars.Var.loc var) "Unknown form: %a"
| None -> String.Map.find extra_vars key String_with_vars.Var.pp var
end
in in
let targets loc name = let expand var syntax_version =
let var = let loc = String_with_vars.Var.loc var in
match name with let key = String_with_vars.Var.full_name var in
| "@" -> sprintf "${%s}" name let res =
| "targets" -> sprintf "%%{%s}" name match String_with_vars.Var.destruct var with
| _ -> assert false | Macro (_, s) -> expand_form s var syntax_version
| Var var_name ->
begin match expand_vars sctx ~syntax_version ~var with
| None -> String.Map.find extra_vars key
| Some Targets ->
let var () =
match var_name with
| "@" -> sprintf "${%s}" var_name
| "targets" -> sprintf "%%{%s}" var_name
| _ -> assert false
in
begin match targets_written_by_user with
| Infer ->
Loc.fail loc "You cannot use %s with inferred rules." (var ())
| Alias ->
Loc.fail loc "You cannot use %s in aliases." (var ())
| Static l ->
Some (Value.L.dirs l) (* XXX hack to signal no dep *)
end
| Some v -> Pform.Var.to_value_no_deps_or_targets v ~scope
end
in in
match targets_written_by_user with Option.iter res ~f:(fun v ->
| Infer -> Loc.fail loc "You cannot use %s with inferred rules." var acc.sdeps <- Path.Set.union
| Alias -> Loc.fail loc "You cannot use %s in aliases." var (Path.Set.of_list (Value.L.deps_only v)) acc.sdeps
| Static l -> Some (Value.L.paths l) );
in res
let t =
U.partial_expand t ~dir ~map_exe ~f:(fun var syntax_version ->
let var_name = String_with_vars.Var.full_name var in
let loc = String_with_vars.Var.loc var in
match var_name with
| "ROOT" -> Some (path_exp sctx.context.build_dir)
| "SCOPE_ROOT" ->
if syntax_version >= (1, 0) then
Loc.fail loc
"Variable %%{SCOPE_ROOT} has been renamed to %%{project_root} \
in dune files"
else
Some (path_exp (Scope.root scope))
| "project_root" when syntax_version >= (1, 0) ->
Some (path_exp (Scope.root scope))
| "@" ->
if syntax_version < (1, 0) then
targets loc var_name
else
Loc.fail loc (* variable substitution to avoid ugly escaping *)
"Variable %s has been renamed to %%{targets} in dune files" "%{@}"
| "targets" when syntax_version >= (1, 0) -> targets loc var_name
| _ ->
match String_with_vars.Var.destruct var with
| Pair ("path-no-dep", s) ->
if syntax_version < (1, 0) then
Some (path_exp (Path.relative dir s))
else
Loc.fail
loc
"The ${path-no-dep:...} syntax has been removed from dune."
| _ ->
let exp = expand var syntax_version in
Option.iter exp ~f:(fun vs ->
acc.sdeps <- Path.Set.union (Path.Set.of_list
(Value.L.paths_only vs)) acc.sdeps;
);
exp)
in in
let t = U.partial_expand t ~dir ~map_exe ~f:expand in
(t, acc) (t, acc)
let expand_step2 ~dir ~dynamic_expansions ~deps_written_by_user ~map_exe t = let expand_step2 ~dir ~dynamic_expansions ~deps_written_by_user ~map_exe t =
@ -807,32 +729,20 @@ 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 ->
let first_dep () = Pform.Map.expand Pform.Map.static_vars ~syntax_version ~var
Some ( |> Option.map ~f:(function
match deps_written_by_user with | Pform.Var.Deps -> (Value.L.paths deps_written_by_user)
| First_dep ->
begin match deps_written_by_user with
| [] -> | [] ->
Loc.warn loc "Variable '%s' used with no explicit \ Loc.warn loc "Variable '%s' used with no explicit \
dependencies@." key; dependencies@." key;
[Value.String ""] [Value.String ""]
| v :: _ -> [Path v] | v :: _ -> [Path v]
) end
in | _ ->
match key with Exn.code_error "Unexpected variable in step2"
| "<" -> ["var", String_with_vars.Var.sexp_of_t var]))
if syntax_version < (1, 0) then
first_dep ()
else
Loc.fail loc "Variable '<' is renamed to 'first-dep' in dune files"
| "first-dep" when syntax_version >= (1, 0) -> first_dep ()
| "^" ->
if syntax_version < (1, 0) then
Some (Value.L.paths deps_written_by_user)
else
Loc.fail loc
"Variable %%{^} has been renamed to %%{deps} in dune files"
| "deps" when syntax_version >= (1, 0) ->
Some (Value.L.paths deps_written_by_user)
| _ -> None)
let run sctx ~loc ?(extra_vars=String.Map.empty) let run sctx ~loc ?(extra_vars=String.Map.empty)
t ~dir ~dep_kind ~targets:targets_written_by_user ~scope t ~dir ~dep_kind ~targets:targets_written_by_user ~scope

View File

@ -78,7 +78,7 @@ val dump_env : t -> dir:Path.t -> (unit, Sexp.t list) Build.t
val find_scope_by_dir : t -> Path.t -> Scope.t val find_scope_by_dir : t -> Path.t -> Scope.t
val find_scope_by_name : t -> Dune_project.Name.t -> Scope.t val find_scope_by_name : t -> Dune_project.Name.t -> Scope.t
val expand_vars val expand_vars_string
: t : t
-> scope:Scope.t -> scope:Scope.t
-> dir:Path.t -> dir:Path.t

View File

@ -56,6 +56,21 @@ type t =
; supported_versions : Supported_versions.t ; supported_versions : Supported_versions.t
} }
module Error = struct
let since loc t ver ~what =
Loc.fail loc "%s is only available since version %s of %s"
what (Version.to_string ver) t.desc
let renamed_in loc t ver ~what ~to_ =
Loc.fail loc "%s was renamed to '%s' in the %s version of %s"
what to_ (Version.to_string ver) t.desc
let deleted_in loc t ver ~what =
Loc.fail loc "%s was deleted in version %s of %s"
what (Version.to_string ver) t.desc
end
let create ~name ~desc supported_versions = let create ~name ~desc supported_versions =
{ name { name
; desc ; desc
@ -112,9 +127,7 @@ let deleted_in t ver =
return () return ()
else begin else begin
desc () >>= fun (loc, what) -> desc () >>= fun (loc, what) ->
Loc.fail loc Error.deleted_in loc t ver ~what
"%s was deleted in version %s of %s" what
(Version.to_string ver) t.desc
end end
let renamed_in t ver ~to_ = let renamed_in t ver ~to_ =
@ -123,9 +136,7 @@ let renamed_in t ver ~to_ =
return () return ()
else begin else begin
desc () >>= fun (loc, what) -> desc () >>= fun (loc, what) ->
Loc.fail loc Error.renamed_in loc t ver ~what ~to_
"%s was renamed to '%s' in the %s version of %s" what to_
(Version.to_string ver) t.desc
end end
let since t ver = let since t ver =
@ -134,7 +145,5 @@ let since t ver =
return () return ()
else begin else begin
desc () >>= fun (loc, what) -> desc () >>= fun (loc, what) ->
Loc.fail loc Error.since loc t ver ~what
"%s is only available since version %s of %s" what
(Version.to_string ver) t.desc
end end

View File

@ -20,6 +20,14 @@ end
type t type t
module Error : sig
val since : Loc.t -> t -> Version.t -> what:string -> _
val renamed_in : Loc.t -> t -> Version.t -> what:string -> to_:string -> _
val deleted_in : Loc.t -> t -> Version.t -> what:string -> _
end
(** [create ~name ~desc supported_versions] defines a new (** [create ~name ~desc supported_versions] defines a new
syntax. [supported_version] is the list of the last minor version syntax. [supported_version] is the list of the last minor version
of each supported major version. [desc] is used to describe what of each supported major version. [desc] is used to describe what

View File

@ -41,6 +41,18 @@ let rec pp syntax ppf = function
Format.pp_close_box ppf () Format.pp_close_box ppf ()
| Template t -> Template.pp syntax ppf t | Template t -> Template.pp syntax ppf t
let pp_quoted =
let rec loop = function
| Atom (A s) as t ->
if Atom.is_valid_dune s then
t
else
Quoted_string s
| List xs -> List (List.map ~f:loop xs)
| (Quoted_string _ | Template _) as t -> t
in
fun ppf t -> pp Dune ppf (loop t)
let pp_print_quoted_string ppf s = let pp_print_quoted_string ppf s =
let syntax = Dune in let syntax = Dune in
if String.contains s '\n' then begin if String.contains s '\n' then begin

View File

@ -76,6 +76,10 @@ val to_string : t -> syntax:syntax -> string
(** Serialize a S-expression using indentation to improve readability *) (** Serialize a S-expression using indentation to improve readability *)
val pp : syntax -> Format.formatter -> t -> unit val pp : syntax -> Format.formatter -> t -> unit
(** Serialization that never fails because it quotes atoms when necessary
TODO remove this once we have a proper sexp type *)
val pp_quoted : Format.formatter -> t -> unit
(** Same as [pp ~syntax:Dune], but split long strings. The formatter (** Same as [pp ~syntax:Dune], but split long strings. The formatter
must have been prepared with [prepare_formatter]. *) must have been prepared with [prepare_formatter]. *)
val pp_split_strings : Format.formatter -> t -> unit val pp_split_strings : Format.formatter -> t -> unit

View File

@ -2,6 +2,7 @@ open Stdune
type t = type t =
| String of string | String of string
| Dir of Path.t
| Path of Path.t | Path of Path.t
let string_of_path ~dir p = Path.reach ~from:dir p let string_of_path ~dir p = Path.reach ~from:dir p
@ -9,11 +10,13 @@ let string_of_path ~dir p = Path.reach ~from:dir p
let to_string t ~dir = let to_string t ~dir =
match t with match t with
| String s -> s | String s -> s
| Dir p
| Path p -> string_of_path ~dir p | Path p -> string_of_path ~dir p
let to_path ?error_loc t ~dir = let to_path ?error_loc t ~dir =
match t with match t with
| String s -> Path.relative ?error_loc dir s | String s -> Path.relative ?error_loc dir s
| Dir p
| Path p -> p | Path p -> p
module L = struct module L = struct
@ -23,12 +26,15 @@ module L = struct
List.map ~f:(to_string ~dir) ts List.map ~f:(to_string ~dir) ts
|> String.concat ~sep:" " |> String.concat ~sep:" "
let paths_only = let deps_only =
List.filter_map ~f:(function List.filter_map ~f:(function
| Dir _
| String _ -> None | String _ -> None
| Path p -> Some p) | Path p -> Some p)
let strings = List.map ~f:(fun x -> String x) let strings = List.map ~f:(fun x -> String x)
let paths = List.map ~f:(fun x -> Path x) let paths = List.map ~f:(fun x -> Path x)
let dirs = List.map ~f:(fun x -> Dir x)
end end

View File

@ -2,6 +2,7 @@ open Stdune
type t = type t =
| String of string | String of string
| Dir of Path.t
| Path of Path.t | Path of Path.t
val to_string : t -> dir:Path.t -> string val to_string : t -> dir:Path.t -> string
@ -13,7 +14,9 @@ module L : sig
val paths : Path.t list -> t list val paths : Path.t list -> t list
val paths_only : t list -> Path.t list val deps_only : t list -> Path.t list
val dirs : Path.t list -> t list
val concat : t list -> dir:Path.t -> string val concat : t list -> dir:Path.t -> string

View File

@ -88,6 +88,14 @@
test-cases/depend-on-the-universe test-cases/depend-on-the-universe
(progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected))))) (progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected)))))
(alias
(name dune-jbuild-var-case)
(deps (package dune) (source_tree test-cases/dune-jbuild-var-case))
(action
(chdir
test-cases/dune-jbuild-var-case
(progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected)))))
(alias (alias
(name dune-ppx-driver-system) (name dune-ppx-driver-system)
(deps (package dune) (source_tree test-cases/dune-ppx-driver-system)) (deps (package dune) (source_tree test-cases/dune-ppx-driver-system))
@ -362,6 +370,14 @@
test-cases/loop test-cases/loop
(progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected))))) (progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected)))))
(alias
(name macro-expand-error)
(deps (package dune) (source_tree test-cases/macro-expand-error))
(action
(chdir
test-cases/macro-expand-error
(progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected)))))
(alias (alias
(name menhir) (name menhir)
(deps (package dune) (source_tree test-cases/menhir)) (deps (package dune) (source_tree test-cases/menhir))
@ -641,6 +657,7 @@
(alias cross-compilation) (alias cross-compilation)
(alias custom-build-dir) (alias custom-build-dir)
(alias depend-on-the-universe) (alias depend-on-the-universe)
(alias dune-jbuild-var-case)
(alias dune-ppx-driver-system) (alias dune-ppx-driver-system)
(alias dune-project-edition) (alias dune-project-edition)
(alias env) (alias env)
@ -673,6 +690,7 @@
(alias lib-available) (alias lib-available)
(alias link-deps) (alias link-deps)
(alias loop) (alias loop)
(alias macro-expand-error)
(alias menhir) (alias menhir)
(alias merlin-tests) (alias merlin-tests)
(alias meta-gen) (alias meta-gen)
@ -718,6 +736,7 @@
(alias cross-compilation) (alias cross-compilation)
(alias custom-build-dir) (alias custom-build-dir)
(alias depend-on-the-universe) (alias depend-on-the-universe)
(alias dune-jbuild-var-case)
(alias dune-ppx-driver-system) (alias dune-ppx-driver-system)
(alias dune-project-edition) (alias dune-project-edition)
(alias env) (alias env)
@ -748,6 +767,7 @@
(alias lib-available) (alias lib-available)
(alias link-deps) (alias link-deps)
(alias loop) (alias loop)
(alias macro-expand-error)
(alias merlin-tests) (alias merlin-tests)
(alias meta-gen) (alias meta-gen)
(alias misc) (alias misc)

View File

@ -1,3 +1,3 @@
(alias (alias
(name x) (name x)
(action (chdir %{ROOT} (echo "running in .\n")))) (action (chdir %{root} (echo "running in .\n"))))

View File

@ -1,3 +1,3 @@
(alias (alias
(name x) (name x)
(action (chdir %{ROOT} (echo "running in bar\n")))) (action (chdir %{root} (echo "running in bar\n"))))

View File

@ -1,3 +1,3 @@
(alias (alias
(name x) (name x)
(action (chdir %{ROOT} (echo "running in baz\n")))) (action (chdir %{root} (echo "running in baz\n"))))

View File

@ -0,0 +1,3 @@
(alias
(name runtest)
(action (with-stdout-to %{null} (echo %{make}))))

View File

@ -0,0 +1 @@
(lang dune 1.0)

View File

@ -0,0 +1,3 @@
(alias
(name runtest)
(action (with-stdout-to %{null} (echo %{MAKE}))))

View File

@ -0,0 +1 @@
(lang dune 1.0)

View File

@ -0,0 +1,3 @@
(alias
((name runtest)
(action (with-stdout-to ${null} (echo ${make})))))

View File

@ -0,0 +1,3 @@
(alias
((name runtest)
(action (with-stdout-to ${null} (echo ${MAKE})))))

View File

@ -0,0 +1,18 @@
All builtin variables are lower cased in Dune:
$ dune runtest --root dune-lower
Entering directory 'dune-lower'
$ dune runtest --root dune-upper
Entering directory 'dune-upper'
File "dune", line 3, characters 41-46:
Error: %{MAKE} was renamed to '%{make}' in the 1.0 version of the dune language
[1]
jbuild files retain the the old names:
$ dune runtest --root jbuilder-upper
Entering directory 'jbuilder-upper'
$ dune runtest --root jbuilder-upper
Entering directory 'jbuilder-upper'

View File

@ -3,8 +3,7 @@ We are dropping support for findlib in dune
$ dune build --root in-dune target.txt $ dune build --root in-dune target.txt
Entering directory 'in-dune' Entering directory 'in-dune'
File "dune", line 2, characters 25-37: File "dune", line 2, characters 25-37:
Error: The findlib special variable is not supported in jbuild files, please use lib instead: Error: %{findlib:..} was renamed to '%{lib:..}' in the 1.0 version of the dune language
%{lib:pkg} in dune files
[1] [1]
But it must still be available in jbuild files But it must still be available in jbuild files

View File

@ -12,7 +12,7 @@
(echo "\n") (echo "\n")
(echo "let () = print_int 43;;"))) (echo "let () = print_int 43;;")))
(flags inline-test-runner %{library-name} (flags inline-test-runner %{library-name}
-source-tree-root %{ROOT} -diff-cmd -))) -source-tree-root %{root} -diff-cmd -)))
(library (library
(name foo_tests) (name foo_tests)

View File

@ -30,7 +30,7 @@
(inline-test-runner (inline-test-runner
%{library-name} %{library-name}
-source-tree-root -source-tree-root
%{ROOT} %{root}
-diff-cmd -diff-cmd
-)) -))
(generate_runner (generate_runner

View File

@ -0,0 +1 @@
(copy_files %{read:x}/*)

View File

@ -0,0 +1,8 @@
we're getting an acceptable error message when adding a macro form in an
inappropariate place:
$ dune build
Info: creating file dune-project with this contents: (lang dune 1.0)
File "dune", line 1, characters 14-21:
Error: macros of the form %{name:..} cannot be expanded here
[1]

View File

@ -8,7 +8,9 @@ In expands to a file name, and registers this as a dependency.
$ dune build --root dune @test-dep $ dune build --root dune @test-dep
Entering directory 'dune' Entering directory 'dune'
dynamic-contents File "dune", line 13, characters 17-47:
Error: %{path:..} was renamed to '%{dep:..}' in the 1.0 version of the dune language
[1]
%{path-no-dep:string} %{path-no-dep:string}
--------------------- ---------------------
@ -18,7 +20,7 @@ This form does not exist, but displays an hint:
$ dune build --root dune-invalid @test-path-no-dep $ dune build --root dune-invalid @test-path-no-dep
Entering directory 'dune-invalid' Entering directory 'dune-invalid'
File "dune", line 7, characters 17-54: File "dune", line 7, characters 17-54:
Error: The ${path-no-dep:...} syntax has been removed from dune. Error: %{path-no-dep:..} was deleted in version 1.0 of the dune language
[1] [1]
jbuild files jbuild files
@ -51,6 +53,5 @@ This form does not exist, but displays an hint:
$ dune build --root jbuild-invalid @test-dep $ dune build --root jbuild-invalid @test-dep
Entering directory 'jbuild-invalid' Entering directory 'jbuild-invalid'
File "jbuild", line 5, characters 16-37: File "jbuild", line 5, characters 16-37:
Error: ${dep:generated-file} is not supported in jbuild files. Error: ${dep:..} is only available since version 1.0 of the dune language
Hint: Did you mean ${path:generated-file} instead?
[1] [1]