Skip to content

Scoped packages (i.e. multiple libraries in a Cabal package) #2716

@ezyang

Description

@ezyang

Currently, Cabal's internal notion of a package only supports zero or one libraries. This sticks out as a bit of a sore thumb compared to other components in a Cabal file: Cabal currently supports compiling many components per Cabal file (libraries, test suites, executables, benchmarks), but only one of these components can be a library. I propose to remove this restriction, thus making libraries treated uniformly with other components in Cabal. We can then refactor PackageDescription to have a list of components.

Use-cases:

  1. For Backpack, we absolutely need the ability for a single Cabal file to result in the installation of multiple "packages" in the installed package database, because these packages are how you do modular development in Backpack. I took a detour to implement this feature, because it will serve as a good blueprint for how to make sure Cabal can handle building/registering multiple libraries.
  2. This change presents a really good opportunity to substantially simplify Cabal's handling of components. Currently, benchmarks, testsuites, executables and libraries are all separately special cased in Cabal, and anything that, e.g. mucks about the BuildInfos has to be implemented FOUR times for each of these cases. If we can push the component abstraction into PackageDescription, this will be a great simplification.

This would then directly allow us to support private packages (these would be an extra library that would be installed to the installed package database, making it visible to GHC).


For internal packages (which may be depended upon by public packages but cannot be referenced directly), the above proposal suffices. However, you might want to export more than one package from a Cabal file. The big use-case is when you have a package which has been split into a constellation of packages in order to make it easier for users to install useful subsets of functionality without pulling in the rest of the dependencies they don't want. However, maintaining N different Cabal files can be a bit of a pain for tightly coupled packages. With scoped packages, all of these packages could be placed in one Cabal file. (We have to make sure components get depsolved separately, but @edsko has put us most of the way there.)

The big problem with this is that it breaks the invariant that there is a one-to-one mapping between exported libraries and Cabal packages. If a Cabal file can define multiple libraries (which live in the same namespace a package names), then both foo.cabal and bar.cabal could define the helperpackage (collision). Furthermore, from cabal-install's perspective, if we need the helper package, it is not obvious where to look if there is no helper.cabal. There was considerable pushback here, so it may end up being the case that this is never going to be implemented.

However, if we did want to solve this, one way would be to introduce a hierarchy of scoping to package names. For the rest of this bug, I'll assume we delimit scopes with -. (If we don't care about compatibility with older versions of GHC, we could use something less ambiguous). The invariant is that a package named p can only define libraries p and p-anysubname. (We might even further imagine publishing a package named p-anysubname, thus allowing multiple libraries to be split up from a Cabal file). If cabal-install encounters a dependency on p-subpackage, it looks at p.cabal for a description of how to build it (or for p-subpackage.cabal). There is some ambiguity since package names today can use hyphens, but the potential massive conflicts are reduced, and cabal-install only has to query a few Cabal packages to see where a package is defined, as opposed to the ENTIRE package database.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions