Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions cabal2nix/src/Distribution/Nixpkgs/Haskell/Derivation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Distribution.Nixpkgs.Haskell.Derivation
, cabalFlags, runHaddock, jailbreak, doCheck, doBenchmark, testFlags, testTargets, hyperlinkSource
, enableLibraryProfiling, enableExecutableProfiling, phaseOverrides, editedCabalFile, metaSection
, dependencies, setupDepends, benchmarkDepends, enableSeparateDataOutput, extraAttributes
, subLibraryDepends, subLibraryDependencies
)
where

Expand Down Expand Up @@ -50,6 +51,8 @@ data Derivation = MkDerivation
, _executableDepends :: BuildInfo
, _testDepends :: BuildInfo
, _benchmarkDepends :: BuildInfo
, _subLibraryDepends :: Map String BuildInfo
, _subLibraryDependencies :: Map String [String]
, _configureFlags :: Set String
, _cabalFlags :: FlagAssignment
, _runHaddock :: Bool
Expand Down Expand Up @@ -83,6 +86,8 @@ nullDerivation = MkDerivation
, _executableDepends = error "undefined Derivation.executableDepends"
, _testDepends = error "undefined Derivation.testDepends"
, _benchmarkDepends = error "undefined Derivation.benchmarkDepends"
, _subLibraryDepends = mempty
, _subLibraryDependencies = mempty
, _configureFlags = error "undefined Derivation.configureFlags"
, _cabalFlags = error "undefined Derivation.cabalFlags"
, _runHaddock = error "undefined Derivation.runHaddock"
Expand All @@ -102,15 +107,26 @@ nullDerivation = MkDerivation

makeLenses ''Derivation

makeLensesFor [("_setupDepends", "dependencies"), ("_libraryDepends", "dependencies"), ("_executableDepends", "dependencies"), ("_testDepends", "dependencies"), ("_benchmarkDepends", "dependencies")] ''Derivation
-- | Traversal over all 'BuildInfo' values in a 'Derivation', including
-- the setup, library, executable, test, benchmark, and sub-library depends.
dependencies :: Traversal' Derivation BuildInfo
dependencies f drv =
(\s l e t b sl -> drv { _setupDepends = s, _libraryDepends = l, _executableDepends = e
, _testDepends = t, _benchmarkDepends = b, _subLibraryDepends = sl })
<$> f (_setupDepends drv)
<*> f (_libraryDepends drv)
<*> f (_executableDepends drv)
<*> f (_testDepends drv)
<*> f (_benchmarkDepends drv)
<*> traverse f (_subLibraryDepends drv)

instance Package Derivation where
packageId = view pkgid

instance NFData Derivation

instance Pretty Derivation where
pPrint drv@MkDerivation {..} = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat
pPrint drv@MkDerivation {_subLibraryDepends = subLibDeps, _subLibraryDependencies = subLibConsumerDeps, ..} = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat
[ text "mkDerivation" <+> lbrace
, nest 2 $ vcat
[ attr "pname" $ doubleQuotes $ pPrint (packageName _pkgid)
Expand All @@ -124,10 +140,12 @@ instance Pretty Derivation where
, boolattr "isExecutable" (not _isLibrary || _isExecutable) _isExecutable
, boolattr "enableSeparateDataOutput" _enableSeparateDataOutput _enableSeparateDataOutput
, onlyIf (_setupDepends /= mempty) $ pPrintBuildInfo "setup" _setupDepends
, onlyIf (_libraryDepends /= mempty) $ pPrintBuildInfo "library" _libraryDepends
, onlyIf (mergedLibraryDepends /= mempty) $ pPrintBuildInfo "library" mergedLibraryDepends
, onlyIf (not (Map.null subLibDeps)) $ pPrintSubLibraryDepends subLibDeps
, onlyIf (_executableDepends /= mempty) $ pPrintBuildInfo "executable" _executableDepends
, onlyIf (_testDepends /= mempty) $ pPrintBuildInfo "test" _testDepends
, onlyIf (_benchmarkDepends /= mempty) $ pPrintBuildInfo "benchmark" _benchmarkDepends
, onlyIf (not (Map.null subLibConsumerDeps)) $ pPrintSubLibraryDependencies subLibConsumerDeps
, boolattr "enableLibraryProfiling" _enableLibraryProfiling _enableLibraryProfiling
, boolattr "enableExecutableProfiling" _enableExecutableProfiling _enableExecutableProfiling
, boolattr "doHaddock" (not _runHaddock) _runHaddock
Expand All @@ -152,8 +170,39 @@ instance Pretty Derivation where
Just derivKind' -> Set.fromList [derivKindFunction derivKind' | not isHackagePackage]
]

-- For backwards compatibility, libraryHaskellDepends is emitted as the
-- union of the main library deps and all sub-library deps. New consumers
-- should prefer the separate subLibraryDepends attrset.
mergedLibraryDepends = _libraryDepends `mappend` foldMap id (Map.elems subLibDeps)

renderedFlags = [ text "-f" <> (if enable then empty else char '-') <> text (unFlagName f) | (f, enable) <- unFlagAssignment _cabalFlags ]
++ map text (toAscList _configureFlags)
isHackagePackage = "mirror://hackage/" `isPrefixOf` derivUrl _src

postUnpack = string $ "sourceRoot+=/" ++ _subpath ++ "; echo source root reset to $sourceRoot"

pPrintSubLibraryDepends :: Map String BuildInfo -> Doc
pPrintSubLibraryDepends libs = vcat
[ text "subLibraryDepends" <+> equals <+> lbrace
, nest 2 $ vcat entries
, rbrace <> semi
]
where
entries = [ vcat [ text (show name) <+> equals <+> lbrace
, nest 2 $ pPrintBuildInfo "" bi
, rbrace <> semi
]
| (name, bi) <- Map.toAscList libs
, bi /= mempty
]

pPrintSubLibraryDependencies :: Map String [String] -> Doc
pPrintSubLibraryDependencies deps = vcat
[ text "subLibraryDependencies" <+> equals <+> lbrace
, nest 2 $ vcat entries
, rbrace <> semi
]
where
entries = [ listattrDoc (show pkgName) empty (map (doubleQuotes . text) subLibs)
| (pkgName, subLibs) <- Map.toAscList deps
]
37 changes: 35 additions & 2 deletions cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ module Distribution.Nixpkgs.Haskell.FromCabal

import Control.Lens
import Data.Maybe
import qualified Data.Map as Map
import Data.Set ( Set )
import qualified Data.Set as Set
import qualified Distribution.Compat.NonEmptySet as NES
import Distribution.Compiler
import Distribution.Nixpkgs.Haskell
import qualified Distribution.Nixpkgs.Haskell as Nix
Expand All @@ -29,6 +31,7 @@ import Distribution.System
import Distribution.Types.PackageVersionConstraint
import Distribution.Text ( display )
import Distribution.Types.ComponentRequestedSpec as Cabal
import Distribution.Types.LibraryVisibility
#if !MIN_VERSION_Cabal(3,8,1)
import Distribution.Types.ExeDependency as Cabal
import Distribution.Types.LegacyExeDependency as Cabal
Expand Down Expand Up @@ -124,10 +127,22 @@ fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags Package
& isExecutable .~ not (null executables)
& extraFunctionArgs .~ mempty
& extraAttributes .~ mempty
& libraryDepends .~ foldMap (convertBuildInfo . libBuildInfo) (maybeToList library ++ subLibraries)
& libraryDepends .~ foldMap (convertBuildInfo . libBuildInfo) (maybeToList library)
& subLibraryDepends .~ Map.fromList
[ (unUnqualComponentName n, convertBuildInfo (libBuildInfo l))
| l <- subLibraries
, LSubLibName n <- [libName l]
]
& executableDepends .~ mconcat (map (convertBuildInfo . buildInfo) executables)
& testDepends .~ mconcat (map (convertBuildInfo . testBuildInfo) testSuites)
& benchmarkDepends .~ mconcat (map (convertBuildInfo . benchmarkBuildInfo) benchmarks)
& subLibraryDependencies .~ collectSubLibDeps
( concatMap (targetBuildDepends . libBuildInfo) (maybeToList library)
++ concatMap (targetBuildDepends . libBuildInfo) subLibraries
++ concatMap (targetBuildDepends . buildInfo) executables
++ concatMap (targetBuildDepends . testBuildInfo) testSuites
++ concatMap (targetBuildDepends . benchmarkBuildInfo) benchmarks
)
& Nix.setupDepends .~ maybe mempty convertSetupBuildInfo setupBuildInfo
& configureFlags .~ mempty
& cabalFlags .~ flags
Expand Down Expand Up @@ -201,13 +216,31 @@ fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags Package
| otherwise = resolveInNixpkgs i

internalLibNames :: [PackageName]
internalLibNames = [ unqualComponentNameToPackageName n | LSubLibName n <- libName <$> subLibraries ]
internalLibNames = [ unqualComponentNameToPackageName n
| l <- subLibraries
, LSubLibName n <- [libName l]
, libVisibility l /= LibraryVisibilityPublic
]

doHaddockPhase :: Bool
doHaddockPhase | not (null internalLibNames) = False
| Just l <- library = not (null (exposedModules l))
| otherwise = True

-- | Collect sub-library qualifiers from dependencies on external packages.
-- For each external dependency that specifies sub-library names (not just
-- LMainLibName), record which sub-libraries are being depended upon.
collectSubLibDeps :: [Dependency] -> Map.Map String [String]
collectSubLibDeps deps = Map.fromListWith (\a b -> Set.toAscList (Set.fromList (a ++ b)))
[ (unPackageName x, subLibNames)
| Dependency x _ libs <- deps
, x `notElem` internalLibNames
, x /= pkgName package -- exclude self-referential sub-library deps
, let subLibNames = [ unUnqualComponentName n | LSubLibName n <- NES.toList libs ]
, not (null subLibNames)
]
pkgName (PackageIdentifier n _) = n

convertBuildInfo :: Cabal.BuildInfo -> Nix.BuildInfo
convertBuildInfo Cabal.BuildInfo {..} | not buildable = mempty
convertBuildInfo Cabal.BuildInfo {..} = mempty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module Distribution.Nixpkgs.Haskell.FromCabal.Normalize ( normalize ) where

import Control.Lens
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.String
import Distribution.Nixpkgs.Haskell
Expand All @@ -17,6 +18,7 @@ normalize drv = drv
& over executableDepends (normalizeBuildInfo (packageName drv))
& over testDepends (normalizeBuildInfo (packageName drv))
& over benchmarkDepends (normalizeBuildInfo (packageName drv))
& over subLibraryDepends (Map.map (normalizeBuildInfo (packageName drv)))
& over metaSection normalizeMeta
& jailbreak %~ (&& (packageName drv /= "jailbreak-cabal"))

Expand Down
5 changes: 5 additions & 0 deletions cabal2nix/test/golden-test-cases/haddock-library.nix.golden
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ mkDerivation {
version = "1.4.5";
sha256 = "deadbeef";
libraryHaskellDepends = [ base bytestring deepseq transformers ];
subLibraryDepends = {
"attoparsec" = {
HaskellDepends = [ base bytestring deepseq ];
};
};
testHaskellDepends = [
base base-compat bytestring deepseq hspec QuickCheck transformers
];
Expand Down
28 changes: 28 additions & 0 deletions cabal2nix/test/golden-test-cases/sub-libraries.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
cabal-version: 3.0
name: sub-libraries
version: 0.1.0.0
synopsis: Test case for sub-library support
license: BSD-3-Clause
build-type: Simple

library
exposed-modules: MyLib
build-depends: base >=4.14
default-language: Haskell2010

library public-sub
visibility: public
exposed-modules: PublicSub
build-depends: base, deepseq
default-language: Haskell2010

library private-sub
visibility: private
exposed-modules: PrivateSub
build-depends: base, containers
default-language: Haskell2010

executable demo
main-is: Main.hs
build-depends: base, sub-libraries, sub-libraries:public-sub
default-language: Haskell2010
22 changes: 22 additions & 0 deletions cabal2nix/test/golden-test-cases/sub-libraries.nix.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{ mkDerivation, base, containers, deepseq, lib }:
mkDerivation {
pname = "sub-libraries";
version = "0.1.0.0";
sha256 = "deadbeef";
isLibrary = true;
isExecutable = true;
libraryHaskellDepends = [ base containers deepseq ];
subLibraryDepends = {
"private-sub" = {
HaskellDepends = [ base containers ];
};
"public-sub" = {
HaskellDepends = [ base deepseq ];
};
};
executableHaskellDepends = [ base ];
doHaddock = false;
description = "Test case for sub-library support";
license = lib.meta.getLicenseFromSpdxId "BSD-3-Clause";
mainProgram = "demo";
}
Loading