Skip to content

Commit 7328e23

Browse files
committed
support multiple sub libraries
1 parent 41239bc commit 7328e23

6 files changed

Lines changed: 144 additions & 5 deletions

File tree

cabal2nix/src/Distribution/Nixpkgs/Haskell/Derivation.hs

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module Distribution.Nixpkgs.Haskell.Derivation
99
, cabalFlags, runHaddock, jailbreak, doCheck, doBenchmark, testFlags, testTargets, hyperlinkSource
1010
, enableLibraryProfiling, enableExecutableProfiling, phaseOverrides, editedCabalFile, metaSection
1111
, dependencies, setupDepends, benchmarkDepends, enableSeparateDataOutput, extraAttributes
12+
, subLibraryDepends, subLibraryDependencies
1213
)
1314
where
1415

@@ -50,6 +51,8 @@ data Derivation = MkDerivation
5051
, _executableDepends :: BuildInfo
5152
, _testDepends :: BuildInfo
5253
, _benchmarkDepends :: BuildInfo
54+
, _subLibraryDepends :: Map String BuildInfo
55+
, _subLibraryDependencies :: Map String [String]
5356
, _configureFlags :: Set String
5457
, _cabalFlags :: FlagAssignment
5558
, _runHaddock :: Bool
@@ -83,6 +86,8 @@ nullDerivation = MkDerivation
8386
, _executableDepends = error "undefined Derivation.executableDepends"
8487
, _testDepends = error "undefined Derivation.testDepends"
8588
, _benchmarkDepends = error "undefined Derivation.benchmarkDepends"
89+
, _subLibraryDepends = mempty
90+
, _subLibraryDependencies = mempty
8691
, _configureFlags = error "undefined Derivation.configureFlags"
8792
, _cabalFlags = error "undefined Derivation.cabalFlags"
8893
, _runHaddock = error "undefined Derivation.runHaddock"
@@ -102,15 +107,26 @@ nullDerivation = MkDerivation
102107

103108
makeLenses ''Derivation
104109

105-
makeLensesFor [("_setupDepends", "dependencies"), ("_libraryDepends", "dependencies"), ("_executableDepends", "dependencies"), ("_testDepends", "dependencies"), ("_benchmarkDepends", "dependencies")] ''Derivation
110+
-- | Traversal over all 'BuildInfo' values in a 'Derivation', including
111+
-- the setup, library, executable, test, benchmark, and sub-library depends.
112+
dependencies :: Traversal' Derivation BuildInfo
113+
dependencies f drv =
114+
(\s l e t b sl -> drv { _setupDepends = s, _libraryDepends = l, _executableDepends = e
115+
, _testDepends = t, _benchmarkDepends = b, _subLibraryDepends = sl })
116+
<$> f (_setupDepends drv)
117+
<*> f (_libraryDepends drv)
118+
<*> f (_executableDepends drv)
119+
<*> f (_testDepends drv)
120+
<*> f (_benchmarkDepends drv)
121+
<*> traverse f (_subLibraryDepends drv)
106122

107123
instance Package Derivation where
108124
packageId = view pkgid
109125

110126
instance NFData Derivation
111127

112128
instance Pretty Derivation where
113-
pPrint drv@MkDerivation {..} = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat
129+
pPrint drv@MkDerivation {_subLibraryDepends = subLibDeps, _subLibraryDependencies = subLibConsumerDeps, ..} = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat
114130
[ text "mkDerivation" <+> lbrace
115131
, nest 2 $ vcat
116132
[ attr "pname" $ doubleQuotes $ pPrint (packageName _pkgid)
@@ -124,10 +140,12 @@ instance Pretty Derivation where
124140
, boolattr "isExecutable" (not _isLibrary || _isExecutable) _isExecutable
125141
, boolattr "enableSeparateDataOutput" _enableSeparateDataOutput _enableSeparateDataOutput
126142
, onlyIf (_setupDepends /= mempty) $ pPrintBuildInfo "setup" _setupDepends
127-
, onlyIf (_libraryDepends /= mempty) $ pPrintBuildInfo "library" _libraryDepends
143+
, onlyIf (mergedLibraryDepends /= mempty) $ pPrintBuildInfo "library" mergedLibraryDepends
144+
, onlyIf (not (Map.null subLibDeps)) $ pPrintSubLibraryDepends subLibDeps
128145
, onlyIf (_executableDepends /= mempty) $ pPrintBuildInfo "executable" _executableDepends
129146
, onlyIf (_testDepends /= mempty) $ pPrintBuildInfo "test" _testDepends
130147
, onlyIf (_benchmarkDepends /= mempty) $ pPrintBuildInfo "benchmark" _benchmarkDepends
148+
, onlyIf (not (Map.null subLibConsumerDeps)) $ pPrintSubLibraryDependencies subLibConsumerDeps
131149
, boolattr "enableLibraryProfiling" _enableLibraryProfiling _enableLibraryProfiling
132150
, boolattr "enableExecutableProfiling" _enableExecutableProfiling _enableExecutableProfiling
133151
, boolattr "doHaddock" (not _runHaddock) _runHaddock
@@ -152,8 +170,39 @@ instance Pretty Derivation where
152170
Just derivKind' -> Set.fromList [derivKindFunction derivKind' | not isHackagePackage]
153171
]
154172

173+
-- For backwards compatibility, libraryHaskellDepends is emitted as the
174+
-- union of the main library deps and all sub-library deps. New consumers
175+
-- should prefer the separate subLibraryDepends attrset.
176+
mergedLibraryDepends = _libraryDepends `mappend` foldMap id (Map.elems subLibDeps)
177+
155178
renderedFlags = [ text "-f" <> (if enable then empty else char '-') <> text (unFlagName f) | (f, enable) <- unFlagAssignment _cabalFlags ]
156179
++ map text (toAscList _configureFlags)
157180
isHackagePackage = "mirror://hackage/" `isPrefixOf` derivUrl _src
158181

159182
postUnpack = string $ "sourceRoot+=/" ++ _subpath ++ "; echo source root reset to $sourceRoot"
183+
184+
pPrintSubLibraryDepends :: Map String BuildInfo -> Doc
185+
pPrintSubLibraryDepends libs = vcat
186+
[ text "subLibraryDepends" <+> equals <+> lbrace
187+
, nest 2 $ vcat entries
188+
, rbrace <> semi
189+
]
190+
where
191+
entries = [ vcat [ text (show name) <+> equals <+> lbrace
192+
, nest 2 $ pPrintBuildInfo "" bi
193+
, rbrace <> semi
194+
]
195+
| (name, bi) <- Map.toAscList libs
196+
, bi /= mempty
197+
]
198+
199+
pPrintSubLibraryDependencies :: Map String [String] -> Doc
200+
pPrintSubLibraryDependencies deps = vcat
201+
[ text "subLibraryDependencies" <+> equals <+> lbrace
202+
, nest 2 $ vcat entries
203+
, rbrace <> semi
204+
]
205+
where
206+
entries = [ listattrDoc (show pkgName) empty (map (doubleQuotes . text) subLibs)
207+
| (pkgName, subLibs) <- Map.toAscList deps
208+
]

cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal.hs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ module Distribution.Nixpkgs.Haskell.FromCabal
99

1010
import Control.Lens
1111
import Data.Maybe
12+
import qualified Data.Map as Map
1213
import Data.Set ( Set )
1314
import qualified Data.Set as Set
15+
import qualified Distribution.Compat.NonEmptySet as NES
1416
import Distribution.Compiler
1517
import Distribution.Nixpkgs.Haskell
1618
import qualified Distribution.Nixpkgs.Haskell as Nix
@@ -29,6 +31,7 @@ import Distribution.System
2931
import Distribution.Types.PackageVersionConstraint
3032
import Distribution.Text ( display )
3133
import Distribution.Types.ComponentRequestedSpec as Cabal
34+
import Distribution.Types.LibraryVisibility
3235
#if !MIN_VERSION_Cabal(3,8,1)
3336
import Distribution.Types.ExeDependency as Cabal
3437
import Distribution.Types.LegacyExeDependency as Cabal
@@ -124,10 +127,22 @@ fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags Package
124127
& isExecutable .~ not (null executables)
125128
& extraFunctionArgs .~ mempty
126129
& extraAttributes .~ mempty
127-
& libraryDepends .~ foldMap (convertBuildInfo . libBuildInfo) (maybeToList library ++ subLibraries)
130+
& libraryDepends .~ foldMap (convertBuildInfo . libBuildInfo) (maybeToList library)
131+
& subLibraryDepends .~ Map.fromList
132+
[ (unUnqualComponentName n, convertBuildInfo (libBuildInfo l))
133+
| l <- subLibraries
134+
, LSubLibName n <- [libName l]
135+
]
128136
& executableDepends .~ mconcat (map (convertBuildInfo . buildInfo) executables)
129137
& testDepends .~ mconcat (map (convertBuildInfo . testBuildInfo) testSuites)
130138
& benchmarkDepends .~ mconcat (map (convertBuildInfo . benchmarkBuildInfo) benchmarks)
139+
& subLibraryDependencies .~ collectSubLibDeps
140+
( concatMap (targetBuildDepends . libBuildInfo) (maybeToList library)
141+
++ concatMap (targetBuildDepends . libBuildInfo) subLibraries
142+
++ concatMap (targetBuildDepends . buildInfo) executables
143+
++ concatMap (targetBuildDepends . testBuildInfo) testSuites
144+
++ concatMap (targetBuildDepends . benchmarkBuildInfo) benchmarks
145+
)
131146
& Nix.setupDepends .~ maybe mempty convertSetupBuildInfo setupBuildInfo
132147
& configureFlags .~ mempty
133148
& cabalFlags .~ flags
@@ -201,13 +216,31 @@ fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags Package
201216
| otherwise = resolveInNixpkgs i
202217

203218
internalLibNames :: [PackageName]
204-
internalLibNames = [ unqualComponentNameToPackageName n | LSubLibName n <- libName <$> subLibraries ]
219+
internalLibNames = [ unqualComponentNameToPackageName n
220+
| l <- subLibraries
221+
, LSubLibName n <- [libName l]
222+
, libVisibility l /= LibraryVisibilityPublic
223+
]
205224

206225
doHaddockPhase :: Bool
207226
doHaddockPhase | not (null internalLibNames) = False
208227
| Just l <- library = not (null (exposedModules l))
209228
| otherwise = True
210229

230+
-- | Collect sub-library qualifiers from dependencies on external packages.
231+
-- For each external dependency that specifies sub-library names (not just
232+
-- LMainLibName), record which sub-libraries are being depended upon.
233+
collectSubLibDeps :: [Dependency] -> Map.Map String [String]
234+
collectSubLibDeps deps = Map.fromListWith (\a b -> Set.toAscList (Set.fromList (a ++ b)))
235+
[ (unPackageName x, subLibNames)
236+
| Dependency x _ libs <- deps
237+
, x `notElem` internalLibNames
238+
, x /= pkgName package -- exclude self-referential sub-library deps
239+
, let subLibNames = [ unUnqualComponentName n | LSubLibName n <- NES.toList libs ]
240+
, not (null subLibNames)
241+
]
242+
pkgName (PackageIdentifier n _) = n
243+
211244
convertBuildInfo :: Cabal.BuildInfo -> Nix.BuildInfo
212245
convertBuildInfo Cabal.BuildInfo {..} | not buildable = mempty
213246
convertBuildInfo Cabal.BuildInfo {..} = mempty

cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
module Distribution.Nixpkgs.Haskell.FromCabal.Normalize ( normalize ) where
44

55
import Control.Lens
6+
import qualified Data.Map as Map
67
import qualified Data.Set as Set
78
import Data.String
89
import Distribution.Nixpkgs.Haskell
@@ -17,6 +18,7 @@ normalize drv = drv
1718
& over executableDepends (normalizeBuildInfo (packageName drv))
1819
& over testDepends (normalizeBuildInfo (packageName drv))
1920
& over benchmarkDepends (normalizeBuildInfo (packageName drv))
21+
& over subLibraryDepends (Map.map (normalizeBuildInfo (packageName drv)))
2022
& over metaSection normalizeMeta
2123
& jailbreak %~ (&& (packageName drv /= "jailbreak-cabal"))
2224

cabal2nix/test/golden-test-cases/haddock-library.nix.golden

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ mkDerivation {
66
version = "1.4.5";
77
sha256 = "deadbeef";
88
libraryHaskellDepends = [ base bytestring deepseq transformers ];
9+
subLibraryDepends = {
10+
"attoparsec" = {
11+
HaskellDepends = [ base bytestring deepseq ];
12+
};
13+
};
914
testHaskellDepends = [
1015
base base-compat bytestring deepseq hspec QuickCheck transformers
1116
];
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
cabal-version: 3.0
2+
name: sub-libraries
3+
version: 0.1.0.0
4+
synopsis: Test case for sub-library support
5+
license: BSD-3-Clause
6+
build-type: Simple
7+
8+
library
9+
exposed-modules: MyLib
10+
build-depends: base >=4.14
11+
default-language: Haskell2010
12+
13+
library public-sub
14+
visibility: public
15+
exposed-modules: PublicSub
16+
build-depends: base, deepseq
17+
default-language: Haskell2010
18+
19+
library private-sub
20+
visibility: private
21+
exposed-modules: PrivateSub
22+
build-depends: base, containers
23+
default-language: Haskell2010
24+
25+
executable demo
26+
main-is: Main.hs
27+
build-depends: base, sub-libraries, sub-libraries:public-sub
28+
default-language: Haskell2010
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{ mkDerivation, base, containers, deepseq, lib }:
2+
mkDerivation {
3+
pname = "sub-libraries";
4+
version = "0.1.0.0";
5+
sha256 = "deadbeef";
6+
isLibrary = true;
7+
isExecutable = true;
8+
libraryHaskellDepends = [ base containers deepseq ];
9+
subLibraryDepends = {
10+
"private-sub" = {
11+
HaskellDepends = [ base containers ];
12+
};
13+
"public-sub" = {
14+
HaskellDepends = [ base deepseq ];
15+
};
16+
};
17+
executableHaskellDepends = [ base ];
18+
doHaddock = false;
19+
description = "Test case for sub-library support";
20+
license = lib.meta.getLicenseFromSpdxId "BSD-3-Clause";
21+
mainProgram = "demo";
22+
}

0 commit comments

Comments
 (0)