Skip to content

Commit dd63604

Browse files
TeofilCmpickering
andcommitted
Support getting nonreinstallable units from GHC
cabal-install includes a hardcoded list of non-reinstallable packages. cabal-install will refuse to use a different version of these packages in a build plan unless the --allow-boot-library-installs flag is set. This list of packages is too pessimistic, and needlessly coupled to GHC. For instance, as of GHC-9.12, `base` and `template-haskell` can be "re-installed" without issue. This patch allows compilers to specify exactly which packages are wired-in and so should not be reinstalled. In the case of GHC-9.14+, this amounts to ghc-internal and ghc itself. If a compiler chooses to specify this information then it overrides the hardcoded non-reinstallable package list. Otherwise, it is still used for the sake of backwards compatibility. Note that this information comes in the form of unit-ids rather than package names. This patch extends the solver with constraints that force the use of a precise unit-id. The behaviour here is still somewhat pessimistic. In the future, we could further relax this restriction and only ban reinstalling these packafes when absolutely necessary, eg, only ban re-installing `ghc` if we are using plugins, etc. For the GHC change that added the interface to expose the unit-id of ghc-internal, see: https://gitlab.haskell.org/ghc/ghc/-/merge_requests/13297 Resolves #10087 Co-Authored-By: Matthew Pickering <[email protected]>
1 parent 01217ac commit dd63604

File tree

13 files changed

+60
-5
lines changed

13 files changed

+60
-5
lines changed

Cabal-syntax/src/Distribution/Compiler.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ import Distribution.Parsec (Parsec (..))
6060
import Distribution.Pretty (Pretty (..), prettyShow)
6161
import qualified System.Info (compilerName, compilerVersion)
6262
import qualified Text.PrettyPrint as Disp
63+
import Distribution.Types.UnitId (UnitId)
64+
import Distribution.Package (PackageName)
6365

6466
data CompilerFlavor
6567
= GHC
@@ -213,6 +215,11 @@ data CompilerInfo = CompilerInfo
213215
-- ^ Supported language standards, if known.
214216
, compilerInfoExtensions :: Maybe [Extension]
215217
-- ^ Supported extensions, if known.
218+
, compilerInfoWiredInUnitIds :: Maybe [(PackageName, UnitId)]
219+
-- ^ 'UnitId's that the compiler doesn't support reinstalling.
220+
-- For instance, when using GHC plugins, one wants to use the
221+
-- exact same version of the `ghc` package as the one the
222+
-- compiler was linked against.
216223
}
217224
deriving (Generic, Show, Read)
218225

@@ -244,4 +251,4 @@ abiTagString (AbiTag tag) = tag
244251
-- compiler id's.
245252
unknownCompilerInfo :: CompilerId -> AbiTag -> CompilerInfo
246253
unknownCompilerInfo compilerId abiTag =
247-
CompilerInfo compilerId abiTag (Just []) Nothing Nothing
254+
CompilerInfo compilerId abiTag (Just []) Nothing Nothing Nothing

Cabal-tests/tests/UnitTests/Distribution/Simple/Program/GHC.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ tests = testGroup "Distribution.Simple.Program.GHC"
5454
, compilerLanguages = []
5555
, compilerExtensions = []
5656
, compilerProperties = Map.singleton "Support parallel --make" "YES"
57+
, compilerWiredInUnitIds = Nothing
5758
})
5859
(Platform X86_64 Linux)
5960
(mempty { ghcOptNumJobs = Flag (NumJobs (Just 4)) })

Cabal/src/Distribution/Simple/Compiler.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ import Distribution.Compiler
101101
import Distribution.Simple.Utils
102102
import Distribution.Utils.Path
103103
import Distribution.Version
104+
import Distribution.Types.UnitId (UnitId)
105+
import Distribution.Package (PackageName)
104106

105107
import Language.Haskell.Extension
106108

@@ -120,6 +122,11 @@ data Compiler = Compiler
120122
-- ^ Supported language standards.
121123
, compilerExtensions :: [(Extension, Maybe CompilerFlag)]
122124
-- ^ Supported extensions.
125+
, compilerWiredInUnitIds :: Maybe [(PackageName, UnitId)]
126+
-- ^ 'UnitId's that the compiler doesn't support reinstalling.
127+
-- For instance, when using GHC plugins, one wants to use the
128+
-- exact same version of the `ghc` package as the one the
129+
-- compiler was linked against.
123130
, compilerProperties :: Map String String
124131
-- ^ A key-value map for properties not covered by the above fields.
125132
}
@@ -178,6 +185,7 @@ compilerInfo c =
178185
(Just . compilerCompat $ c)
179186
(Just . map fst . compilerLanguages $ c)
180187
(Just . map fst . compilerExtensions $ c)
188+
(compilerWiredInUnitIds c)
181189

182190
-- ------------------------------------------------------------
183191

Cabal/src/Distribution/Simple/GHC.hs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,25 @@ configure verbosity hcPath hcPkgPath conf0 = do
247247
compilerId :: CompilerId
248248
compilerId = CompilerId GHC ghcVersion
249249

250+
projectUnitId :: Maybe String
251+
projectUnitId = Map.lookup "Project Unit Id" ghcInfoMap
252+
250253
-- The @AbiTag@ is the @Project Unit Id@ but with redundant information from the compiler version removed.
251254
-- For development versions of the compiler these look like:
252255
-- @Project Unit Id@: "ghc-9.13-inplace"
253256
-- @compilerId@: "ghc-9.13.20250413"
254257
-- So, we need to be careful to only strip the /common/ prefix.
255258
-- In this example, @AbiTag@ is "inplace".
256259
compilerAbiTag :: AbiTag
257-
compilerAbiTag = maybe NoAbiTag AbiTag (dropWhile (== '-') . stripCommonPrefix (prettyShow compilerId) <$> Map.lookup "Project Unit Id" ghcInfoMap)
260+
compilerAbiTag = maybe NoAbiTag AbiTag (dropWhile (== '-') . stripCommonPrefix (prettyShow compilerId) <$> projectUnitId)
261+
262+
wiredInUnitIds = do
263+
ghcInternalUnitId <- Map.lookup "ghc-internal Unit Id" ghcInfoMap
264+
ghcUnitId <- projectUnitId
265+
pure
266+
[ (mkPackageName "ghc", mkUnitId ghcUnitId)
267+
, (mkPackageName "ghc-internal", mkUnitId ghcInternalUnitId)
268+
]
258269

259270
let comp =
260271
Compiler
@@ -264,6 +275,7 @@ configure verbosity hcPath hcPkgPath conf0 = do
264275
, compilerLanguages = languages
265276
, compilerExtensions = extensions
266277
, compilerProperties = ghcInfoMap
278+
, compilerWiredInUnitIds = wiredInUnitIds
267279
}
268280
compPlatform = Internal.targetPlatform ghcInfo
269281
-- configure gcc and ld

Cabal/src/Distribution/Simple/GHCJS.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ configure verbosity hcPath hcPkgPath conf0 = do
203203
, compilerLanguages = languages
204204
, compilerExtensions = extensions
205205
, compilerProperties = ghcInfoMap
206+
, compilerWiredInUnitIds = Nothing
206207
}
207208
compPlatform = Internal.targetPlatform ghcjsInfo
208209
return (comp, compPlatform, progdb3)

Cabal/src/Distribution/Simple/UHC.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ configure verbosity hcPath _hcPkgPath progdb = do
7878
, compilerLanguages = uhcLanguages
7979
, compilerExtensions = uhcLanguageExtensions
8080
, compilerProperties = Map.empty
81+
, compilerWiredInUnitIds = Nothing
8182
}
8283
compPlatform = Nothing
8384
return (comp, compPlatform, progdb')

cabal-install-solver/src/Distribution/Solver/Modular/Message.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ showFR _ UnknownPackage = " (unknown package)"
295295
showFR _ (GlobalConstraintVersion vr (ConstraintSourceProjectConfig pc)) = '\n' : (render . nest 6 $ docProjectConfigPathFailReason vr pc)
296296
showFR _ (GlobalConstraintVersion vr src) = " (" ++ constraintSource src ++ " requires " ++ prettyShow vr ++ ")"
297297
showFR _ (GlobalConstraintInstalled src) = " (" ++ constraintSource src ++ " requires installed instance)"
298+
showFR _ (GlobalConstraintInstalledSpecificUnitId unitId src) = " (" ++ constraintSource src ++ " requires installed instance with unit id " ++ prettyShow unitId ++ ")"
298299
showFR _ (GlobalConstraintSource src) = " (" ++ constraintSource src ++ " requires source instance)"
299300
showFR _ (GlobalConstraintFlag src) = " (" ++ constraintSource src ++ " requires opposite flag selection)"
300301
showFR _ ManualFlag = " (manual flag can only be changed explicitly)"

cabal-install-solver/src/Distribution/Solver/Modular/Package.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Distribution.Solver.Modular.Package
1010
, PN
1111
, QPV
1212
, instI
13+
, instUid
1314
, makeIndependent
1415
, primaryPP
1516
, setupPP
@@ -77,6 +78,10 @@ instI :: I -> Bool
7778
instI (I _ (Inst _)) = True
7879
instI _ = False
7980

81+
instUid :: UnitId -> I -> Bool
82+
instUid uid (I _ (Inst uid')) = uid == uid'
83+
instUid _ _ = False
84+
8085
-- | Is the package in the primary group of packages. This is used to
8186
-- determine (1) if we should try to establish stanza preferences
8287
-- for this goal, and (2) whether or not a user specified @--constraint@

cabal-install-solver/src/Distribution/Solver/Modular/Preference.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ processPackageConstraintP qpn c i (LabeledPackageConstraint (PackageConstraint s
190190
go _ PackagePropertyInstalled
191191
| instI i = r
192192
| otherwise = Fail c (GlobalConstraintInstalled src)
193+
go _ (PackagePropertyInstalledSpecificUnitId unitId)
194+
| instUid unitId i = r
195+
| otherwise = Fail c (GlobalConstraintInstalledSpecificUnitId unitId src)
193196
go _ PackagePropertySource
194197
| not (instI i) = r
195198
| otherwise = Fail c (GlobalConstraintSource src)

cabal-install-solver/src/Distribution/Solver/Modular/Tree.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ data FailReason = UnsupportedExtension Extension
118118
| UnknownPackage
119119
| GlobalConstraintVersion VR ConstraintSource
120120
| GlobalConstraintInstalled ConstraintSource
121+
| GlobalConstraintInstalledSpecificUnitId UnitId ConstraintSource
121122
| GlobalConstraintSource ConstraintSource
122123
| GlobalConstraintFlag ConstraintSource
123124
| ManualFlag

cabal-install-solver/src/Distribution/Solver/Types/PackageConstraint.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module Distribution.Solver.Types.PackageConstraint (
1919
import Distribution.Solver.Compat.Prelude
2020
import Prelude ()
2121

22-
import Distribution.Package (PackageName)
22+
import Distribution.Package (PackageName, UnitId)
2323
import Distribution.PackageDescription (FlagAssignment, dispFlagAssignment)
2424
import Distribution.Pretty (flatStyle, Pretty(pretty))
2525
import Distribution.Types.PackageVersionConstraint (PackageVersionConstraint (..))
@@ -90,6 +90,7 @@ instance Pretty ConstraintScope where
9090
data PackageProperty
9191
= PackagePropertyVersion VersionRange
9292
| PackagePropertyInstalled
93+
| PackagePropertyInstalledSpecificUnitId UnitId
9394
| PackagePropertySource
9495
| PackagePropertyFlags FlagAssignment
9596
| PackagePropertyStanzas [OptionalStanza]
@@ -101,6 +102,7 @@ instance Structured PackageProperty
101102
instance Pretty PackageProperty where
102103
pretty (PackagePropertyVersion verrange) = pretty verrange
103104
pretty PackagePropertyInstalled = Disp.text "installed"
105+
pretty (PackagePropertyInstalledSpecificUnitId unitId) = Disp.text "installed(" <> pretty unitId <> Disp.text ")"
104106
pretty PackagePropertySource = Disp.text "source"
105107
pretty (PackagePropertyFlags flags) = dispFlagAssignment flags
106108
pretty (PackagePropertyStanzas stanzas) =
@@ -138,6 +140,7 @@ packageConstraintToDependency (PackageConstraint scope prop) = toDep prop
138140
where
139141
toDep (PackagePropertyVersion vr) = Just $ PackageVersionConstraint (scopeToPackageName scope) vr
140142
toDep (PackagePropertyInstalled) = Nothing
143+
toDep (PackagePropertyInstalledSpecificUnitId {}) = Nothing
141144
toDep (PackagePropertySource) = Nothing
142145
toDep (PackagePropertyFlags _) = Nothing
143146
toDep (PackagePropertyStanzas _) = Nothing

cabal-install/src/Distribution/Client/Dependency.hs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,16 @@ setSolverVerbosity verbosity params =
435435
{ depResolverVerbosity = verbosity
436436
}
437437

438+
dependOnWiredIns :: CompilerInfo -> DepResolverParams -> DepResolverParams
439+
dependOnWiredIns compiler params = addConstraints extraConstraints params
440+
where
441+
extraConstraints =
442+
[ LabeledPackageConstraint
443+
(PackageConstraint (ScopeAnyQualifier pkgName) (PackagePropertyInstalledSpecificUnitId unitId))
444+
ConstraintSourceNonReinstallablePackage
445+
| (pkgName, unitId) <- fromMaybe [] $ compilerInfoWiredInUnitIds compiler
446+
]
447+
438448
-- | Some packages are specific to a given compiler version and should never be
439449
-- reinstalled.
440450
dontInstallNonReinstallablePackages :: DepResolverParams -> DepResolverParams
@@ -840,8 +850,8 @@ resolveDependencies platform comp pkgConfigDB params =
840850
order
841851
verbosity
842852
) =
843-
if asBool (depResolverAllowBootLibInstalls params)
844-
then params
853+
if isJust (compilerInfoWiredInUnitIds comp) || asBool (depResolverAllowBootLibInstalls params)
854+
then dependOnWiredIns comp params
845855
else dontInstallNonReinstallablePackages params
846856

847857
preferences :: PackageName -> PackagePreferences

cabal-install/tests/UnitTests/Distribution/Client/Store.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ testListEmpty =
4646
, compilerLanguages = []
4747
, compilerExtensions = []
4848
, compilerProperties = mempty
49+
, compilerWiredInUnitIds = Nothing
4950
}
5051

5152
unitid = mkUnitId "foo-1.0-xyz"
@@ -102,6 +103,7 @@ testInstallSerial =
102103
, compilerLanguages = []
103104
, compilerExtensions = []
104105
, compilerProperties = mempty
106+
, compilerWiredInUnitIds = Nothing
105107
}
106108

107109
unitid1 = mkUnitId "foo-1.0-xyz"

0 commit comments

Comments
 (0)