Skip to content

Commit 554468f

Browse files
ezyangEricson2314
authored andcommitted
Distinguish between internal and external libraries in build-depends
Fixes haskell#4155. We create a new `LibDependency` just used for parsing `build-depends` entries for now, but I hope it has a bright future in the brave new per-component world. Already in 'Cabal', this type will be used instead of 'Dependency' in most cases, implemented in the following commits of this PR. Used in: - Condition Trees - Querying the PackageIndex ----- Not sure about which type should have the (not)ThisPackageVersion function Also need to update some comments. Everything builds, however.
1 parent 063dab7 commit 554468f

File tree

48 files changed

+1012
-481
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1012
-481
lines changed

Cabal/Cabal.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,10 @@ library
307307
Distribution.Types.Dependency
308308
Distribution.Types.ExeDependency
309309
Distribution.Types.LegacyExeDependency
310+
Distribution.Types.LibDependency
310311
Distribution.Types.PkgconfigDependency
311312
Distribution.Types.DependencyMap
313+
Distribution.Types.LibDependencyMap
312314
Distribution.Types.ComponentId
313315
Distribution.Types.MungedPackageId
314316
Distribution.Types.PackageId

Cabal/Distribution/Backpack/ComponentsGraph.hs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import Distribution.PackageDescription as PD hiding (Flag)
1616
import Distribution.Simple.BuildToolDepends
1717
import Distribution.Simple.LocalBuildInfo
1818
import Distribution.Types.ComponentRequestedSpec
19-
import Distribution.Types.UnqualComponentName
19+
import Distribution.Types.LibDependency
2020
import Distribution.Compat.Graph (Graph, Node(..))
2121
import qualified Distribution.Compat.Graph as Graph
22+
import Distribution.Types.Mixin
2223

2324
import Distribution.Text
2425
( Text(disp) )
@@ -64,18 +65,16 @@ mkComponentsGraph enabled pkg_descr =
6465
-- The dependencies for the given component
6566
componentDeps component =
6667
(CExeName <$> getAllInternalToolDependencies pkg_descr bi)
67-
68-
++ [ if pkgname == packageName pkg_descr
69-
then CLibName
70-
else CSubLibName toolname
71-
| Dependency pkgname _ <- targetBuildDepends bi
72-
, let toolname = packageNameToUnqualComponentName pkgname
73-
, toolname `elem` internalPkgDeps ]
68+
++ mixin_deps
69+
++ [ maybe CLibName CSubLibName (libDepLibraryName ld)
70+
| ld <- targetBuildDepends bi
71+
, libDepPackageName ld == packageName pkg_descr ]
7472
where
7573
bi = componentBuildInfo component
76-
internalPkgDeps = map (conv . libName) (allLibraries pkg_descr)
77-
conv Nothing = packageNameToUnqualComponentName $ packageName pkg_descr
78-
conv (Just s) = s
74+
mixin_deps =
75+
[ maybe CLibName CSubLibName (mixinLibraryName mix)
76+
| mix <- mixins bi
77+
, mixinPackageName mix == packageName pkg_descr ]
7978

8079
-- | Given the package description and a 'PackageDescription' (used
8180
-- to determine if a package name is internal or not), sort the

Cabal/Distribution/Backpack/ConfiguredComponent.hs

Lines changed: 52 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@ import Distribution.Compat.Prelude hiding ((<>))
2222
import Distribution.Backpack.Id
2323

2424
import Distribution.Types.AnnotatedId
25-
import Distribution.Types.Dependency
25+
import Distribution.Types.LibDependency
2626
import Distribution.Types.ExeDependency
2727
import Distribution.Types.IncludeRenaming
2828
import Distribution.Types.ComponentId
2929
import Distribution.Types.PackageId
3030
import Distribution.Types.PackageName
3131
import Distribution.Types.Mixin
3232
import Distribution.Types.ComponentName
33-
import Distribution.Types.UnqualComponentName
3433
import Distribution.Types.ComponentInclude
3534
import Distribution.Package
3635
import Distribution.PackageDescription as PD hiding (Flag)
@@ -43,7 +42,6 @@ import Distribution.Utils.MapAccum
4342
import Distribution.Utils.Generic
4443

4544
import Control.Monad
46-
import qualified Data.Set as Set
4745
import qualified Data.Map as Map
4846
import Distribution.Text
4947
import Text.PrettyPrint
@@ -96,59 +94,72 @@ dispConfiguredComponent cc =
9694
| incl <- cc_includes cc
9795
])
9896

97+
-- | This is a mapping that keeps track of package-internal libraries
98+
-- and executables. Although a component of the key is a general
99+
-- 'ComponentName', actually only 'CLib', 'CSubLib' and 'CExe' will ever
100+
-- be here.
99101
type ConfiguredComponentMap =
100102
Map PackageName (Map ComponentName (AnnotatedId ComponentId))
101103

104+
-- Executable map must be different because an executable can
105+
-- have the same name as a library. Ew.
106+
107+
-- | Given some ambient environment of package names that
108+
-- are "in scope", looks at the 'BuildInfo' to decide
109+
-- what the packages actually resolve to, and then builds
110+
-- a 'ConfiguredComponent'.
102111
toConfiguredComponent
103112
:: PackageDescription
104113
-> ComponentId
105114
-> ConfiguredComponentMap
106115
-> Component
107116
-> LogProgress ConfiguredComponent
108117
toConfiguredComponent pkg_descr this_cid dep_map component = do
109-
lib_deps <-
110-
if newPackageDepsBehaviour pkg_descr
111-
then forM (targetBuildDepends bi) $ \(Dependency name _) -> do
112-
let (pn, cn) = fixFakePkgName pkg_descr name
113-
value <- case Map.lookup cn =<< Map.lookup pn dep_map of
114-
Nothing ->
115-
dieProgress $
116-
text "Dependency on unbuildable" <+>
117-
text (showComponentName cn) <+>
118-
text "from" <+> disp pn
119-
Just v -> return v
120-
return value
121-
else return old_style_lib_deps
118+
let reg_lib_deps =
119+
if newPackageDepsBehaviour pkg_descr
120+
then
121+
[ (pn, cn)
122+
| LibDependency pn mb_ln _ <- targetBuildDepends bi
123+
, let cn = libraryComponentName mb_ln ]
124+
else
125+
-- dep_map contains a mix of internal and external deps.
126+
-- We want all the public libraries (dep_cn == CLibName)
127+
-- of all external deps (dep /= pn). Note that this
128+
-- excludes the public library of the current package:
129+
-- this is not supported by old-style deps behavior
130+
-- because it would imply a cyclic dependency for the
131+
-- library itself.
132+
[ (pn, cn)
133+
| (pn, comp_map) <- Map.toList dep_map
134+
, pn /= packageName pkg_descr
135+
, (cn, _) <- Map.toList comp_map
136+
, cn == CLibName ]
137+
138+
reg_lib_map, mixin_map :: Map (PackageName, ComponentName) (IncludeRenaming, Bool)
139+
140+
reg_lib_map = Map.fromList $
141+
reg_lib_deps `zip` repeat (defaultIncludeRenaming, True)
142+
143+
mixin_map = Map.fromList
144+
[ ((pn, cn), (rns, False))
145+
| Mixin pn mb_ln rns <- mixins bi
146+
, let cn = libraryComponentName mb_ln ]
122147

123-
-- Resolve each @mixins@ into the actual dependency
124-
-- from @lib_deps@.
125-
explicit_includes <- forM (mixins bi) $ \(Mixin name rns) -> do
126-
let (pkg, cname) = fixFakePkgName pkg_descr name
127-
aid <-
128-
case Map.lookup cname =<< Map.lookup pkg dep_map of
129-
Nothing ->
130-
dieProgress $
131-
text "Mix-in refers to non-existent package" <+>
132-
quotes (disp name) $$
133-
text "(did you forget to add the package to build-depends?)"
134-
Just r -> return r
148+
lib_deps = Map.toList $ reg_lib_map `Map.union` mixin_map
149+
150+
mixin_includes <- forM lib_deps $ \((pname, cname), (rns, implicit)) -> do
151+
aid <- case Map.lookup cname =<< Map.lookup pname dep_map of
152+
Nothing -> dieProgress $
153+
text "Dependency on unbuildable" <+>
154+
text (showComponentName cname) <+>
155+
text "from" <+> disp pname
156+
Just r -> return r
135157
return ComponentInclude {
136158
ci_ann_id = aid,
137159
ci_renaming = rns,
138-
ci_implicit = False
160+
ci_implicit = implicit
139161
}
140162

141-
-- Any @build-depends@ which is not explicitly mentioned in
142-
-- @backpack-include@ is converted into an "implicit" include.
143-
let used_explicitly = Set.fromList (map ci_id explicit_includes)
144-
implicit_includes
145-
= map (\aid -> ComponentInclude {
146-
ci_ann_id = aid,
147-
ci_renaming = defaultIncludeRenaming,
148-
ci_implicit = True
149-
})
150-
$ filter (flip Set.notMember used_explicitly . ann_id) lib_deps
151-
152163
return ConfiguredComponent {
153164
cc_ann_id = AnnotatedId {
154165
ann_id = this_cid,
@@ -158,22 +169,10 @@ toConfiguredComponent pkg_descr this_cid dep_map component = do
158169
cc_component = component,
159170
cc_public = componentName component == CLibName,
160171
cc_exe_deps = exe_deps,
161-
cc_includes = explicit_includes ++ implicit_includes
172+
cc_includes = mixin_includes
162173
}
163174
where
164175
bi = componentBuildInfo component
165-
-- dep_map contains a mix of internal and external deps.
166-
-- We want all the public libraries (dep_cn == CLibName)
167-
-- of all external deps (dep /= pn). Note that this
168-
-- excludes the public library of the current package:
169-
-- this is not supported by old-style deps behavior
170-
-- because it would imply a cyclic dependency for the
171-
-- library itself.
172-
old_style_lib_deps = [ e
173-
| (pn, comp_map) <- Map.toList dep_map
174-
, pn /= packageName pkg_descr
175-
, (cn, e) <- Map.toList comp_map
176-
, cn == CLibName ]
177176
-- We have to nub here, because 'getAllToolDependencies' may return
178177
-- duplicates (see #4986). (NB: This is not needed for lib_deps,
179178
-- since those elaborate into includes, for which there explicitly
@@ -264,16 +263,3 @@ newPackageDepsBehaviourMinVersion = mkVersion [1,7,1]
264263
newPackageDepsBehaviour :: PackageDescription -> Bool
265264
newPackageDepsBehaviour pkg =
266265
specVersion pkg >= newPackageDepsBehaviourMinVersion
267-
268-
-- | 'build-depends:' stanzas are currently ambiguous as the external packages
269-
-- and internal libraries are specified the same. For now, we assume internal
270-
-- libraries shadow, and this function disambiguates accordingly, but soon the
271-
-- underlying ambiguity will be addressed.
272-
fixFakePkgName :: PackageDescription -> PackageName -> (PackageName, ComponentName)
273-
fixFakePkgName pkg_descr pn =
274-
if subLibName `elem` internalLibraries
275-
then (packageName pkg_descr, CSubLibName subLibName)
276-
else (pn, CLibName)
277-
where
278-
subLibName = packageNameToUnqualComponentName pn
279-
internalLibraries = mapMaybe libName (allLibraries pkg_descr)

Cabal/Distribution/PackageDescription/Check.hs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import Distribution.System
5353
import Distribution.Text
5454
import Distribution.Types.ComponentRequestedSpec
5555
import Distribution.Types.CondTree
56+
import Distribution.Types.LibDependency
5657
import Distribution.Types.ExeDependency
5758
import Distribution.Types.UnqualComponentName
5859
import Distribution.Utils.Generic (isAscii)
@@ -544,6 +545,11 @@ checkFields pkg =
544545
++ ". This version range does not include the current package, and must "
545546
++ "be removed as the current package's library will always be used."
546547

548+
, check (not (null depMissingInternalLibrary)) $
549+
PackageBuildImpossible $
550+
"The package depends on a missing internal library: "
551+
++ commaSep (map display depInternalExecutableWithImpossibleVersion)
552+
547553
, check (not (null depInternalExecutableWithExtraVersion)) $
548554
PackageBuildWarning $
549555
"The package has an extraneous version range for a dependency on an "
@@ -586,17 +592,14 @@ checkFields pkg =
586592
| (compiler, vr) <- testedWith pkg
587593
, isNoVersion vr ]
588594

589-
internalLibraries =
590-
map (maybe (packageName pkg) (unqualComponentNameToPackageName) . libName)
591-
(allLibraries pkg)
595+
internalLibraries = mapMaybe libName $ allLibraries pkg
592596

593597
internalExecutables = map exeName $ executables pkg
594598

595599
internalLibDeps =
596600
[ dep
597-
| bi <- allBuildInfo pkg
598-
, dep@(Dependency name _) <- targetBuildDepends bi
599-
, name `elem` internalLibraries
601+
| dep@(LibDependency name _ _) <- allBuildDepends pkg
602+
, name == packageName pkg
600603
]
601604

602605
internalExeDeps =
@@ -608,17 +611,23 @@ checkFields pkg =
608611

609612
depInternalLibraryWithExtraVersion =
610613
[ dep
611-
| dep@(Dependency _ versionRange) <- internalLibDeps
614+
| dep@(LibDependency _ _ versionRange) <- internalLibDeps
612615
, not $ isAnyVersion versionRange
613616
, packageVersion pkg `withinRange` versionRange
614617
]
615618

616619
depInternalLibraryWithImpossibleVersion =
617620
[ dep
618-
| dep@(Dependency _ versionRange) <- internalLibDeps
621+
| dep@(LibDependency _ _ versionRange) <- internalLibDeps
619622
, not $ packageVersion pkg `withinRange` versionRange
620623
]
621624

625+
depMissingInternalLibrary =
626+
[ dep
627+
| dep@(LibDependency _ (Just lName) _) <- internalLibDeps
628+
, not $ lName `elem` internalLibraries
629+
]
630+
622631
depInternalExecutableWithExtraVersion =
623632
[ dep
624633
| dep@(ExeDependency _ _ versionRange) <- internalExeDeps
@@ -1201,7 +1210,7 @@ checkCabalVersion pkg =
12011210
PackageDistInexcusable $
12021211
"The package uses full version-range expressions "
12031212
++ "in a 'build-depends' field: "
1204-
++ commaSep (map displayRawDependency versionRangeExpressions)
1213+
++ commaSep (map displayRawLibDependency versionRangeExpressions)
12051214
++ ". To use this new syntax the package needs to specify at least "
12061215
++ "'cabal-version: >= 1.8'. Alternatively, if broader compatibility "
12071216
++ "is important, then convert to conjunctive normal form, and use "
@@ -1216,7 +1225,7 @@ checkCabalVersion pkg =
12161225
++ "'cabal-version: >= 1.6'. Alternatively, if broader compatibility "
12171226
++ "is important then use: " ++ commaSep
12181227
[ display (Dependency name (eliminateWildcardSyntax versionRange))
1219-
| Dependency name versionRange <- depsUsingWildcardSyntax ]
1228+
| LibDependency name Nothing versionRange <- depsUsingWildcardSyntax ]
12201229

12211230
-- check use of "build-depends: foo ^>= 1.2.3" syntax
12221231
, checkVersion [2,0] (not (null depsUsingMajorBoundSyntax)) $
@@ -1227,8 +1236,8 @@ checkCabalVersion pkg =
12271236
++ ". To use this new syntax the package need to specify at least "
12281237
++ "'cabal-version: >= 2.0'. Alternatively, if broader compatibility "
12291238
++ "is important then use: " ++ commaSep
1230-
[ display (Dependency name (eliminateMajorBoundSyntax versionRange))
1231-
| Dependency name versionRange <- depsUsingMajorBoundSyntax ]
1239+
[ display (LibDependency name lname (eliminateMajorBoundSyntax versionRange))
1240+
| LibDependency name lname versionRange <- depsUsingMajorBoundSyntax ]
12321241

12331242
, checkVersion [2,1] (any (not . null)
12341243
(concatMap buildInfoField
@@ -1363,7 +1372,7 @@ checkCabalVersion pkg =
13631372
_ -> False
13641373

13651374
versionRangeExpressions =
1366-
[ dep | dep@(Dependency _ vr) <- allBuildDepends pkg
1375+
[ dep | dep@(LibDependency _ _ vr) <- allBuildDepends pkg
13671376
, usesNewVersionRangeSyntax vr ]
13681377

13691378
testedWithVersionRangeExpressions =
@@ -1391,10 +1400,11 @@ checkCabalVersion pkg =
13911400
alg (VersionRangeParensF _) = 3
13921401
alg _ = 1 :: Int
13931402

1394-
depsUsingWildcardSyntax = [ dep | dep@(Dependency _ vr) <- allBuildDepends pkg
1395-
, usesWildcardSyntax vr ]
1403+
depsUsingWildcardSyntax = [ dep
1404+
| dep@(LibDependency _ _ vr) <- allBuildDepends pkg
1405+
, usesWildcardSyntax vr ]
13961406

1397-
depsUsingMajorBoundSyntax = [ dep | dep@(Dependency _ vr) <- allBuildDepends pkg
1407+
depsUsingMajorBoundSyntax = [ dep | dep@(LibDependency _ _ vr) <- allBuildDepends pkg
13981408
, usesMajorBoundSyntax vr ]
13991409

14001410
usesBackpackIncludes = any (not . null . mixins) (allBuildInfo pkg)
@@ -1492,6 +1502,12 @@ displayRawDependency :: Dependency -> String
14921502
displayRawDependency (Dependency pkg vr) =
14931503
display pkg ++ " " ++ display vr
14941504

1505+
displayRawLibDependency :: LibDependency -> String
1506+
displayRawLibDependency (LibDependency pkg ml vr) =
1507+
display pkg
1508+
++ ":lib:" ++ maybe (display pkg) display ml
1509+
++ " " ++ display vr
1510+
14951511

14961512
-- ------------------------------------------------------------
14971513
-- * Checks on the GenericPackageDescription
@@ -1541,7 +1557,7 @@ checkPackageVersions pkg =
15411557
foldr intersectVersionRanges anyVersion baseDeps
15421558
where
15431559
baseDeps =
1544-
[ vr | Dependency pname vr <- allBuildDepends pkg'
1560+
[ vr | LibDependency pname _ vr <- allBuildDepends pkg'
15451561
, pname == mkPackageName "base" ]
15461562

15471563
-- Just in case finalizePD fails for any reason,

0 commit comments

Comments
 (0)