Skip to content

Commit

Permalink
Merge pull request #7551 from Mikolaj/m-renaud-mrenaud-docs-getting-s…
Browse files Browse the repository at this point in the history
…tarted

Restructure Getting Started docs to get to a running program faster.

This is rebased (with resolved conflicts) version of #6157 by @m-renaud .
  • Loading branch information
Mikolaj authored Sep 6, 2021
2 parents 888801b + 0f041b6 commit 55c426f
Showing 1 changed file with 126 additions and 72 deletions.
198 changes: 126 additions & 72 deletions doc/developing-packages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,57 @@ Quickstart
.. TIP::
If this is your first time using `cabal` you should check out the `Getting Started guide <getting-started.html>`__.

Let's assume we have created a project directory and already have a
Haskell module or two.
Starting from scratch, we're going to walk you through creating a simple
Haskell application.

Every project needs a name, we'll call this example "proglet".
**TL;DR;** ``mkdir proglet && cd proglet && cabal init --simple --exe && cabal run proglet``


Introduction
------------

Every application needs a name, we'll call ours "proglet" and start by
creating an empty directory.

.. highlight:: console

::

$ mkdir proglet
$ cd proglet/
$ ls
Proglet.hs

It is assumed that (apart from external dependencies) all the files that
make up a package live under a common project root directory. This
simple example has all the project files in one directory, but most
packages will use one or more subdirectories.

To turn this into a Cabal package we need two extra files in the
project's root directory:
Using ``cabal init``
--------------------

- ``proglet.cabal``: containing package metadata and build information.
The ``cabal init`` command creates the necessary files for a Cabal package,
it has both an ``--interactive`` (default) and ``--non-interactive``
mode. The interactive mode will walk you through many of the package
options and metadata, the non-interactive mode will simply pick reasonable
defaults which is sufficient if you're just trying something out.

- ``Setup.hs``: usually containing a few standardized lines of code,
but can be customized if necessary.
.. highlight:: console

We can create both files manually or we can use ``cabal init`` to create
them for us.
::

Using "cabal init"
------------------
$ cabal init --non-interactive
# You can also use -n which is the short version of --non-interactive

The ``cabal init --interactive`` command is interactive. If we answer
"no" to using the "sensible defaults" it asks a number of questions.
If you want, you can also try out the interactive mode, for now chose
"Executable" when asked what type of package you want to build.

.. highlight:: console

::

$ cabal init --interactive
Should I generate a simple project with sensible defaults? [default: y] n
$ cabal init
...
What does the package build:
1) Executable
2) Library
3) Library and Executable
4) Test suite
Your choice?
...

One of the important questions is whether the package contains a library
and/or an executable. Libraries are collections of Haskell modules that
Expand All @@ -66,25 +71,55 @@ and executable; or: test suite) cabal asks us a number of questions starting wit
which version of the cabal specification to use, our package's name
(for example, "proglet"), and our package's version.

It also asks questions about various other bits of package metadata. For
a package that you never intend to distribute to others, these fields
can be left blank.
::

Generating CHANGELOG.md...
Generating Main.hs...
Generating proglet.cabal...

Use the ``ls`` command to see the creaed files:

::

$ ls
CHANGELOG.md Main.hs proglet.cabal

Finally, ``cabal init --interactive`` creates the initial ``proglet.cabal``
and ``Setup.hs`` files, and depending on your choice of license, a
``LICENSE`` file as well.

Running the program
-------------------

Now that we have our Haskell code and the extra files that Cabal needs we
can build and run our application.

::

Generating LICENSE...
Generating Setup.hs...
Generating proglet.cabal...
$ cabal build
Resolving dependencies...
...
Linking /path/to/proglet ...

$ cabal run proglet
...
Hello, Haskell!

Since we have an executable we can use ``cabal run proglet`` which will build
our executable (and re-build it if we've made any changes) and then run the
binary. The ``cabal run`` command works for any ``component-name`` (tests for
example), not just the main executable.


About the Cabal package structure
---------------------------------

It is assumed that all the files that make up a package live under a common
root directory (apart from external dependencies). This simple example has
all the package files in one directory, but most packages use one or more
subdirectories.

Cabal needs one extra file in the package's root directory:

You may want to edit the .cabal file and add a Description field.
- ``proglet.cabal``: contains package metadata and build information.

At this stage the ``proglet.cabal`` is not quite complete and before you
are able to build the package you will need to edit the file and add
some build information about the library or executable.

Editing the .cabal file
-----------------------
Expand All @@ -93,33 +128,42 @@ Editing the .cabal file

Load up the ``.cabal`` file in a text editor. The first part of the
``.cabal`` file has the package metadata and towards the end of the file
you will find the :pkg-section:`executable` or :pkg-section:`library` section.
you will find the :pkg-section:`executable` or :pkg-section:`library`
section.

You will see that the fields that have yet to be filled in are commented
out. Cabal files use "``--``" Haskell-style comment syntax. (Note that
comments are only allowed on lines on their own. Trailing comments on
other lines are not allowed because they could be confused with program
options.)
out. Cabal files use "``--``" Haskell-style comment syntax.

.. NOTE::
Comments are only allowed on lines on their own. Trailing comments on
other lines are not allowed because they could be confused with program
options.

If you selected earlier to create a library package then your ``.cabal``
file will have a section that looks like this:

::

library
exposed-modules: Proglet
executable proglet
main-is: Main.hs
-- other-modules:
-- build-depends:
-- other-extensions:
build-depends: base >=4.11 && <4.12
-- hs-source-dirs:
default-language: Haskell2010


Alternatively, if you selected an executable then there will be a
section like:
If you selected earlier to create a library package then your ``.cabal``
file will have a section that looks like this:

::

executable proglet
-- main-is:
library
exposed-modules: MyLib
-- other-modules:
-- build-depends:
build-depends: base >=4.11 && <4.12
-- hs-source-dirs:
default-language: Haskell2010


The build information fields listed (but commented out) are just the few
most important and common fields. There are many others that are covered
Expand All @@ -135,22 +179,24 @@ not specified in the library section. Executables often follow the name
of the package too, but this is not required and the name is given
explicitly.


Modules included in the package
-------------------------------

For an executable, ``cabal init`` creates the ``Main.hs`` file which
contains your program's ``Main`` module. It will also fill in the
:pkg-field:`executable:main-is` field with the file name of your program's
``Main`` module, including the ``.hs`` (or ``.lhs``) extension. Other
modules included in the executable should be listed in the
:pkg-field:`other-modules` field.

For a library, ``cabal init`` looks in the project directory for files
that look like Haskell modules and adds all the modules to the
:pkg-field:`library:exposed-modules` field. For modules that do not form part
of your package's public interface, you can move those modules to the
:pkg-field:`other-modules` field. Either way, all modules in the library need
to be listed.

For an executable, ``cabal init`` does not try to guess which file
contains your program's ``Main`` module. You will need to fill in the
:pkg-field:`executable:main-is` field with the file name of your program's
``Main`` module (including ``.hs`` or ``.lhs`` extension). Other modules
included in the executable should be listed in the :pkg-field:`other-modules`
field.

Modules imported from other packages
------------------------------------
Expand All @@ -173,23 +219,23 @@ package, so we must list it:
library
exposed-modules: Proglet
other-modules:
build-depends: containers, base == 4.*
build-depends: containers, base >=4.11 && <4.12

In addition, almost every package also depends on the ``base`` library
package because it exports the standard ``Prelude`` module plus other
basic modules like ``Data.List``.

You will notice that we have listed ``base == 4.*``. This gives a
You will notice that we have listed ``base >=4.11 && <4.12``. This gives a
constraint on the version of the base package that our package will work
with. The most common kinds of constraints are:

- ``pkgname >= n``
- ``pkgname ^>= n`` (since Cabal 2.0)
- ``pkgname >= n && < m``
- ``pkgname == n.*`` (since Cabal 1.6)
- ``pkgname >=n``
- ``pkgname ^>=n`` (since Cabal 2.0)
- ``pkgname >=n && <m``
- ``pkgname ==n.*`` (since Cabal 1.6)

The last is just shorthand, for example ``base == 4.*`` means exactly
the same thing as ``base >= 4 && < 5``. Please refer to the documentation
The last is just shorthand, for example ``base ==4.*`` means exactly
the same thing as ``base >=4 && <5``. Please refer to the documentation
on the :pkg-field:`build-depends` field for more information.

Also, you can factor out shared ``build-depends`` (and other fields such
Expand All @@ -211,7 +257,8 @@ your libraries and executable sections. For example:
Proglet

Note that the ``import`` **must** be the first thing in the stanza. For more
information see the :ref:`common-stanzas` section.
information see the `Common stanzas`_ section.


Building the package
--------------------
Expand All @@ -223,14 +270,20 @@ which also downloads and builds all required dependencies:
$ cabal build
If the package contains an executable, it can be installed:
If the package contains an executable, you can run it with:

.. code-block:: console
$ cabal run
and the executable can also be installed for convenince:

.. code-block:: console
$ cabal install
The executable program lands in a special directory for binaries
that may or may not already be on your system's ``PATH``.
When installed, the executable program lands in a special directory
for binaries that may or may not already be on your system's ``PATH``.
If it is, the executable can be run by typing its filename on commandline.
For installing libraries see the :ref:`adding-libraries` section.

Expand All @@ -246,6 +299,7 @@ packages and details needed for distributing packages to other people.
The previous chapter covers building and installing packages -- your own
packages or ones developed by other people.


Package concepts
================

Expand Down Expand Up @@ -302,7 +356,7 @@ of digits such as "1.0.1" or "2.0". There are a range of common
conventions for "versioning" packages, that is giving some meaning to
the version number in terms of changes in the package, such as
e.g. `SemVer <http://semver.org>`__; however, for packages intended to be
distributed via Hackage Haskell's `Package Versioning Policy <https://pvp.haskell.org/>`_ applies
distributed via Hackage Haskell's `Package Versioning Policy`_ applies
(see also the `PVP/SemVer FAQ section <https://pvp.haskell.org/faq/#semver>`__).

The combination of package name and version is called the *package ID*
Expand Down Expand Up @@ -367,9 +421,9 @@ Operating system packages
Unit of distribution
--------------------

The Cabal package is the unit of distribution. What this means is that
each Cabal package can be distributed on its own in source or binary
form. Of course there may be dependencies between packages, but there is
The Cabal package is the unit of distribution. This means that
each Cabal package can be distributed on its own, in source or binary
form. There may be dependencies between packages, but there is
usually a degree of flexibility in which versions of packages can work
together so distributing them independently makes sense.

Expand Down

0 comments on commit 55c426f

Please sign in to comment.