Skip to content

Commit

Permalink
Add dune-project generation to dune init (ocaml#4881)
Browse files Browse the repository at this point in the history
* Document cram stanza in dune-project docs
* Add encode function for Dune_project.t
* Add support fore subst_config field
* Add dune-project creation to dune init proj
* Document purpose of Dyn module

Thanks to @jeremiedimino
see ocaml#4881 (comment)

* Add Univ_map.to_dyns

Thanks to @jeremiedimino
ocaml#4881 (comment)

* Document dune init in quickstart part of manual

Thanks to @christinerose for improvements and edits in docs 

Signed-off-by: Shon Feder <[email protected]>
Signed-off-by: Jeremie Dimino <[email protected]>

Co-authored-by: Jeremie Dimino <[email protected]>
  • Loading branch information
2 people authored and rgrinberg committed Oct 3, 2021
1 parent a2c3609 commit 05109f3
Show file tree
Hide file tree
Showing 23 changed files with 684 additions and 62 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Unreleased
----------

- Generate a `dune-project` when initializing projects with `dune init proj ...`
(#4881, closes #4367, @shonfeder)

- Allow spaces in the directory argument of the `subdir` stanza (#4943, fixes
#4907, @rgrinberg)

Expand Down
46 changes: 41 additions & 5 deletions bin/dune_init.ml
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ module Init_context = struct
~infer_from_opam_files:true ~dir_status:Normal
with
| Some p -> p
| None -> Dune_project.anonymous ~dir:Path.Source.root
| None -> Dune_project.anonymous ~dir:Path.Source.root ()
in
let dir =
match path with
Expand Down Expand Up @@ -230,8 +230,6 @@ module Component = struct
| Exec
| Lib

(* TODO(shonfeder) Add custom templates *)

let of_string = function
| "executable" -> Some Exec
| "library" -> Some Lib
Expand Down Expand Up @@ -308,6 +306,7 @@ module Component = struct
@ optional_field ~f:pps options.pps)
end

(* Make CST representation of a stanza for the given `kind` *)
let make kind common_options fields =
(* Form the AST *)
List ((atom kind :: fields) @ Field.common common_options)
Expand Down Expand Up @@ -347,12 +346,35 @@ module Component = struct
make "library" common (public_name @ inline_tests)

let test common (() : Options.Test.t) = make "test" common []

(* A list of CSTs for dune-project file content *)
let dune_project ?(opam_file_gen = true) dir (common : Options.Common.t) =
let package = Package.default (Atom.to_string common.name) dir in
let packages =
Package.Name.Map.singleton (Package.name package) package
in
let info = Package.Info.example in
Dune_project.anonymous ~dir ~packages ~info ()
|> Dune_project.set_dialects Dialect.DB.empty
|> Dune_project.set_generate_opam_files opam_file_gen
|> Dune_project.encode
|> List.map ~f:(fun exp ->
exp |> Dune_lang.Ast.add_loc ~loc:Loc.none |> Cst.concrete)
|> fun cst ->
List.append cst
[ Cst.Comment
( Loc.none
, [ " See the complete stanza docs at \
https://dune.readthedocs.io/en/stable/dune-files.html#dune-project"
] )
]
end

(* TODO Support for merging in changes to an existing stanza *)
let add_stanza_to_dune_file ~(project : Dune_project.t) ~dir stanza =
File.load_dune_file ~path:dir |> File.Stanza.add project stanza

(* Functions to make the various components, represented as lists of files *)
module Make = struct
let bin ({ context; common; options } : Options.Executable.t Options.t) =
let dir = context.dir in
Expand Down Expand Up @@ -392,6 +414,20 @@ module Component = struct
let files = [ test_dune; test_ml ] in
[ { dir; files } ]

let dune_project_file dir
({ context; common; options } : Options.Project.t Options.t) =
let opam_file_gen =
match options.pkg with
| Opam -> true
| Esy -> false
in
let content =
Stanza_cst.dune_project ~opam_file_gen
Path.(as_in_source_tree_exn context.dir)
common
in
File.Dune { path = dir; content; name = "dune-project" }

let proj_exec dir
({ context; common; options } : Options.Project.t Options.t) =
let lib_target =
Expand Down Expand Up @@ -454,7 +490,7 @@ module Component = struct
(Loc.none, Dune_lang.Atom.to_string common.name)
in
let proj_target =
let files =
let package_files =
match (pkg : Options.Project.Pkg.t) with
| Opam ->
let opam_file = Package.file ~dir ~name in
Expand All @@ -464,7 +500,7 @@ module Component = struct
]
| Esy -> [ File.make_text dir "package.json" "" ]
in
{ dir; files }
{ dir; files = dune_project_file dir opts :: package_files }
in
let component_targets =
match (template : Options.Project.Template.t) with
Expand Down
9 changes: 7 additions & 2 deletions bin/dune_init.mli
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ module Kind : sig

val to_string : t -> string

(* val kind_strings : string list *)
val commands : (string * t) list
end

Expand All @@ -32,6 +31,7 @@ end
module Component : sig
(** Options determining the details of a generated component *)
module Options : sig
(** The common options shared by all components *)
module Common : sig
type t =
{ name : Dune_lang.Atom.t
Expand All @@ -46,23 +46,28 @@ module Component : sig

val public_name_to_string : public_name -> string

(** Options for executable components *)
module Executable : sig
type t = { public : public_name option }
end

(** Options for library components *)
module Library : sig
type t =
{ public : public_name option
; inline_tests : bool
}
end

(** Options for test components *)
module Test : sig
(** NOTE: no options supported yet *)
type t = unit
end

(** Options for project components (which consist of several sub-components) *)
module Project : sig
(** Determines whether this is a library project or an executable project *)
module Template : sig
type t =
| Exec
Expand Down Expand Up @@ -96,7 +101,7 @@ module Component : sig
}
end

(** The supported types of components *)
(** All the the supported types of components *)
type 'options t =
| Executable : Options.Executable.t Options.t -> Options.Executable.t t
| Library : Options.Library.t Options.t -> Options.Library.t t
Expand Down
18 changes: 18 additions & 0 deletions doc/dune-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Stanza reference
****************

.. _dune-project:

dune-project
============

Expand Down Expand Up @@ -55,6 +57,18 @@ Sets the version of the project:
(version <version>)
cram
----

Enable or disable cram-style tests for the project. See :ref:`cram-tests` for
details.

.. code:: scheme
(cram <status>)
Where status is either ``enabled`` or ``disabled``.

.. _implicit_transitive_deps:

implicit_transitive_deps
Expand Down Expand Up @@ -385,6 +399,8 @@ Note that ``dune`` continues to be accepted even after enabling this option, but
if a file named ``dune-file`` is found in a directory, it will take precedence
over ``dune``.

.. _dune-files:

dune
====

Expand Down Expand Up @@ -676,6 +692,8 @@ library whose name is not prefixed by the package name. Such a library cannot be
defined in Dune, but other build systems allow it and this feature is meant to
help migration from those systems.

.. _executable:

executable
----------

Expand Down
146 changes: 142 additions & 4 deletions doc/quick-start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,148 @@ This document gives simple usage examples of Dune. You can also look at
`examples <https://github.com/ocaml/dune/tree/master/example>`__ for complete
examples of projects using Dune.

Initializing Projects
=====================

The following subsections illustrate basic usage of the ``dune init proj``
subcommand. For more documentation, see :ref:`initializing_components` and the
inline help available from ``dune init --help``.

.. _initializing-an-executable:

Initializing an Executable
--------------------------

To initialize a project that will build an executable program, run the following
(replacing ``project_name`` with the name of your project):

.. code:: shell
dune init proj project_name
This creates a project directory that includes the following contents:

.. code::
project_name/
├── dune-project
├── test
│ ├── dune
│ └── project_name.ml
├── lib
│   └── dune
├── bin
│   ├── dune
│   └── main.ml
└── project_name.opam
Now, enter your project's directory:

.. code:: shell
cd project_name
Then, you can build your project with:

.. code:: shell
dune build
You can run your tests with:

.. code:: shell
dune test
You can run your program with:

.. code:: shell
dune exec project_name
The following itemization of the generated content isn't necessary to review at
this point. But whenever you are ready, it will provide jump-off points from
which you can dive deeper into Dune's capabilities:

* The ``dune-project`` file specifies metadata about the project, including its
name, packaging data (including dependencies), and information about the
authors and maintainers. You should open this in your editor to fill in the
placeholder values. See :ref:`dune-project` for details.
* The ``test`` directory contains a skeleton for your project's tests. Add to
the tests by editing ``test/project_name.ml``. See :ref:`writing-tests` for
details on testing.
* The ``lib`` directory will hold the library you write to provide the core
functionality of your executable. Add modules to your library by creating new
``.ml`` files in this directory. See :ref:`library` for details on specifying
libraries manually.
* The ``bin`` directory holds a skeleton for the executable program. Within the
modules in this directory, you can access the modules in your ``lib`` under
the namespace ``Project_name.Mod``, where ``Project_name`` is replaced with
the name of your project and ``Mod`` corresponds to the name of the file in
the ``lib`` directory. You can run the executable with ``dune exec
project_name``. See :ref:`hello-world-program` for an example of specifying
an executable manually and :ref:`executable` for details.
* The ``project_name.opam`` file will be freshly generated from the
``dune-project`` file whenever you build your project. You shouldn't need to
worry about this, but you can see :ref:`opam-generation` for details.
* The ``dune`` files in each directory specify the component to be built with
the files in that directory. For details on dune files, see :ref:`dune-files`.

Initializing a Library
--------------------------

To initialize a project for an OCaml library, run the following (replacing
``project_name`` with the name of your project):

.. code:: shell
dune init proj --kind=lib project_name
This creates a project directory that includes the following contents:

.. code::
project_name/
├── dune-project
├── lib
│   └── dune
├── test
│ ├── dune
│ └── project_name.ml
└── project_name.opam
Now, enter your project's directory:

.. code:: shell
cd project_name
Then, you can build your project with:

.. code:: shell
dune build
You can run your tests with:

.. code:: shell
dune test
All of the subcomponents generated are the same as those described in
:ref:`initializing-an-executable`, with the following exceptions:

* There is no ``bin`` directory generated.
* The ``dune`` file in the ``lib`` directory specifies that the library should
be *public*. See :ref:`library` for details.

.. _hello-world-program:

Building a Hello World Program
==============================

Since OCaml is a compiler language, first create a ``dune`` file in Nano, Vim,
Since OCaml is a compiled language, first create a ``dune`` file in Nano, Vim,
or your preferred text editor. Declare the ``hello_world`` executable by including following stanza
(shown below). Name this initial file ``dune`` and save it in a directory of your choice.

Expand Down Expand Up @@ -113,7 +251,7 @@ And build it with:
The executable will be built as ``_build/default/hello_world.exe``

Defining a Library Using Lwt and ``ocaml-re``
=========================================
=============================================

Write this ``dune`` file:

Expand Down Expand Up @@ -199,7 +337,7 @@ declare the dependency to this file via:
(preprocessor_deps config.h)
Using the ``.cppo.ml`` Style Like the ``ocamlbuild`` Plugin
---------------------------------------------------
-----------------------------------------------------------

Write this in your ``dune`` file:

Expand Down Expand Up @@ -230,7 +368,7 @@ this ``dune`` file:
(c_library_flags (-lblah)))
Defining a Library with C Stubs using ``pkg-config``
================================================
====================================================

Same context as before, but using ``pkg-config`` to query the
compilation and link flags. Write this ``dune`` file:
Expand Down
Loading

0 comments on commit 05109f3

Please sign in to comment.