Skip to content

Commit 0f4ed00

Browse files
committed
Implement "convenience libraries", fixes haskell#269.
Convenience libraries are package-private libraries that can be used as part of executables, libraries, etc without being exposed to the external world. Private libraries are signified using the library foo stanza. Within a Cabal package, the name convenience library shadows the conventional meaning of package name in build-depends, so that references to "foo" do not indicate foo in Hackage, but the convenience library defined in the same package. (So, don't shadow Hackage packages!) This commit implements convenience libraries such that they ARE installed the package database (this prevents us from having to special case dynamically linked executables); in GHC 7.10 and later they are installed under the same package name as the package that contained them, but have a distinct "component ID" (one pay off of making the distinction between component IDs and installed package IDs.) There is a "default" library which is identified by the fact that its library name coincides with the package name. There are some new convenience functions to permit referencing this. There are a few latent bugs in this commit which are fixed in later commits in this patchset. (Those bugfixes required a bit of refactoring, so it's clearer if they're not with this patch.) Signed-off-by: Edward Z. Yang <[email protected]>
1 parent bd6baef commit 0f4ed00

File tree

40 files changed

+1869
-354
lines changed

40 files changed

+1869
-354
lines changed

Cabal/Cabal.cabal

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ extra-source-files:
9797
tests/PackageTests/HaddockNewline/A.hs
9898
tests/PackageTests/HaddockNewline/HaddockNewline.cabal
9999
tests/PackageTests/HaddockNewline/Setup.hs
100+
tests/PackageTests/MultipleLibraries/p.cabal
101+
tests/PackageTests/MultipleLibraries/p/P.hs
102+
tests/PackageTests/MultipleLibraries/p/Foo.hs
103+
tests/PackageTests/MultipleLibraries/p/p.cabal
104+
tests/PackageTests/MultipleLibraries/p/p/P.hs
105+
tests/PackageTests/MultipleLibraries/p/q/Q.hs
106+
tests/PackageTests/MultipleLibraries/q/Q.hs
107+
tests/PackageTests/MultipleLibraries/q/q.cabal
100108
tests/PackageTests/OrderFlags/Foo.hs
101109
tests/PackageTests/OrderFlags/my.cabal
102110
tests/PackageTests/PathsModule/Executable/Main.hs

Cabal/Distribution/PackageDescription.hs

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ data PackageDescription
189189
buildType :: Maybe BuildType,
190190
setupBuildInfo :: Maybe SetupBuildInfo,
191191
-- components
192-
library :: Maybe Library,
192+
libraries :: [Library],
193193
executables :: [Executable],
194194
testSuites :: [TestSuite],
195195
benchmarks :: [Benchmark],
@@ -256,7 +256,7 @@ emptyPackageDescription
256256
category = "",
257257
customFieldsPD = [],
258258
setupBuildInfo = Nothing,
259-
library = Nothing,
259+
libraries = [],
260260
executables = [],
261261
testSuites = [],
262262
benchmarks = [],
@@ -390,6 +390,7 @@ instance Text ModuleRenaming where
390390
-- The Library type
391391

392392
data Library = Library {
393+
libName :: String,
393394
exposedModules :: [ModuleName],
394395
reexportedModules :: [ModuleReexport],
395396
requiredSignatures:: [ModuleName], -- ^ What sigs need implementations?
@@ -403,6 +404,7 @@ instance Binary Library
403404

404405
instance Monoid Library where
405406
mempty = Library {
407+
libName = mempty,
406408
exposedModules = mempty,
407409
reexportedModules = mempty,
408410
requiredSignatures = mempty,
@@ -414,6 +416,7 @@ instance Monoid Library where
414416

415417
instance Semigroup Library where
416418
a <> b = Library {
419+
libName = combine' libName,
417420
exposedModules = combine exposedModules,
418421
reexportedModules = combine reexportedModules,
419422
requiredSignatures = combine requiredSignatures,
@@ -422,20 +425,26 @@ instance Semigroup Library where
422425
libBuildInfo = combine libBuildInfo
423426
}
424427
where combine field = field a `mappend` field b
428+
combine' field = case (field a, field b) of
429+
("","") -> ""
430+
("", x) -> x
431+
(x, "") -> x
432+
(x, y) -> error $ "Ambiguous values for library field: '"
433+
++ x ++ "' and '" ++ y ++ "'"
425434

426435
emptyLibrary :: Library
427436
emptyLibrary = mempty
428437

429438
-- |does this package have any libraries?
430439
hasLibs :: PackageDescription -> Bool
431-
hasLibs p = maybe False (buildable . libBuildInfo) (library p)
440+
hasLibs p = any (buildable . libBuildInfo) (libraries p)
432441

433442
-- |'Maybe' version of 'hasLibs'
434-
maybeHasLibs :: PackageDescription -> Maybe Library
443+
maybeHasLibs :: PackageDescription -> [Library]
435444
maybeHasLibs p =
436-
library p >>= \lib -> if buildable (libBuildInfo lib)
437-
then Just lib
438-
else Nothing
445+
libraries p >>= \lib -> if buildable (libBuildInfo lib)
446+
then return lib
447+
else []
439448

440449
-- |If the package description has a library section, call the given
441450
-- function with the library build info as argument.
@@ -919,7 +928,7 @@ emptyBuildInfo = mempty
919928
-- all buildable executables, test suites and benchmarks. Useful for gathering
920929
-- dependencies.
921930
allBuildInfo :: PackageDescription -> [BuildInfo]
922-
allBuildInfo pkg_descr = [ bi | Just lib <- [library pkg_descr]
931+
allBuildInfo pkg_descr = [ bi | lib <- libraries pkg_descr
923932
, let bi = libBuildInfo lib
924933
, buildable bi ]
925934
++ [ bi | exe <- executables pkg_descr
@@ -954,10 +963,10 @@ usedExtensions :: BuildInfo -> [Extension]
954963
usedExtensions bi = oldExtensions bi
955964
++ defaultExtensions bi
956965

957-
type HookedBuildInfo = (Maybe BuildInfo, [(String, BuildInfo)])
966+
type HookedBuildInfo = ([(String, BuildInfo)], [(String, BuildInfo)])
958967

959968
emptyHookedBuildInfo :: HookedBuildInfo
960-
emptyHookedBuildInfo = (Nothing, [])
969+
emptyHookedBuildInfo = ([], [])
961970

962971
-- |Select options for a particular Haskell compiler.
963972
hcOptions :: CompilerFlavor -> BuildInfo -> [String]
@@ -1113,28 +1122,30 @@ lowercase = map Char.toLower
11131122
-- ------------------------------------------------------------
11141123

11151124
updatePackageDescription :: HookedBuildInfo -> PackageDescription -> PackageDescription
1116-
updatePackageDescription (mb_lib_bi, exe_bi) p
1117-
= p{ executables = updateExecutables exe_bi (executables p)
1118-
, library = updateLibrary mb_lib_bi (library p)
1125+
updatePackageDescription (lib_bi, exe_bi) p
1126+
= p{ executables = updateMany exeName updateExecutable exe_bi (executables p)
1127+
, libraries = updateMany libName updateLibrary lib_bi (libraries p)
11191128
}
11201129
where
1121-
updateLibrary :: Maybe BuildInfo -> Maybe Library -> Maybe Library
1122-
updateLibrary (Just bi) (Just lib) = Just (lib{libBuildInfo = bi `mappend` libBuildInfo lib})
1123-
updateLibrary Nothing mb_lib = mb_lib
1124-
updateLibrary (Just _) Nothing = Nothing
1125-
1126-
updateExecutables :: [(String, BuildInfo)] -- ^[(exeName, new buildinfo)]
1127-
-> [Executable] -- ^list of executables to update
1128-
-> [Executable] -- ^list with exeNames updated
1129-
updateExecutables exe_bi' executables' = foldr updateExecutable executables' exe_bi'
1130-
1131-
updateExecutable :: (String, BuildInfo) -- ^(exeName, new buildinfo)
1132-
-> [Executable] -- ^list of executables to update
1133-
-> [Executable] -- ^list with exeName updated
1134-
updateExecutable _ [] = []
1135-
updateExecutable exe_bi'@(name,bi) (exe:exes)
1136-
| exeName exe == name = exe{buildInfo = bi `mappend` buildInfo exe} : exes
1137-
| otherwise = exe : updateExecutable exe_bi' exes
1130+
updateMany :: (a -> String) -- ^ @exeName@ or @libName@
1131+
-> (BuildInfo -> a -> a) -- ^ @updateExecutable@ or @updateLibrary@
1132+
-> [(String, BuildInfo)] -- ^[(name, new buildinfo)]
1133+
-> [a] -- ^list of components to update
1134+
-> [a] -- ^list with updated components
1135+
updateMany name update hooked_bi' cs' = foldr (updateOne name update) cs' hooked_bi'
1136+
1137+
updateOne :: (a -> String) -- ^ @exeName@ or @libName@
1138+
-> (BuildInfo -> a -> a) -- ^ @updateExecutable@ or @updateLibrary@
1139+
-> (String, BuildInfo) -- ^(name, new buildinfo)
1140+
-> [a] -- ^list of compnoents to update
1141+
-> [a] -- ^list with name component updated
1142+
updateOne _ _ _ [] = []
1143+
updateOne name_sel update hooked_bi'@(name,bi) (c:cs)
1144+
| name_sel c == name = update bi c : cs
1145+
| otherwise = c : updateOne name_sel update hooked_bi' cs
1146+
1147+
updateExecutable bi exe = exe{buildInfo = bi `mappend` buildInfo exe}
1148+
updateLibrary bi lib = lib{libBuildInfo = bi `mappend` libBuildInfo lib}
11381149

11391150
-- ---------------------------------------------------------------------------
11401151
-- The GenericPackageDescription type
@@ -1143,7 +1154,7 @@ data GenericPackageDescription =
11431154
GenericPackageDescription {
11441155
packageDescription :: PackageDescription,
11451156
genPackageFlags :: [Flag],
1146-
condLibrary :: Maybe (CondTree ConfVar [Dependency] Library),
1157+
condLibraries :: [(String, CondTree ConfVar [Dependency] Library)],
11471158
condExecutables :: [(String, CondTree ConfVar [Dependency] Executable)],
11481159
condTestSuites :: [(String, CondTree ConfVar [Dependency] TestSuite)],
11491160
condBenchmarks :: [(String, CondTree ConfVar [Dependency] Benchmark)]

Cabal/Distribution/PackageDescription/Check.hs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import Distribution.Text
4646
import Language.Haskell.Extension
4747

4848
import Data.Maybe
49-
( isNothing, isJust, catMaybes, mapMaybe, maybeToList, fromMaybe )
49+
( isNothing, isJust, catMaybes, mapMaybe, fromMaybe )
5050
import Data.List (sort, group, isPrefixOf, nub, find)
5151
import Control.Monad
5252
( filterM, liftM )
@@ -173,7 +173,7 @@ checkSanity pkg =
173173
, check (all ($ pkg) [ null . executables
174174
, null . testSuites
175175
, null . benchmarks
176-
, isNothing . library ]) $
176+
, null . libraries ]) $
177177
PackageBuildImpossible
178178
"No executables, libraries, tests, or benchmarks found. Nothing to do."
179179

@@ -185,7 +185,7 @@ checkSanity pkg =
185185
--TODO: check for name clashes case insensitively: windows file systems cannot
186186
--cope.
187187

188-
++ maybe [] (checkLibrary pkg) (library pkg)
188+
++ concatMap (checkLibrary pkg) (libraries pkg)
189189
++ concatMap (checkExecutable pkg) (executables pkg)
190190
++ concatMap (checkTestSuite pkg) (testSuites pkg)
191191
++ concatMap (checkBenchmark pkg) (benchmarks pkg)
@@ -673,7 +673,7 @@ checkGhcOptions pkg =
673673

674674
where
675675
all_ghc_options = concatMap get_ghc_options (allBuildInfo pkg)
676-
lib_ghc_options = maybe [] (get_ghc_options . libBuildInfo) (library pkg)
676+
lib_ghc_options = concatMap (get_ghc_options . libBuildInfo) (libraries pkg)
677677
get_ghc_options bi = hcOptions GHC bi ++ hcProfOptions GHC bi
678678

679679
checkFlags :: [String] -> PackageCheck -> Maybe PackageCheck
@@ -895,9 +895,18 @@ checkCabalVersion pkg =
895895
++ "different modules then list the other ones in the "
896896
++ "'other-languages' field."
897897

898+
, checkVersion [1,23]
899+
(case libraries pkg of
900+
[lib] -> libName lib /= unPackageName (packageName pkg)
901+
[] -> False
902+
_ -> True) $
903+
PackageDistInexcusable $
904+
"To use multiple 'library' sections or a named library section "
905+
++ "the package needs to specify at least 'cabal-version >= 1.23'."
906+
898907
-- check use of reexported-modules sections
899908
, checkVersion [1,21]
900-
(maybe False (not.null.reexportedModules) (library pkg)) $
909+
(any (not.null.reexportedModules) (libraries pkg)) $
901910
PackageDistInexcusable $
902911
"To use the 'reexported-module' field the package needs to specify "
903912
++ "at least 'cabal-version: >= 1.21'."
@@ -1296,7 +1305,7 @@ checkConditionals pkg =
12961305
unknownOSs = [ os | OS (OtherOS os) <- conditions ]
12971306
unknownArches = [ arch | Arch (OtherArch arch) <- conditions ]
12981307
unknownImpls = [ impl | Impl (OtherCompiler impl) _ <- conditions ]
1299-
conditions = maybe [] fvs (condLibrary pkg)
1308+
conditions = concatMap (fvs . snd) (condLibraries pkg)
13001309
++ concatMap (fvs . snd) (condExecutables pkg)
13011310
fvs (CondNode _ _ ifs) = concatMap compfv ifs -- free variables
13021311
compfv (c, ct, mct) = condfv c ++ fvs ct ++ maybe [] fvs mct
@@ -1399,8 +1408,8 @@ checkDevelopmentOnlyFlags pkg =
13991408

14001409
allConditionalBuildInfo :: [([Condition ConfVar], BuildInfo)]
14011410
allConditionalBuildInfo =
1402-
concatMap (collectCondTreePaths libBuildInfo)
1403-
(maybeToList (condLibrary pkg))
1411+
concatMap (collectCondTreePaths libBuildInfo . snd)
1412+
(condLibraries pkg)
14041413

14051414
++ concatMap (collectCondTreePaths buildInfo . snd)
14061415
(condExecutables pkg)

0 commit comments

Comments
 (0)