NixOS / cabal2nix

Generate Nix build instructions from a Cabal file
https://haskell4nix.readthedocs.io
Other
355 stars 154 forks source link

Handle internal libraries correctly #539

Open sternenseemann opened 2 years ago

sternenseemann commented 2 years ago

Since 2.0, Cabal has a notion of internal libraries (which is any named library in the cabal file):

Cabal 2.0 and later support “internal libraries”, which are extra named libraries (as opposed to the usual unnamed library section). […]

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 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 build-depends declaration.

My intuition would be that we'd need to detect these and disable the internal library (i.e. setting isLibrary = false; in simple cases). An obvious example of this is jacinda which has an executable and an internal library we should not install.

It gets trickier if you have an internal library (e.g. for the test suite and executable) and a public library. We probably need to teach the generic-builder.nix in nixpkgs to distinguish between public and internal library instead of relying on isLibrary (which should only describe whether we have a public library or not).

What is a bit unclear to me is whether a public library can depend on an internal one and if we would need to install the internal one in such cases.

See also https://github.com/NixOS/nixpkgs/issues/155924#issuecomment-1017859265.

m4dc4p commented 2 years ago

Not as obvious, but this bug leads to huge closure sizes (such as including all of GHC and its docs). Especially painful when using nix to build docker images.

maralorn commented 2 years ago

@m4dc4p You mean this affects packages which have only executables and internal libraries?

Note that you can currently work around this by applying the function haskell.lib.justStaticExecutables to the resulting packages.

sternenseemann commented 2 years ago

I'm still inclined to think that this is a Cabal bug as well, Setup.hs copy should not install things that are not supposed to be installed.

m4dc4p commented 2 years ago

@maralorn That doesn't work when the executable also includes an internal library. (We were already using the justStaticExecutables function). Moving the executables to their own package does work, however, if the shared library uses the Cabal data-files feature, you still end up with a closure that depends on GHC. See https://github.com/NixOS/nixpkgs/issues/155924#issuecomment-1030697619.

TeofilC commented 11 months ago

I took a brief look at this and testing it locally it seems that both Setup copy <exe component> and Setup install install the internal library even if we just pass the name of an exe component that depends on it. So I think https://github.com/NixOS/cabal2nix/issues/539#issuecomment-1030603825 is right that this is a Cabal bug. Edit: I took another look at this and managed to get it working, ie, only the correct components were installed by ./Setup.

In this comment: https://github.com/NixOS/cabal2nix/issues/603#issuecomment-1602412717 @sternenseemann, you suggested that there should be a way forward that makes better use of component info. What did you have in mind?