From a076f5c8493a4888708b1b7d18dc1d6323f170a9 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Wed, 25 Oct 2023 20:00:21 +0100 Subject: [PATCH] Rework material on library components --- doc/cabal-package.rst | 174 +++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 96 deletions(-) diff --git a/doc/cabal-package.rst b/doc/cabal-package.rst index 75ec9ff40ed..ae014f48f3e 100644 --- a/doc/cabal-package.rst +++ b/doc/cabal-package.rst @@ -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 @@ -801,18 +800,45 @@ Library Build information for libraries. - A package can have one default library, which is identified by omitting the - ``name`` argument. + A package can include zero or more library components, being an optional + 'main' unnamed library (which is identified by having no ``name`` argument) + and/or zero or more 'subsidiary' or 'ancilliary' named libraries (referred + to as 'sublibraries', which are identified by their ``name`` argument). 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:`Sublibraries ` 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 - ` 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, because other packages cannot depend upon it. -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 ` 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``, other + components of the package that provide the library and components of other + packages are able to depend on the library. If set to ``private``, only + other components of the package that provide it are able to depend upon it; + components of other packages are not able to depend upon it. + + See the :pkg-field:`build-depends` field for the syntax to specify a 'main' + unnamed library or a sublibrary in a ``build-depends:``. .. pkg-field:: exposed-modules: identifier list @@ -847,23 +873,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 sublibraries. 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:`Sublibraries ` for examples and more - information. - .. pkg-field:: reexported-modules: exportlist :since: 1.22 @@ -903,22 +912,21 @@ section on `build information`_). .. _sublibs: -**Sublibraries** +**Sublibraries - Examples** -Cabal 2.0 and later support "sublibraries", 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 a sublibrary, 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 (that is, a 'private' sublibrary) +is a test suite that needs access to some internal modules in your 'main' +unnamed library, which you do not otherwise want to expose. 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 @@ -931,7 +939,7 @@ 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 @@ -939,26 +947,18 @@ look something like this: 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 -Sublibraries 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.) Sublibraries 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. +Another example of the use of internal libraries is a package that includes one +or more executables but does not include a public library. -Shadowing 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: +Internal libraries can be used to incorporate an external dependency into a +package, effectively simulating *private dependencies*. Below is an example: :: - cabal-version: 3.0 + cabal-version: 3.4 name: haddock-library version: 1.6.0 license: BSD-3-Clause @@ -973,7 +973,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 @@ -1001,25 +1001,6 @@ a real-world use case: default-language: Haskell2010 -.. note:: - For packages using ``cabal-version: 3.4`` or higher, the syntax to - specify a sublibrary 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 `__. - -.. - TODO inline the blog post - Executables ^^^^^^^^^^^ @@ -1454,24 +1435,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 ` for examples and more - information. + A library is identified by the name of the package that provides it, + optionally followed by a colon and the library's name (available from + ``cabal-version: 3.0``). If a library name is omitted, the package's 'main' + unnamed library will be used. To refer expressly to a package's 'main' + unnamed library, use the name of the package as the library name (for + example, ``my-package:my-package``). 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**