implement the manual properly for (install ...) stanzas
This commit is contained in:
parent
efbe548612
commit
2e7d592f66
23
ROADMAP.org
23
ROADMAP.org
|
@ -116,3 +116,26 @@ Load a configuration file from =~/.config/jbuilder/config.sexp= where
|
||||||
the user can define preferences such as colors.
|
the user can define preferences such as colors.
|
||||||
** Code improvements
|
** Code improvements
|
||||||
*** Delete the global variables in Clflags
|
*** Delete the global variables in Clflags
|
||||||
|
*** Consolidate the S-expression parser
|
||||||
|
|
||||||
|
It doesn't follow the specification given in the readme of
|
||||||
|
[[https://github.com/janestreet/parsexp][parsexp]]. This need to be fixed.
|
||||||
|
** Make =Jbuild_plugin= a library
|
||||||
|
|
||||||
|
Currently Jbuilder generates a wrapper script containing the source
|
||||||
|
code of the =Jbuild_plugin= followed by the user script. While this
|
||||||
|
method is trivial to implement, it is not great if users want to write
|
||||||
|
libraries for jbuild plugins.
|
||||||
|
|
||||||
|
What we should do instead is create a proper =jbuild_plugin= library
|
||||||
|
that is installed. This library should read a file containing the
|
||||||
|
build context details generated by Jbuilder and passed as
|
||||||
|
=Sys.argv.(1)=.
|
||||||
|
|
||||||
|
We need to refactor things a bit to make this happen, in particular
|
||||||
|
the library will propably need to know how to parse s-expression. We
|
||||||
|
can create a =jbuild_common= library to put the parts that are common
|
||||||
|
between =jbuild_plugin= and =jbuilder=.
|
||||||
|
|
||||||
|
Note that =doc/jbuild= is an OCaml script. To simplify the bootstrap,
|
||||||
|
we should just convert it back to a static =jbuild= file.
|
||||||
|
|
110
doc/manual.org
110
doc/manual.org
|
@ -39,7 +39,8 @@ it from the crowd:
|
||||||
a great choice for multi-project development
|
a great choice for multi-project development
|
||||||
|
|
||||||
- cross-platform: as long as your code is portable, Jbuilder will be
|
- cross-platform: as long as your code is portable, Jbuilder will be
|
||||||
able to cross-compile it automatically
|
able to cross-compile it (note that Jbuilder is designed internally
|
||||||
|
to make this easy but the actual support is not implemented yet)
|
||||||
|
|
||||||
- release directly from any revision: Jbuilder needs no setup
|
- release directly from any revision: Jbuilder needs no setup
|
||||||
stage. To release your project, you can simply point to a specific
|
stage. To release your project, you can simply point to a specific
|
||||||
|
@ -55,7 +56,7 @@ format and the third one describes how to use the =jbuilder= command.
|
||||||
- *package*: a package is a set of libraries, executables, ... that
|
- *package*: a package is a set of libraries, executables, ... that
|
||||||
are built and installed as one by opam
|
are built and installed as one by opam
|
||||||
|
|
||||||
- *project*: project is a source tree, maybe containing one or more
|
- *project*: a project is a source tree, maybe containing one or more
|
||||||
packages
|
packages
|
||||||
|
|
||||||
- *root*: the root is the directory from where Jbuilder can build
|
- *root*: the root is the directory from where Jbuilder can build
|
||||||
|
@ -72,31 +73,34 @@ format and the third one describes how to use the =jbuilder= command.
|
||||||
|
|
||||||
- *build context*: a build context is a subdirectory of the
|
- *build context*: a build context is a subdirectory of the
|
||||||
=<root>/_build= directory. It contains all the build artifacts of
|
=<root>/_build= directory. It contains all the build artifacts of
|
||||||
the workspace built against a specific configuration. The is always
|
the workspace built against a specific configuration. Without
|
||||||
a =default= build context, which correspond to the environemnt in
|
specific configuration from the user, there is always a =default=
|
||||||
which Jbuilder is executed. Unless a =jbuild-workspace= file exists in
|
build context, which correspond to the environemnt in which Jbuilder
|
||||||
a parent directory and defines more build contexts, =default= is the
|
is executed. Build contexts can be specified by writing a
|
||||||
only build context available
|
[[jbuild-workspace]] file
|
||||||
|
|
||||||
|
- *build context root*: the root of a build context named =foo= is
|
||||||
|
=<root>/_build/<foo>=
|
||||||
|
|
||||||
- *alias*: an alias is a build target that doesn't produce any file
|
- *alias*: an alias is a build target that doesn't produce any file
|
||||||
and has configurable dependencies. Alias are per-directory and some
|
and has configurable dependencies. Alias are per-directory and some
|
||||||
are recursive; asking an alias to be built in a given directrory
|
are recursive; asking an alias to be built in a given directrory
|
||||||
will trigger the construction of the alias in all children
|
will trigger the construction of the alias in all children
|
||||||
directories recursively. The most interesting one is =runtest=,
|
directories recursively. The most interesting ones are:
|
||||||
which will run user defined tests
|
+ =runtest= which runs user defined tests
|
||||||
|
+ =install= which depends on everything that should be installed
|
||||||
|
|
||||||
* Jbuilder project layout and metadata specification
|
* Jbuilder project layout and metadata specification
|
||||||
|
|
||||||
A typical jbuilder project will have one or more =<package>.opam= file
|
A typical jbuilder project will have one or more =<package>.opam= file
|
||||||
at toplevel as well as =jbuild= files at toplevel and wherever
|
at toplevel as well as =jbuild= files wherever interesting things are:
|
||||||
interesting things are: libraries, executables, tests, documents to
|
libraries, executables, tests, documents to install, etc...
|
||||||
install, etc...
|
|
||||||
|
|
||||||
It is recommemded to organize your project so that you have exactly
|
It is recommemded to organize your project so that you have exactly
|
||||||
one library per directory. You can have several executables in the
|
one library per directory. You can have several executables in the
|
||||||
same directory, as long as they share the same build configuration.
|
same directory, as long as they share the same build configuration.
|
||||||
|
|
||||||
The rest of these section describe the format of Jbuilder metadata
|
The rest of these sections describe the format of Jbuilder metadata
|
||||||
files.
|
files.
|
||||||
|
|
||||||
Note that the Jbuilder metadata format is versionned in order to
|
Note that the Jbuilder metadata format is versionned in order to
|
||||||
|
@ -113,24 +117,23 @@ latest one will be used.
|
||||||
|
|
||||||
** Metadata format
|
** Metadata format
|
||||||
|
|
||||||
All configuration files read by Jbuilder are using S-expression
|
Most configuration files read by Jbuilder are using the S-expression
|
||||||
syntax, which is very simple. Everything is either an atom or a
|
syntax, which is very simple. Everything is either an atom or a
|
||||||
list. The exact specification of S-expressions is described in the
|
list. The exact specification of S-expressions is described in the
|
||||||
documentation of the [[https://github.com/janestreet/parsexp][parsexp]] library.
|
documentation of the [[https://github.com/janestreet/parsexp][parsexp]] library.
|
||||||
|
|
||||||
Note that the format is completely static. If you have a pattern
|
Note that the format is completely static. However you can do
|
||||||
that's repeated a lot, you can use [[https://github.com/janestreet/cinaps][cinaps]] to generate the boilerplate.
|
meta-programming on jbuilds files by writing them in [[OCaml syntax]].
|
||||||
|
|
||||||
** <package>.opam files
|
** <package>.opam files
|
||||||
|
|
||||||
Jbuilder doesn't read =<package>.opam= files, however when a
|
When a =<package>.opam= file is present, Jbuilder will knows that the
|
||||||
=<package>.opam= is present, Jbuilder will knows that the package
|
package named =<package>= exists. It will know how to construct a
|
||||||
named =<package>= exists. It will know how to construct a
|
=<package>.install= file in the same directory to handle installation
|
||||||
=<package>.install= file in the same directory, to handle installation
|
via [[https://opam.ocaml.org/][opam]]. Jbuilder also defines the recursive =install= alias, which
|
||||||
via [[https://opam.ocaml.org/][opam]]. Jbuilder also defines the recursive =install= alias, which depends
|
depends on all the buildable =<package>.install= files in the
|
||||||
on all the buildable =<package>.install= files in the workspace. So
|
workspace. So for instance to build everything that is installable in
|
||||||
for instance to build everything that is installable in a workspace,
|
a workspace, run at the root:
|
||||||
run at the root:
|
|
||||||
|
|
||||||
#+begin_src
|
#+begin_src
|
||||||
$ jbuilder build @install
|
$ jbuilder build @install
|
||||||
|
@ -148,14 +151,13 @@ this is where =opam pin ...= will look for them.
|
||||||
|
|
||||||
*** Package version
|
*** Package version
|
||||||
|
|
||||||
Note that when installing a package, Jbuilder will write down the
|
Note that Jbuilder will try to determine the version number of
|
||||||
version of the package in the installation directory. While Jbuilder
|
packages defined in the workspace. While Jbuilder itself makes no use
|
||||||
makes no use of it at the moment, it can be use by external tools such
|
of version numbers, it can be use by external tools such as [[http://projects.camlcity.org/projects/findlib.html][ocamlfind]].
|
||||||
as [[http://projects.camlcity.org/projects/findlib.html][ocamlfind]].
|
|
||||||
|
|
||||||
Jbuilder determines the version of a package by first looking in the
|
Jbuilder determines the version of a package by first looking in the
|
||||||
=<package>.opam= contains a =version= variable. If not, it will try to
|
=<package>.opam= for a =version= variable. If not found, it will try
|
||||||
read the first line of a version file in the same directory as the
|
to read the first line of a version file in the same directory as the
|
||||||
=<package>.opam= file. The version file is any file whose name is, in
|
=<package>.opam= file. The version file is any file whose name is, in
|
||||||
order in which they are looked for:
|
order in which they are looked for:
|
||||||
|
|
||||||
|
@ -163,12 +165,9 @@ order in which they are looked for:
|
||||||
- =version=
|
- =version=
|
||||||
- =VERSION=
|
- =VERSION=
|
||||||
|
|
||||||
The version file can be generated by a rule.
|
The version file can be generated by a user rule.
|
||||||
|
|
||||||
Note that it is not mandatory to specify a version number and if
|
If the version can't be determined, Jbuilder just won't assign one.
|
||||||
Jbuilder cannot determine the package version, then it just won't
|
|
||||||
assign one. Managing versions should be left to package managers
|
|
||||||
anyway.
|
|
||||||
|
|
||||||
*** Odig conventions
|
*** Odig conventions
|
||||||
|
|
||||||
|
@ -177,8 +176,8 @@ README*, CHANGE*, HISTORY* and LICENSE* files in the same directory as
|
||||||
the =<package>.opam= file to a location where odig will find them.
|
the =<package>.opam= file to a location where odig will find them.
|
||||||
|
|
||||||
Note that this include files present in the source tree as well as
|
Note that this include files present in the source tree as well as
|
||||||
generated files. So for instance a changelog generated by a rule will
|
generated files. So for instance a changelog generated by a user rule
|
||||||
be automatically installed as well.
|
will be automatically installed as well.
|
||||||
|
|
||||||
** jbuild
|
** jbuild
|
||||||
|
|
||||||
|
@ -201,9 +200,7 @@ The script can use the directive =#require= to access libraries:
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Note that any library required by a =jbuild= file must be part of the
|
Note that any library required by a =jbuild= file must be part of the
|
||||||
installed world. This mean that your project won't be compilable in
|
installed world.
|
||||||
the same workspace as the required library, unless the library has
|
|
||||||
been previously installed.
|
|
||||||
|
|
||||||
If you don't like the S-expression syntax, then this method gives you
|
If you don't like the S-expression syntax, then this method gives you
|
||||||
a way to use whatever else you want. For instance you could have an
|
a way to use whatever else you want. For instance you could have an
|
||||||
|
@ -218,6 +215,10 @@ let () =
|
||||||
library "foo" ~modules:["plop"; "bidule"]
|
library "foo" ~modules:["plop"; "bidule"]
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
Currently the =Jbuild_plugin= module is only available inside
|
||||||
|
plugins. It is however planned to make it a proper library, see [[../ROADMAP.org][the
|
||||||
|
roadmap]] for details.
|
||||||
|
|
||||||
*** Specification
|
*** Specification
|
||||||
|
|
||||||
=jbuild= files are composed of stanzas. For instance a typical
|
=jbuild= files are composed of stanzas. For instance a typical
|
||||||
|
@ -273,7 +274,7 @@ the library and you are free to expose only the modules you want.
|
||||||
field, the library will not be installed by Jbuilder. The public
|
field, the library will not be installed by Jbuilder. The public
|
||||||
name must start by the package name it is part of and optionally
|
name must start by the package name it is part of and optionally
|
||||||
followed by a dot and anything else you want. The package name must
|
followed by a dot and anything else you want. The package name must
|
||||||
be one of the package that Jbuilder knows about, as determined by
|
be one of the packages that Jbuilder knows about, as determined by
|
||||||
the [[package.opam][<package>.opam files]]
|
the [[package.opam][<package>.opam files]]
|
||||||
|
|
||||||
- =(synopsis <string>)= should give a one-line description of the
|
- =(synopsis <string>)= should give a one-line description of the
|
||||||
|
@ -305,7 +306,7 @@ the library and you are free to expose only the modules you want.
|
||||||
toplevel namespace will make your library unusable with other
|
toplevel namespace will make your library unusable with other
|
||||||
libraries if there is a module name clash. This option is only
|
libraries if there is a module name clash. This option is only
|
||||||
intended for libraries that manually prefix all their modules by the
|
intended for libraries that manually prefix all their modules by the
|
||||||
library name
|
library name and to ease porting of existing projects to Jbuilder
|
||||||
|
|
||||||
- =(preprocess <preprocess-spec>)= specifies how to pre-process files
|
- =(preprocess <preprocess-spec>)= specifies how to pre-process files
|
||||||
if needed. The default is =no_processing=. Other options are
|
if needed. The default is =no_processing=. Other options are
|
||||||
|
@ -327,7 +328,7 @@ the library and you are free to expose only the modules you want.
|
||||||
|
|
||||||
- =(cxx_names (<names>))= is the same as =c_names= but for C++ stubs
|
- =(cxx_names (<names>))= is the same as =c_names= but for C++ stubs
|
||||||
|
|
||||||
- =(install_c_headers (<names>))= if your libraries has public C
|
- =(install_c_headers (<names>))=, if your libraries has public C
|
||||||
header files that must be installed, you must list them in this
|
header files that must be installed, you must list them in this
|
||||||
field, with the =.h= extension
|
field, with the =.h= extension
|
||||||
|
|
||||||
|
@ -340,9 +341,9 @@ the library and you are free to expose only the modules you want.
|
||||||
=ppx_type_conv_plugin= and must be set when the library is intended
|
=ppx_type_conv_plugin= and must be set when the library is intended
|
||||||
to be used as a ppx rewriter or a =[@@deriving ...]= plugin
|
to be used as a ppx rewriter or a =[@@deriving ...]= plugin
|
||||||
|
|
||||||
- =(ppx_runtime_libraries (<library-names>))= when the library is a
|
- =(ppx_runtime_libraries (<library-names>))= is for when the library
|
||||||
ppx rewriter or a =[@@deriving ...]= plugin and has runtime
|
is a ppx rewriter or a =[@@deriving ...]= plugin and has runtime
|
||||||
dependencies, you can specify them here
|
dependencies. You need to specify these runtime dependencies them here
|
||||||
|
|
||||||
- =(virtual_deps (<opam-packages>)=. Sometimes opam packages enable a
|
- =(virtual_deps (<opam-packages>)=. Sometimes opam packages enable a
|
||||||
specific feature only if another package is installed. This is for
|
specific feature only if another package is installed. This is for
|
||||||
|
@ -359,7 +360,7 @@ the library and you are free to expose only the modules you want.
|
||||||
to =ocamlc= and =ocamlopt= when building the library archive
|
to =ocamlc= and =ocamlopt= when building the library archive
|
||||||
files. You can use this to specify =-linkall= for
|
files. You can use this to specify =-linkall= for
|
||||||
instance. =<flags>= is a list of strings supporting [[Variables expansion][variables
|
instance. =<flags>= is a list of strings supporting [[Variables expansion][variables
|
||||||
expansion]].
|
expansion]]
|
||||||
|
|
||||||
- =(c_flags <flags>)= specifies the compilation flags for C stubs,
|
- =(c_flags <flags>)= specifies the compilation flags for C stubs,
|
||||||
using the [[Ordered set language][ordered set language]]. This field supports =(:include ...)=
|
using the [[Ordered set language][ordered set language]]. This field supports =(:include ...)=
|
||||||
|
@ -403,7 +404,7 @@ Note that in case native compilation is not available, =<name>.exe=
|
||||||
will in fact be a custom byte-code executable. Custom in the sense of
|
will in fact be a custom byte-code executable. Custom in the sense of
|
||||||
=ocamlc -custom=, meaning that it is a native executable that embeds
|
=ocamlc -custom=, meaning that it is a native executable that embeds
|
||||||
the =ocamlrun= virtual machine as well as the byte code. As such you
|
the =ocamlrun= virtual machine as well as the byte code. As such you
|
||||||
can always rely on =<name>.exe= begin available.
|
can always rely on =<name>.exe= being available.
|
||||||
|
|
||||||
=<optional-fields>= are:
|
=<optional-fields>= are:
|
||||||
|
|
||||||
|
@ -428,9 +429,9 @@ can always rely on =<name>.exe= begin available.
|
||||||
|
|
||||||
**** rule
|
**** rule
|
||||||
|
|
||||||
The =rule= stanza is used to create custom rules. It tells Jbuilder
|
The =rule= stanza is used to create custom user rules. It tells
|
||||||
how to generate a specific set of files from a specific set of
|
Jbuilder how to generate a specific set of files from a specific set
|
||||||
dependencies.
|
of dependencies.
|
||||||
|
|
||||||
The syntax is as follow:
|
The syntax is as follow:
|
||||||
|
|
||||||
|
@ -473,7 +474,6 @@ dependencies. See the [[User actions][actions section]] for more details.
|
||||||
(action (run ocamlyacc ${<}))))
|
(action (run ocamlyacc ${<}))))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
**** alias
|
**** alias
|
||||||
|
|
||||||
The =alias= stanza lets you add dependencies to an alias, or specify
|
The =alias= stanza lets you add dependencies to an alias, or specify
|
||||||
|
@ -516,7 +516,7 @@ See the [[runtest][section about running tests]] for details.
|
||||||
The =provides= stanza allows you to globally name a file, either a
|
The =provides= stanza allows you to globally name a file, either a
|
||||||
source file or a target. This is especially important for build tools;
|
source file or a target. This is especially important for build tools;
|
||||||
by using the =provides= mechanism, you don't need to know whether the
|
by using the =provides= mechanism, you don't need to know whether the
|
||||||
binary is in the tree or installed.
|
binary is in the workspace or installed.
|
||||||
|
|
||||||
The syntax is as follow:
|
The syntax is as follow:
|
||||||
|
|
||||||
|
@ -546,7 +546,7 @@ in points to using the special forms =${bin:<name>}= or
|
||||||
Note that any file referred by a =provides= stanza should probably be
|
Note that any file referred by a =provides= stanza should probably be
|
||||||
installed as well, using an [[install]] stanza. If the file is meant to be
|
installed as well, using an [[install]] stanza. If the file is meant to be
|
||||||
installed in a library directory, then its name should be of the form
|
installed in a library directory, then its name should be of the form
|
||||||
=<public-library-name>:<file>=. It is meant to be installed in the
|
=<public-library-name>:<file>=. If it is meant to be installed in the
|
||||||
=bin= directory, then its name should be the program name.
|
=bin= directory, then its name should be the program name.
|
||||||
|
|
||||||
**** install
|
**** install
|
||||||
|
@ -597,7 +597,7 @@ manual. The following sections are available:
|
||||||
|
|
||||||
***** Ordered set language
|
***** Ordered set language
|
||||||
|
|
||||||
A few fields takes as argument a ordered set and can be specified
|
A few fields takes as argument am ordered set and can be specified
|
||||||
using a small DSL.
|
using a small DSL.
|
||||||
|
|
||||||
This DSL is interpreted by jbuilder into an ordered set of strings
|
This DSL is interpreted by jbuilder into an ordered set of strings
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
((name jbuilder)
|
((name jbuilder)
|
||||||
(public_name jbuilder)
|
(public_name jbuilder)
|
||||||
(libraries (unix jbuilder_re))
|
(libraries (unix jbuilder_re))
|
||||||
(synopsis "Internal Jbuilder library, do not use!"))
|
(synopsis "Internal Jbuilder library, do not use!")))
|
||||||
|
|
||||||
(ocamllex (sexp_lexer meta_lexer glob_lexer))
|
(ocamllex (sexp_lexer meta_lexer glob_lexer))
|
||||||
|
|
|
@ -5,6 +5,7 @@ module Jbuilds = struct
|
||||||
type script =
|
type script =
|
||||||
{ dir : Path.t
|
{ dir : Path.t
|
||||||
; visible_packages : Package.t String_map.t
|
; visible_packages : Package.t String_map.t
|
||||||
|
; closest_packages : Package.t list
|
||||||
}
|
}
|
||||||
|
|
||||||
type one =
|
type one =
|
||||||
|
@ -69,6 +70,7 @@ end
|
||||||
return (path, stanzas)
|
return (path, stanzas)
|
||||||
| Script { dir
|
| Script { dir
|
||||||
; visible_packages
|
; visible_packages
|
||||||
|
; closest_packages
|
||||||
} ->
|
} ->
|
||||||
let file = Path.relative dir "jbuild" in
|
let file = Path.relative dir "jbuild" in
|
||||||
let generated_jbuild =
|
let generated_jbuild =
|
||||||
|
@ -77,7 +79,8 @@ end
|
||||||
let wrapper = Path.extend_basename generated_jbuild ~suffix:".ml" in
|
let wrapper = Path.extend_basename generated_jbuild ~suffix:".ml" in
|
||||||
ensure_parent_dir_exists generated_jbuild;
|
ensure_parent_dir_exists generated_jbuild;
|
||||||
let requires =
|
let requires =
|
||||||
create_plugin_wrapper context ~exec_dir:dir ~plugin:file ~wrapper ~target:generated_jbuild
|
create_plugin_wrapper context ~exec_dir:dir ~plugin:file ~wrapper
|
||||||
|
~target:generated_jbuild
|
||||||
in
|
in
|
||||||
let pkgs =
|
let pkgs =
|
||||||
List.map requires ~f:(Findlib.find_exn context.findlib)
|
List.map requires ~f:(Findlib.find_exn context.findlib)
|
||||||
|
@ -115,7 +118,7 @@ end
|
||||||
args
|
args
|
||||||
>>= fun () ->
|
>>= fun () ->
|
||||||
let sexps = Sexp_load.many (Path.to_string generated_jbuild) in
|
let sexps = Sexp_load.many (Path.to_string generated_jbuild) in
|
||||||
return (dir, Stanzas.parse sexps ~dir ~visible_packages))
|
return (dir, Stanzas.parse sexps ~dir ~visible_packages ~closest_packages))
|
||||||
|> Future.all
|
|> Future.all
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -126,15 +129,16 @@ type conf =
|
||||||
; packages : Package.t String_map.t
|
; packages : Package.t String_map.t
|
||||||
}
|
}
|
||||||
|
|
||||||
let load ~dir ~visible_packages =
|
let load ~dir ~visible_packages ~closest_packages =
|
||||||
let file = Path.relative dir "jbuild" in
|
let file = Path.relative dir "jbuild" in
|
||||||
match Sexp_load.many_or_ocaml_script (Path.to_string file) with
|
match Sexp_load.many_or_ocaml_script (Path.to_string file) with
|
||||||
| Sexps sexps ->
|
| Sexps sexps ->
|
||||||
Jbuilds.Literal (dir, Stanzas.parse sexps ~dir ~visible_packages)
|
Jbuilds.Literal (dir, Stanzas.parse sexps ~dir ~visible_packages ~closest_packages)
|
||||||
| Ocaml_script ->
|
| Ocaml_script ->
|
||||||
Script
|
Script
|
||||||
{ dir
|
{ dir
|
||||||
; visible_packages
|
; visible_packages
|
||||||
|
; closest_packages
|
||||||
}
|
}
|
||||||
|
|
||||||
let load () =
|
let load () =
|
||||||
|
@ -175,20 +179,21 @@ let load () =
|
||||||
|> List.map ~f:(fun pkg -> (pkg.Package.path, pkg))
|
|> List.map ~f:(fun pkg -> (pkg.Package.path, pkg))
|
||||||
|> Path.Map.of_alist_multi
|
|> Path.Map.of_alist_multi
|
||||||
in
|
in
|
||||||
let rec walk dir jbuilds visible_packages =
|
let rec walk dir jbuilds visible_packages closest_packages =
|
||||||
let path = File_tree.Dir.path dir in
|
let path = File_tree.Dir.path dir in
|
||||||
let files = File_tree.Dir.files dir in
|
let files = File_tree.Dir.files dir in
|
||||||
let sub_dirs = File_tree.Dir.sub_dirs dir in
|
let sub_dirs = File_tree.Dir.sub_dirs dir in
|
||||||
let visible_packages =
|
let visible_packages, closest_packages =
|
||||||
match Path.Map.find path packages_per_dir with
|
match Path.Map.find path packages_per_dir with
|
||||||
| None -> visible_packages
|
| None -> (visible_packages, closest_packages)
|
||||||
| Some pkgs ->
|
| Some pkgs ->
|
||||||
List.fold_left pkgs ~init:visible_packages ~f:(fun acc pkg ->
|
(List.fold_left pkgs ~init:visible_packages ~f:(fun acc pkg ->
|
||||||
String_map.add acc ~key:pkg.Package.name ~data:pkg)
|
String_map.add acc ~key:pkg.Package.name ~data:pkg),
|
||||||
|
pkgs)
|
||||||
in
|
in
|
||||||
let jbuilds =
|
let jbuilds =
|
||||||
if String_set.mem "jbuild" files then
|
if String_set.mem "jbuild" files then
|
||||||
let jbuild = load ~dir:path ~visible_packages in
|
let jbuild = load ~dir:path ~visible_packages ~closest_packages in
|
||||||
jbuild :: jbuilds
|
jbuild :: jbuilds
|
||||||
else
|
else
|
||||||
jbuilds
|
jbuilds
|
||||||
|
@ -207,13 +212,13 @@ let load () =
|
||||||
let children, jbuilds =
|
let children, jbuilds =
|
||||||
String_map.fold sub_dirs ~init:([], jbuilds)
|
String_map.fold sub_dirs ~init:([], jbuilds)
|
||||||
~f:(fun ~key:_ ~data:dir (children, jbuilds) ->
|
~f:(fun ~key:_ ~data:dir (children, jbuilds) ->
|
||||||
let child, jbuilds = walk dir jbuilds visible_packages in
|
let child, jbuilds = walk dir jbuilds visible_packages closest_packages in
|
||||||
(child :: children, jbuilds))
|
(child :: children, jbuilds))
|
||||||
in
|
in
|
||||||
(Alias.Node (path, children), jbuilds)
|
(Alias.Node (path, children), jbuilds)
|
||||||
in
|
in
|
||||||
let root = File_tree.root ftree in
|
let root = File_tree.root ftree in
|
||||||
let tree, jbuilds = walk root [] String_map.empty in
|
let tree, jbuilds = walk root [] String_map.empty [] in
|
||||||
{ file_tree = ftree
|
{ file_tree = ftree
|
||||||
; tree
|
; tree
|
||||||
; jbuilds
|
; jbuilds
|
||||||
|
|
|
@ -729,15 +729,16 @@ end
|
||||||
module Stanzas = struct
|
module Stanzas = struct
|
||||||
type t = Stanza.t list
|
type t = Stanza.t list
|
||||||
|
|
||||||
let resolve_packages ts ~dir ~(visible_packages : Package.t String_map.t) =
|
let resolve_packages ts ~dir
|
||||||
|
~(visible_packages : Package.t String_map.t)
|
||||||
|
~(closest_packages : Package.t list) =
|
||||||
let error fmt =
|
let error fmt =
|
||||||
Loc.fail (Loc.in_file (Path.to_string (Path.relative dir "jbuild"))) fmt
|
Loc.fail (Loc.in_file (Path.to_string (Path.relative dir "jbuild"))) fmt
|
||||||
in
|
in
|
||||||
let known_packages () =
|
let package_listing packages =
|
||||||
let visible_packages = String_map.values visible_packages in
|
let longest_pkg = List.longest_map packages ~f:(fun p -> p.Package.name) in
|
||||||
let longest_pkg = List.longest_map visible_packages ~f:(fun p -> p.name) in
|
|
||||||
String.concat ~sep:"\n"
|
String.concat ~sep:"\n"
|
||||||
(List.map visible_packages ~f:(fun pkg ->
|
(List.map packages ~f:(fun pkg ->
|
||||||
sprintf "- %-*s (because of %s)" longest_pkg pkg.Package.name
|
sprintf "- %-*s (because of %s)" longest_pkg pkg.Package.name
|
||||||
(Path.to_string (Path.relative pkg.path (pkg.name ^ ".opam")))))
|
(Path.to_string (Path.relative pkg.path (pkg.name ^ ".opam")))))
|
||||||
in
|
in
|
||||||
|
@ -748,18 +749,19 @@ module Stanzas = struct
|
||||||
%s%s"
|
%s%s"
|
||||||
pkg
|
pkg
|
||||||
(Path.to_string dir)
|
(Path.to_string dir)
|
||||||
(known_packages ())
|
(package_listing (String_map.values visible_packages))
|
||||||
(hint pkg (String_map.keys visible_packages))
|
(hint pkg (String_map.keys visible_packages))
|
||||||
in
|
in
|
||||||
let default () =
|
let default () =
|
||||||
match String_map.keys visible_packages with
|
match closest_packages with
|
||||||
| [pkg] -> pkg
|
| [pkg] -> pkg
|
||||||
| [] -> error "no packages are defined here"
|
| [] -> error "no packages are defined here"
|
||||||
| _ :: _ :: _ ->
|
| _ :: _ :: _ ->
|
||||||
error "there is more than one package visible here:\n\
|
error "I can't determine automatically which package your (install ...) \
|
||||||
|
stanzas are for in this directory. I have the choice between these ones:\n\
|
||||||
%s\n\
|
%s\n\
|
||||||
You need to add a (package ...) field in your (install ...) stanzas"
|
You need to add a (package ...) field in your (install ...) stanzas"
|
||||||
(known_packages ())
|
(package_listing closest_packages)
|
||||||
in
|
in
|
||||||
List.map ts ~f:(fun (stanza : Stanza.t) ->
|
List.map ts ~f:(fun (stanza : Stanza.t) ->
|
||||||
match stanza with
|
match stanza with
|
||||||
|
@ -771,7 +773,7 @@ module Stanzas = struct
|
||||||
check pkg;
|
check pkg;
|
||||||
stanza
|
stanza
|
||||||
| Install ({ package = None; _ } as install) ->
|
| Install ({ package = None; _ } as install) ->
|
||||||
Install { install with package = Some (default ()) }
|
Install { install with package = Some (default ()).name }
|
||||||
| _ -> stanza)
|
| _ -> stanza)
|
||||||
|
|
||||||
let parse sexps ~dir ~visible_packages =
|
let parse sexps ~dir ~visible_packages =
|
||||||
|
|
Loading…
Reference in New Issue