Skip to content

Commit

Permalink
Rework material on library components
Browse files Browse the repository at this point in the history
  • Loading branch information
mpilgrem committed Oct 25, 2023
1 parent bc7e8fc commit 675d474
Showing 1 changed file with 75 additions and 95 deletions.
170 changes: 75 additions & 95 deletions doc/cabal-package.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ Package Description
===================

The Cabal package is the unit of distribution. When installed, its
purpose is to make available:
purpose is to make available one or more:

- One or more Haskell programs (executables).
- Haskell programs (executables); and/or

- One or more libraries, exposing a number of Haskell modules.
- libraries, exposing a number of Haskell modules.

However having both a library and executables in a package does not work
very well; if the executables depend on the library, they must
Executables can declare a library in the same package as a dependency, and
Cabal will treat them as if they were in another package that depended on the
library. The alternative, which applied before Cabal 1.8.0.4, is that if the
executables depend on the library in the same package, they must
explicitly list all the modules they directly or indirectly import from
that library. Fortunately, starting with Cabal 1.8.0.4, executables can
also declare the package that they are in as a dependency, and Cabal
will treat them as if they were in another package that depended on the
library.
that library.

Internally, the package may consist of much more than a bunch of Haskell
modules: it may also have C source code and header files, source code
Expand Down Expand Up @@ -801,18 +800,42 @@ Library

Build information for libraries.

A package can have one default library, which is identified by omitting the
``name`` argument.
A package can include an optional 'main' library (which is identified by
omitting the ``name`` argument) and zero or more named libraries (referred
to as 'sublibraries') (which are identified by the setting the ``name``
field). A sublibrary cannot have the same name as its package.

Starting with Cabal 2.0, sub-library components can be defined by setting
the ``name`` field to a name different from the current package's name; see
section on :ref:`Internal Libraries <sublibs>` for more information. By
default, these sub-libraries are private and internal. Since Cabal 3.0,
these sub-libraries can also be exposed and used by other packages. See the
:pkg-field:`library:visibility` field and :ref:`Multiple Public Libraries
<publicsublibs>` for more information.
A sublibrary has a 'visibility' which can be 'public' or 'private' (the
default) - see the :pkg-field:`library:visibility` field. The 'main'
unnamed library is always public. A private sublibrary may be referred to as
an 'internal' library.

The library section should contain the following fields:
Before Cabal 3.0, all sublibraries were internal libraries. Before Cabal 2.0
a package could not include sublibraries.

A package being able to include more than one public library separates the
unit of distribution (the package) from the unit of buildable code (the
library). This is useful for Haskell projects with many libraries that are
distributed together as it avoids duplication and potential inconsistencies.

See :ref:`Sublibraries - Examples <sublibs>` for examples.

A library section should contain the following fields:

.. pkg-field:: visibility: visibility specifiers

:since: 3.0

:default:
``private`` for sublibraries. Cannot be set for the 'main' unnamed
library, which is always public.

Can be set to ``public`` or ``private``. If set to ``public``, depending on
this library from another package is allowed. If set to ``private``,
depending on this library is allowed only from the same package.

See the :pkg-field:`build-depends` field for the syntax to specify a
sublibrary in a ``build-depends:``.

.. pkg-field:: exposed-modules: identifier list

Expand Down Expand Up @@ -847,23 +870,6 @@ The library section should contain the following fields:
that use a flat module namespace or where it is known that the
exposed modules would clash with other common modules.

.. pkg-field:: visibility: visibility specifiers

:since: 3.0

:default:
``private`` for internal libraries. Cannot be set for main
(unnamed) library, which is always public.

Can be ``public`` or ``private``.
Makes it possible to have multiple public libraries in a single package.
If set to ``public``, depending on this library from another package is
allowed. If set to ``private``, depending on this library is allowed only
from the same package.

See section on :ref:`Internal Libraries <sublibs>` for examples and more
information.

.. pkg-field:: reexported-modules: exportlist
:since: 1.22

Expand Down Expand Up @@ -903,22 +909,21 @@ section on `build information`_).

.. _sublibs:

**Internal Libraries**
**Sublibraries - Examples**

Cabal 2.0 and later support "internal libraries", which are extra named
libraries (as opposed to the usual unnamed library section). For
example, suppose that your test suite needs access to some internal
modules in your library, which you do not otherwise want to export. You
could put these modules in an internal library, which the main library
and the test suite :pkg-field:`build-depends` upon. Then your Cabal file might
look something like this:
An example of the use of an internal library (a 'private' sublibrary) is a
test suite that needs access to some internal modules in your 'main' library,
which you do not otherwise want to export. You could put those modules in an
internal library, which the 'main' unnamed library and the test
suite :pkg-field:`build-depends` upon. Your Cabal file might then look something
like this:

::

cabal-version: 2.0
cabal-version: 3.4
name: foo
version: 0.1.0.0
license: BSD3
license: BSD-3-Clause
license-file: LICENSE
build-type: Simple

Expand All @@ -931,34 +936,27 @@ look something like this:

library
exposed-modules: Foo.Public
build-depends: foo-internal, base >= 4.3 && < 5
build-depends: foo:foo-internal, base >= 4.3 && < 5
default-language: Haskell2010

test-suite test-foo
type: exitcode-stdio-1.0
main-is: test-foo.hs
-- NOTE: no constraints on 'foo-internal' as same-package
-- dependencies implicitly refer to the same package instance
build-depends: foo-internal, base
build-depends: foo:foo-internal, base
default-language: Haskell2010

Internal libraries are also useful for packages that define multiple
executables, but do not define a publicly accessible library. Internal
libraries are only visible internally in the package (so they can only
be added to the :pkg-field:`build-depends` of same-package libraries,
executables, test suites, etc.) Internal libraries locally shadow any
packages which have the same name; consequently, don't name an internal
library with the same name as an external dependency if you need to be
able to refer to the external dependency in a
:pkg-field:`build-depends` declaration.

Shadowing can be used to vendor an external dependency into a package
Another example of the use of internal libraries is a package that includes one
or more executables but does not include a public library.

Internal libraries can be used to vendor an external dependency into a package
and thus emulate *private dependencies*. Below is an example based on
a real-world use case:

::

cabal-version: 3.0
cabal-version: 3.4
name: haddock-library
version: 1.6.0
license: BSD-3-Clause
Expand All @@ -973,7 +971,7 @@ a real-world use case:
hs-source-dirs: src

-- internal sub-lib
build-depends: attoparsec
build-depends: haddock-library:attoparsec

exposed-modules:
Documentation.Haddock
Expand Down Expand Up @@ -1001,25 +999,6 @@ a real-world use case:

default-language: Haskell2010

.. note::
For packages using ``cabal-version: 3.4`` or higher, the syntax to
specify an internal library in a ``build-depends:`` section is
``package-name:internal-library-name``.

.. _publicsublibs:

**Multiple Public Libraries**

Cabal 3.0 and later support exposing multiple libraries from a single package
through the field :pkg-field:`library:visibility`.
Having multiple public libraries is useful for separating the unit of
distribution (package) from the unit of buildable code (library).
For more information about the rationale and some examples, see
`this blog post <https://fgaz.me/posts/2019-11-14-cabal-multiple-libraries/>`__.

..
TODO inline the blog post
Executables
^^^^^^^^^^^

Expand Down Expand Up @@ -1454,24 +1433,25 @@ system-dependent values for these fields.

.. pkg-field:: build-depends: library list

Declares the *library* dependencies required to build the current
package component; see :pkg-field:`build-tool-depends` for
declaring build-time *tool* dependencies. External library
dependencies should be annotated with a version constraint.
Declares the *library* dependencies (from the same package or other
packages) required to build the current package component. See
:pkg-field:`build-tool-depends` for declaring build-time *tool*
dependencies. Dependencies on libraries from another package should be
annotated with a version constraint.

**Library Names**

External libraries are identified by the package's name they're
provided by, optionally followed by a colon and the library name
(available from ``cabal-version: 3.0``).
If the library name is absent, the main (unnamed) library will be used.
To refer to the main (unnamed) library explicitly, use the name of the
package (``foo:foo``).
Multiple libraries from the same package can be specified with the shorthand
syntax ``pkg:{lib1,lib2}```.

See section on :ref:`Multiple Public Libraries <publicsublibs>` for examples and more
information.
A library is identified by the package's name it is provided by, optionally
followed by a colon and the library's name (available from
``cabal-version: 3.0``). If the library name is absent, the package's 'main'
unnamed library will be used. To refer to a package's 'main' unnamed library
explicitly, use the name of the package as the library name (``foo:foo``).
More than one library from the same package can be specified with the
shorthand syntax ``pkg:{lib1,lib2}``.

See the section on :pkg-section:`library` for more information about how
a package can specify library components for use by other components of the
same package or by other packages.

**Version Constraints**

Expand Down

0 comments on commit 675d474

Please sign in to comment.