diff --git a/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo.hs b/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo.hs index b510a34d540..b1758312611 100644 --- a/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo.hs +++ b/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo.hs @@ -42,8 +42,10 @@ data InstalledPackageInfo = InstalledPackageInfo sourcePackageId :: PackageId , sourceLibName :: LibraryName , installedComponentId_ :: ComponentId + , installedSublibs :: [InstalledPackageInfo] , libVisibility :: LibraryVisibility , installedUnitId :: UnitId + , installedInstanceUnitId :: InstanceUnitId , -- INVARIANT: if this package is definite, OpenModule's -- OpenUnitId directly records UnitId. If it is -- indefinite, OpenModule is always an OpenModuleVar @@ -135,6 +137,8 @@ emptyInstalledPackageInfo = , sourceLibName = LMainLibName , installedComponentId_ = mkComponentId "" , installedUnitId = mkUnitId "" + , installedInstanceUnitId = mkInstanceUnitId $ mkUnitId "" + , installedSublibs = mempty , instantiatedWith = [] , compatPackageKey = "" , license = Left SPDX.NONE diff --git a/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/FieldGrammar.hs b/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/FieldGrammar.hs index 6d2849c5142..78283c238fc 100644 --- a/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/FieldGrammar.hs +++ b/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/FieldGrammar.hs @@ -61,6 +61,7 @@ ipiFieldGrammar , c (Identity LibraryVisibility) , c (Identity PackageName) , c (Identity UnitId) + , c (Identity InstanceUnitId) , c (Identity UnqualComponentName) , c (List FSep (Identity AbiDependency) AbiDependency) , c (List FSep (Identity UnitId) UnitId) @@ -85,6 +86,7 @@ ipiFieldGrammar = <@> blurFieldGrammar basic basicFieldGrammar -- Basic fields <@> optionalFieldDef "id" L.installedUnitId (mkUnitId "") + <@> optionalFieldDef "instance-id" L.installedInstanceUnitId (mkInstanceUnitId $ mkUnitId "") <@> optionalFieldDefAla "instantiated-with" InstWith L.instantiatedWith [] <@> optionalFieldDefAla "key" CompatPackageKey L.compatPackageKey "" <@> optionalFieldDefAla "license" SpecLicenseLenient L.license (Left SPDX.NONE) @@ -134,6 +136,7 @@ ipiFieldGrammar = (PackageIdentifier pn _basicVersion) (combineLibraryName ln _basicLibName) (mkComponentId "") -- installedComponentId_, not in use + mempty -- installedSublibs _basicLibVisibility where MungedPackageName pn ln = _basicName diff --git a/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/Lens.hs b/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/Lens.hs index 5ced273f460..cbd53817bee 100644 --- a/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/Lens.hs +++ b/Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/Lens.hs @@ -10,7 +10,7 @@ import Prelude () import Distribution.Backpack (OpenModule) import Distribution.License (License) import Distribution.ModuleName (ModuleName) -import Distribution.Package (AbiHash, ComponentId, PackageIdentifier, UnitId) +import Distribution.Package (AbiHash, ComponentId, InstanceUnitId, PackageIdentifier, UnitId) import Distribution.Types.InstalledPackageInfo (AbiDependency, ExposedModule, InstalledPackageInfo) import Distribution.Types.LibraryName (LibraryName) import Distribution.Types.LibraryVisibility (LibraryVisibility) @@ -27,6 +27,10 @@ installedUnitId :: Lens' InstalledPackageInfo UnitId installedUnitId f s = fmap (\x -> s{T.installedUnitId = x}) (f (T.installedUnitId s)) {-# INLINE installedUnitId #-} +installedInstanceUnitId :: Lens' InstalledPackageInfo InstanceUnitId +installedInstanceUnitId f s = fmap (\x -> s{T.installedInstanceUnitId = x}) (f (T.installedInstanceUnitId s)) +{-# INLINE installedInstanceUnitId #-} + installedComponentId_ :: Lens' InstalledPackageInfo ComponentId installedComponentId_ f s = fmap (\x -> s{T.installedComponentId_ = x}) (f (T.installedComponentId_ s)) {-# INLINE installedComponentId_ #-} diff --git a/Cabal-syntax/src/Distribution/Types/UnitId.hs b/Cabal-syntax/src/Distribution/Types/UnitId.hs index 0b5ca4bdf7b..7f5538493c1 100644 --- a/Cabal-syntax/src/Distribution/Types/UnitId.hs +++ b/Cabal-syntax/src/Distribution/Types/UnitId.hs @@ -13,6 +13,9 @@ module Distribution.Types.UnitId , newSimpleUnitId , mkLegacyUnitId , getHSLibraryName + , InstanceUnitId + , mkInstanceUnitId + , unInstanceUnitId ) where import Distribution.Compat.Prelude @@ -131,3 +134,16 @@ instance Parsec DefUnitId where -- is to ensure that the 'DefUnitId' invariant holds. unsafeMkDefUnitId :: UnitId -> DefUnitId unsafeMkDefUnitId = DefUnitId + +-- | A 'UnitId' for an instance (group of components). Typically +-- this matches a main library 'UnitId' +newtype InstanceUnitId = InstanceUnitId {unInstanceUnitId :: UnitId} + deriving (Generic, Read, Show, Eq, Ord, Data, Binary, NFData, Pretty) + +instance Structured InstanceUnitId + +instance Parsec InstanceUnitId where + parsec = InstanceUnitId <$> parsec + +mkInstanceUnitId :: UnitId -> InstanceUnitId +mkInstanceUnitId = InstanceUnitId diff --git a/Cabal-tests/tests/ParserTests/ipi/Includes2.cabal b/Cabal-tests/tests/ParserTests/ipi/Includes2.cabal index efaad1e6540..6c6ccbaca0c 100644 --- a/Cabal-tests/tests/ParserTests/ipi/Includes2.cabal +++ b/Cabal-tests/tests/ParserTests/ipi/Includes2.cabal @@ -1,6 +1,7 @@ name: z-Includes2-z-mylib version: 0.1.0.0 id: Includes2-0.1.0.0-inplace-mylib+3gY9SyjX86dBypHcOaev1n +instance-id: Includes2-0.1.0.0-inplace-mylib+3gY9SyjX86dBypHcOaev1n instantiated-with: Database=Includes2-0.1.0.0-inplace-mysql:Database.MySQL package-name: Includes2 lib-name: mylib diff --git a/Cabal-tests/tests/ParserTests/ipi/Includes2.expr b/Cabal-tests/tests/ParserTests/ipi/Includes2.expr index cc002958c05..f0ed3e0d738 100644 --- a/Cabal-tests/tests/ParserTests/ipi/Includes2.expr +++ b/Cabal-tests/tests/ParserTests/ipi/Includes2.expr @@ -9,10 +9,13 @@ InstalledPackageInfo { (UnqualComponentName "mylib"), installedComponentId_ = ComponentId "", + installedSublibs = [], libVisibility = LibraryVisibilityPrivate, installedUnitId = UnitId "Includes2-0.1.0.0-inplace-mylib+3gY9SyjX86dBypHcOaev1n", + installedInstanceUnitId = InstanceUnitId + (UnitId "Includes2-0.1.0.0-inplace-mylib+3gY9SyjX86dBypHcOaev1n"), instantiatedWith = [ _×_ (ModuleName "Database") diff --git a/Cabal-tests/tests/ParserTests/ipi/Includes2.format b/Cabal-tests/tests/ParserTests/ipi/Includes2.format index ab6445d811d..3eece63182c 100644 --- a/Cabal-tests/tests/ParserTests/ipi/Includes2.format +++ b/Cabal-tests/tests/ParserTests/ipi/Includes2.format @@ -3,6 +3,7 @@ version: 0.1.0.0 package-name: Includes2 lib-name: mylib id: Includes2-0.1.0.0-inplace-mylib+3gY9SyjX86dBypHcOaev1n +instance-id: Includes2-0.1.0.0-inplace-mylib+3gY9SyjX86dBypHcOaev1n instantiated-with: Database=Includes2-0.1.0.0-inplace-mysql:Database.MySQL key: Includes2-0.1.0.0-inplace-mylib+3gY9SyjX86dBypHcOaev1n license: BSD3 diff --git a/Cabal-tests/tests/ParserTests/ipi/internal-preprocessor-test.expr b/Cabal-tests/tests/ParserTests/ipi/internal-preprocessor-test.expr index 3c3be058152..350a782ee81 100644 --- a/Cabal-tests/tests/ParserTests/ipi/internal-preprocessor-test.expr +++ b/Cabal-tests/tests/ParserTests/ipi/internal-preprocessor-test.expr @@ -8,10 +8,13 @@ InstalledPackageInfo { sourceLibName = LMainLibName, installedComponentId_ = ComponentId "", + installedSublibs = [], libVisibility = LibraryVisibilityPublic, installedUnitId = UnitId "internal-preprocessor-test-0.1.0.0", + installedInstanceUnitId = InstanceUnitId + (UnitId ""), instantiatedWith = [], compatPackageKey = "internal-preprocessor-test-0.1.0.0", diff --git a/Cabal-tests/tests/ParserTests/ipi/issue-2276-ghc-9885.expr b/Cabal-tests/tests/ParserTests/ipi/issue-2276-ghc-9885.expr index d5da47695e5..9e57e7896ca 100644 --- a/Cabal-tests/tests/ParserTests/ipi/issue-2276-ghc-9885.expr +++ b/Cabal-tests/tests/ParserTests/ipi/issue-2276-ghc-9885.expr @@ -8,10 +8,13 @@ InstalledPackageInfo { sourceLibName = LMainLibName, installedComponentId_ = ComponentId "", + installedSublibs = [], libVisibility = LibraryVisibilityPublic, installedUnitId = UnitId "transformers-0.5.2.0", + installedInstanceUnitId = InstanceUnitId + (UnitId ""), instantiatedWith = [], compatPackageKey = "transformers-0.5.2.0", diff --git a/Cabal-tests/tests/ParserTests/ipi/transformers.cabal b/Cabal-tests/tests/ParserTests/ipi/transformers.cabal index 2c6387c2206..5329fd959ea 100644 --- a/Cabal-tests/tests/ParserTests/ipi/transformers.cabal +++ b/Cabal-tests/tests/ParserTests/ipi/transformers.cabal @@ -1,6 +1,7 @@ name: transformers version: 0.5.2.0 id: transformers-0.5.2.0 +instance-id: transformers-0.5.2.0 key: transformers-0.5.2.0 license: BSD3 maintainer: Ross Paterson diff --git a/Cabal-tests/tests/ParserTests/ipi/transformers.expr b/Cabal-tests/tests/ParserTests/ipi/transformers.expr index bcb40470a87..cd2a369d90e 100644 --- a/Cabal-tests/tests/ParserTests/ipi/transformers.expr +++ b/Cabal-tests/tests/ParserTests/ipi/transformers.expr @@ -8,10 +8,13 @@ InstalledPackageInfo { sourceLibName = LMainLibName, installedComponentId_ = ComponentId "", + installedSublibs = [], libVisibility = LibraryVisibilityPublic, installedUnitId = UnitId "transformers-0.5.2.0", + installedInstanceUnitId = InstanceUnitId + (UnitId "transformers-0.5.2.0"), instantiatedWith = [], compatPackageKey = "transformers-0.5.2.0", diff --git a/Cabal-tests/tests/ParserTests/ipi/transformers.format b/Cabal-tests/tests/ParserTests/ipi/transformers.format index 66a0e14e5b5..7de14b06258 100644 --- a/Cabal-tests/tests/ParserTests/ipi/transformers.format +++ b/Cabal-tests/tests/ParserTests/ipi/transformers.format @@ -2,6 +2,7 @@ name: transformers version: 0.5.2.0 visibility: public id: transformers-0.5.2.0 +instance-id: transformers-0.5.2.0 key: transformers-0.5.2.0 license: BSD3 maintainer: Ross Paterson diff --git a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs index 93ec21c5b9f..734efdd45d6 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs @@ -33,4 +33,4 @@ md5CheckGenericPackageDescription proxy = md5Check proxy md5CheckLocalBuildInfo :: Proxy LocalBuildInfo -> Assertion md5CheckLocalBuildInfo proxy = md5Check proxy - 0x78979713e08179ab070d6ab10cd5ef6c + 0xe394537933f4b964768db669ff128aa7 diff --git a/Cabal-tree-diff/src/Data/TreeDiff/Instances/Cabal.hs b/Cabal-tree-diff/src/Data/TreeDiff/Instances/Cabal.hs index f8eaad4bf88..f6e5fc093e1 100644 --- a/Cabal-tree-diff/src/Data/TreeDiff/Instances/Cabal.hs +++ b/Cabal-tree-diff/src/Data/TreeDiff/Instances/Cabal.hs @@ -27,7 +27,7 @@ import Distribution.Types.AbiHash (AbiHash) import Distribution.Types.ComponentId (ComponentId) import Distribution.Types.DumpBuildInfo (DumpBuildInfo) import Distribution.Types.PackageVersionConstraint -import Distribution.Types.UnitId (DefUnitId, UnitId) +import Distribution.Types.UnitId (DefUnitId, InstanceUnitId, UnitId) import Distribution.Utils.NubList (NubList) import Distribution.Utils.Path (SymbolicPathX) import Distribution.Utils.ShortText (ShortText, fromShortText) @@ -113,6 +113,7 @@ instance ToExpr ForeignLibOption instance ToExpr ForeignLibType instance ToExpr HaddockTarget instance ToExpr IncludeRenaming +instance ToExpr InstanceUnitId instance ToExpr InstalledPackageInfo instance ToExpr KnownRepoType instance ToExpr LegacyExeDependency diff --git a/Cabal/src/Distribution/Backpack/Configure.hs b/Cabal/src/Distribution/Backpack/Configure.hs index 55d1ae03254..fb6f91e69af 100644 --- a/Cabal/src/Distribution/Backpack/Configure.hs +++ b/Cabal/src/Distribution/Backpack/Configure.hs @@ -67,6 +67,7 @@ configureComponentLocalBuildInfos -> Bool -- deterministic -> Flag String -- configIPID -> Flag ComponentId -- configCID + -> Flag InstanceUnitId -- configIUID -> PackageDescription -> ([PreExistingComponent], [ConfiguredPromisedComponent]) -> FlagAssignment -- configConfigurationsFlags @@ -81,6 +82,7 @@ configureComponentLocalBuildInfos deterministic ipid_flag cid_flag + iuid_flag pkg_descr (prePkgDeps, promisedPkgDeps) flags @@ -127,6 +129,7 @@ configureComponentLocalBuildInfos deterministic ipid_flag cid_flag + iuid_flag pkg_descr conf_pkg_map (map fst graph0) @@ -391,6 +394,7 @@ mkLinkedComponentsLocalBuildInfo comp rcs = map go rcs in LibComponentLocalBuildInfo { componentPackageDeps = cpds , componentUnitId = this_uid + , componentInstanceUnitId = this_instance_uid , componentComponentId = this_cid , componentInstantiatedWith = insts , componentIsIndefinite_ = is_indefinite @@ -445,6 +449,7 @@ mkLinkedComponentsLocalBuildInfo comp rcs = map go rcs } where this_uid = rc_uid rc + this_instance_uid = rc_instance_id rc this_open_uid = rc_open_uid rc this_cid = rc_cid rc cname = componentName (rc_component rc) diff --git a/Cabal/src/Distribution/Backpack/ConfiguredComponent.hs b/Cabal/src/Distribution/Backpack/ConfiguredComponent.hs index 9fd78352b7c..569de9cf988 100644 --- a/Cabal/src/Distribution/Backpack/ConfiguredComponent.hs +++ b/Cabal/src/Distribution/Backpack/ConfiguredComponent.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE PatternSynonyms #-} + -- | See module Distribution.Backpack.ConfiguredComponent ( ConfiguredComponent (..) @@ -22,7 +24,7 @@ import Distribution.CabalSpecVersion import Distribution.Package import Distribution.PackageDescription import Distribution.Simple.BuildToolDepends -import Distribution.Simple.Flag (Flag) +import Distribution.Simple.Flag (Flag, pattern Flag, pattern NoFlag) import Distribution.Simple.LocalBuildInfo import Distribution.Types.AnnotatedId import Distribution.Types.ComponentInclude @@ -43,6 +45,7 @@ import qualified Text.PrettyPrint as PP data ConfiguredComponent = ConfiguredComponent { cc_ann_id :: AnnotatedId ComponentId -- ^ Unique identifier of component, plus extra useful info. + , cc_instance_unit_id :: InstanceUnitId , cc_component :: Component -- ^ The fragment of syntax from the Cabal file describing this -- component. @@ -98,11 +101,12 @@ dispConfiguredComponent cc = mkConfiguredComponent :: PackageDescription -> ComponentId + -> InstanceUnitId -> [AnnotatedId ComponentId] -- lib deps -> [AnnotatedId ComponentId] -- exe deps -> Component -> LogProgress ConfiguredComponent -mkConfiguredComponent pkg_descr this_cid lib_deps exe_deps component = do +mkConfiguredComponent pkg_descr this_cid this_iuid lib_deps exe_deps component = do -- Resolve each @mixins@ into the actual dependency -- from @lib_deps@. explicit_includes <- forM (mixins bi) $ \(Mixin pn ln rns) -> do @@ -142,6 +146,7 @@ mkConfiguredComponent pkg_descr this_cid lib_deps exe_deps component = do , ann_pid = package pkg_descr , ann_cname = componentName component } + , cc_instance_unit_id = this_iuid , cc_component = component , cc_public = is_public , cc_exe_deps = exe_deps @@ -170,11 +175,12 @@ type ConfiguredComponentMap = toConfiguredComponent :: PackageDescription -> ComponentId + -> InstanceUnitId -> ConfiguredComponentMap -> ConfiguredComponentMap -> Component -> LogProgress ConfiguredComponent -toConfiguredComponent pkg_descr this_cid lib_dep_map exe_dep_map component = do +toConfiguredComponent pkg_descr this_cid this_iuid lib_dep_map exe_dep_map component = do lib_deps <- if newPackageDepsBehaviour pkg_descr then fmap concat $ @@ -202,6 +208,7 @@ toConfiguredComponent pkg_descr this_cid lib_dep_map exe_dep_map component = do mkConfiguredComponent pkg_descr this_cid + this_iuid lib_deps exe_deps component @@ -246,6 +253,7 @@ toConfiguredComponent' -> Bool -- deterministic -> Flag String -- configIPID (todo: remove me) -> Flag ComponentId -- configCID + -> Flag InstanceUnitId -- configIUID -> ConfiguredComponentMap -> Component -> LogProgress ConfiguredComponent @@ -256,12 +264,14 @@ toConfiguredComponent' deterministic ipid_flag cid_flag + iuid_flag dep_map component = do cc <- toConfiguredComponent pkg_descr this_cid + this_iuid dep_map dep_map component @@ -279,6 +289,10 @@ toConfiguredComponent' (package pkg_descr) (componentName component) (Just (deps, flags)) + this_iuid = + case iuid_flag of + Flag iuid -> iuid + NoFlag -> mkInstanceUnitId $ mkUnitId $ unComponentId this_cid deps = [ ann_id aid | m <- Map.elems dep_map, aid <- Map.elems m ] @@ -308,6 +322,7 @@ toConfiguredComponents -> Bool -- deterministic -> Flag String -- configIPID -> Flag ComponentId -- configCID + -> Flag InstanceUnitId -- configIUID -> PackageDescription -> ConfiguredComponentMap -> [Component] @@ -318,6 +333,7 @@ toConfiguredComponents deterministic ipid_flag cid_flag + iuid_flag pkg_descr dep_map comps = @@ -332,6 +348,7 @@ toConfiguredComponents deterministic ipid_flag cid_flag + iuid_flag m component return (extendConfiguredComponentMap cc m, cc) diff --git a/Cabal/src/Distribution/Backpack/LinkedComponent.hs b/Cabal/src/Distribution/Backpack/LinkedComponent.hs index d041c715aac..961a604ec74 100644 --- a/Cabal/src/Distribution/Backpack/LinkedComponent.hs +++ b/Cabal/src/Distribution/Backpack/LinkedComponent.hs @@ -50,6 +50,8 @@ import Text.PrettyPrint (Doc, hang, hsep, quotes, text, vcat, ($+$)) data LinkedComponent = LinkedComponent { lc_ann_id :: AnnotatedId ComponentId -- ^ Uniquely identifies linked component + , lc_instance_id :: InstanceUnitId + -- ^ Uniquely identifies instance (group of components) , lc_component :: Component -- ^ Corresponds to 'cc_component'. , lc_exe_deps :: [AnnotatedId OpenUnitId] @@ -128,6 +130,7 @@ toLinkedComponent pkg_map ConfiguredComponent { cc_ann_id = aid@AnnotatedId{ann_id = this_cid} + , cc_instance_unit_id = iuid , cc_component = component , cc_exe_deps = exe_deps , cc_public = is_public @@ -378,6 +381,7 @@ toLinkedComponent return $ LinkedComponent { lc_ann_id = aid + , lc_instance_id = iuid , lc_component = component , lc_public = is_public , -- These must be executables diff --git a/Cabal/src/Distribution/Backpack/ReadyComponent.hs b/Cabal/src/Distribution/Backpack/ReadyComponent.hs index 3eef45fadbb..143a49435a5 100644 --- a/Cabal/src/Distribution/Backpack/ReadyComponent.hs +++ b/Cabal/src/Distribution/Backpack/ReadyComponent.hs @@ -55,6 +55,8 @@ import Distribution.Version -- for every way these packages can be fully instantiated. data ReadyComponent = ReadyComponent { rc_ann_id :: AnnotatedId UnitId + , rc_instance_id :: InstanceUnitId + -- ^ Uniquely identifies instance (group of components) , rc_open_uid :: OpenUnitId -- ^ The 'OpenUnitId' for this package. At the moment, this -- is used in only one case, which is to determine if an @@ -319,6 +321,7 @@ toReadyComponents pid_map subst0 comps = Just ReadyComponent { rc_ann_id = (lc_ann_id lc){ann_id = uid} + , rc_instance_id = lc_instance_id lc , rc_open_uid = DefiniteUnitId (unsafeMkDefUnitId uid) , rc_cid = lc_cid lc , rc_component = lc_component lc @@ -387,6 +390,7 @@ toReadyComponents pid_map subst0 comps = Just ReadyComponent { rc_ann_id = (lc_ann_id lc){ann_id = uid} + , rc_instance_id = lc_instance_id lc , rc_cid = lc_cid lc , rc_open_uid = lc_uid lc , rc_component = lc_component lc diff --git a/Cabal/src/Distribution/Simple/Build.hs b/Cabal/src/Distribution/Simple/Build.hs index e79a1924eb9..5954b139367 100644 --- a/Cabal/src/Distribution/Simple/Build.hs +++ b/Cabal/src/Distribution/Simple/Build.hs @@ -851,6 +851,7 @@ testSuiteLibV09AsLibAndExe , componentIsPublic = False , componentIncludes = componentIncludes clbi , componentUnitId = componentUnitId clbi + , componentInstanceUnitId = componentInstanceUnitId clbi , componentComponentId = componentComponentId clbi , componentInstantiatedWith = [] , componentCompatPackageName = compat_name diff --git a/Cabal/src/Distribution/Simple/Configure.hs b/Cabal/src/Distribution/Simple/Configure.hs index df1acb72658..64cfc629f88 100644 --- a/Cabal/src/Distribution/Simple/Configure.hs +++ b/Cabal/src/Distribution/Simple/Configure.hs @@ -721,6 +721,10 @@ preConfigurePackage verbHandles cfg g_pkg_descr = do when (isJust (flagToMaybe (configCID cfg)) && isNothing mb_cname) $ dieWithException verbosity ConfigCIDValidForPreComponent + -- configIUID is only valid for per-component configure + when (isJust (flagToMaybe (configIUID cfg)) && isNothing mb_cname) $ + dieWithException verbosity ConfigIUIDValidForPreComponent + -- Make a data structure describing what components are enabled. let enabled :: ComponentRequestedSpec enabled = @@ -1427,7 +1431,7 @@ configureComponents -- components (which may build-depends on each other) and form a graph. -- From there, we build a ComponentLocalBuildInfo for each of the -- components, which lets us actually build each component. - ( buildComponents :: [ComponentLocalBuildInfo] + ( buildComponents0 :: [ComponentLocalBuildInfo] , packageDependsIndex :: InstalledPackageIndex ) <- runLogProgress verbosity $ @@ -1438,6 +1442,7 @@ configureComponents (fromFlagOrDefault False (configDeterministic cfg)) (configIPID cfg) (configCID cfg) + (configIUID cfg) pkg_descr externalPkgDeps (configConfigurationsFlags cfg) @@ -1445,6 +1450,47 @@ configureComponents installedPackageSet comp + -- Set a common 'InstanceUnitId' for all components so they can be + -- identified as belonging to the same group. + -- + -- If the package has a main library, its 'InstanceUnitId' is used. + -- Otherwise, an arbitrary component's 'InstanceUnitId' is used. + -- + -- Only for 'ComponentRequestedSpec'. + -- For 'OneComponentRequestedSpec', 'InstanceUnitId' is passed via 'configIUID' flag. + let maybeSetCommonInstanceUnitId = + case enabled of + -- Whole package configure, set InstanceUnitIDs + ComponentRequestedSpec{} -> + let + setCommonInstanceUnitId + :: [ComponentLocalBuildInfo] + -> [ComponentLocalBuildInfo] + setCommonInstanceUnitId [] = [] + setCommonInstanceUnitId [single] = [single] + setCommonInstanceUnitId comps@(fstComp : _rest) = + let + assignOne newId LibComponentLocalBuildInfo{..} = LibComponentLocalBuildInfo{componentInstanceUnitId = newId, ..} + assignOne _newId other = other + + assignAll newId = map (assignOne newId) comps + + matchMainLib lclbi@(LibComponentLocalBuildInfo{}) = componentLocalName lclbi == CLibName LMainLibName + matchMainLib _ = False + in + case find matchMainLib comps of + Nothing -> + -- no main library, use arbitrary (first one) for componentInstanceUnitId assignment + assignAll (mkInstanceUnitId $ componentUnitId fstComp) + Just mainLib -> + assignAll (componentInstanceUnitId mainLib) + in + setCommonInstanceUnitId + -- Component configure, InstanceUnitID passed via flag + OneComponentRequestedSpec{} -> id + + let buildComponents = maybeSetCommonInstanceUnitId buildComponents0 + let buildComponentsMap = foldl' ( \m clbi -> diff --git a/Cabal/src/Distribution/Simple/Errors.hs b/Cabal/src/Distribution/Simple/Errors.hs index 4dc21def00d..6830af76aa7 100644 --- a/Cabal/src/Distribution/Simple/Errors.hs +++ b/Cabal/src/Distribution/Simple/Errors.hs @@ -115,6 +115,7 @@ data CabalException | NoValidComponent | ConfigureEitherSingleOrAll | ConfigCIDValidForPreComponent + | ConfigIUIDValidForPreComponent | SanityCheckForEnableComponents | SanityCheckForDynamicStaticLinking | UnsupportedLanguages PackageIdentifier CompilerId [String] @@ -249,6 +250,7 @@ exceptionCode e = case e of NoValidComponent{} -> 5680 ConfigureEitherSingleOrAll{} -> 2001 ConfigCIDValidForPreComponent{} -> 7006 + ConfigIUIDValidForPreComponent{} -> 7007 SanityCheckForEnableComponents{} -> 5004 SanityCheckForDynamicStaticLinking{} -> 4007 UnsupportedLanguages{} -> 8074 @@ -510,6 +512,7 @@ exceptionMessage e = case e of NoValidComponent -> "No valid component targets found" ConfigureEitherSingleOrAll -> "Can only configure either a single component or all of them" ConfigCIDValidForPreComponent -> "--cid is only supported for per-component configure" + ConfigIUIDValidForPreComponent -> "--iuid is only supported for per-component configure" SanityCheckForEnableComponents -> "--enable-tests/--enable-benchmarks are incompatible with" ++ " explicitly specifying a component to configure." diff --git a/Cabal/src/Distribution/Simple/Register.hs b/Cabal/src/Distribution/Simple/Register.hs index 3e603a14d6a..22ba700cf15 100644 --- a/Cabal/src/Distribution/Simple/Register.hs +++ b/Cabal/src/Distribution/Simple/Register.hs @@ -501,7 +501,9 @@ generalInstalledPackageInfo adjustRelIncDirs pkg abi_hash lib lbi clbi installDi IPI.InstalledPackageInfo { IPI.sourcePackageId = packageId pkg , IPI.installedUnitId = componentUnitId clbi + , IPI.installedInstanceUnitId = componentInstanceUnitId clbi , IPI.installedComponentId_ = componentComponentId clbi + , IPI.installedSublibs = mempty , IPI.instantiatedWith = expectLibraryComponent (maybeComponentInstantiatedWith clbi) , IPI.sourceLibName = libName lib , IPI.compatPackageKey = expectLibraryComponent (maybeComponentCompatPackageKey clbi) diff --git a/Cabal/src/Distribution/Simple/Setup/Config.hs b/Cabal/src/Distribution/Simple/Setup/Config.hs index 92fb879df9a..4652ac15c0b 100644 --- a/Cabal/src/Distribution/Simple/Setup/Config.hs +++ b/Cabal/src/Distribution/Simple/Setup/Config.hs @@ -164,6 +164,8 @@ data ConfigFlags = ConfigFlags -- ^ explicit IPID to be used , configCID :: Flag ComponentId -- ^ explicit CID to be used + , configIUID :: Flag InstanceUnitId + -- ^ explicit InstanceUnitID to be used , configDeterministic :: Flag Bool -- ^ be as deterministic as possible -- (e.g., invariant over GHC, database, diff --git a/Cabal/src/Distribution/Types/ComponentLocalBuildInfo.hs b/Cabal/src/Distribution/Types/ComponentLocalBuildInfo.hs index 32f4aab473b..a7880664745 100644 --- a/Cabal/src/Distribution/Types/ComponentLocalBuildInfo.hs +++ b/Cabal/src/Distribution/Types/ComponentLocalBuildInfo.hs @@ -24,7 +24,6 @@ import Distribution.Types.UnitId import qualified Distribution.InstalledPackageInfo as Installed --- | The first five fields are common across all algebraic variants. data ComponentLocalBuildInfo = LibComponentLocalBuildInfo { componentLocalName :: ComponentName @@ -39,6 +38,9 @@ data ComponentLocalBuildInfo , componentUnitId :: UnitId -- ^ The computed 'UnitId' which uniquely identifies this -- component. Might be hashed. + , componentInstanceUnitId :: InstanceUnitId + -- ^ The 'InstanceUnitId' which uniquely identifies package instance + -- (equal to componentUnitId for main component, sub components inherit it from main) , componentIsIndefinite_ :: Bool -- ^ Is this an indefinite component (i.e. has unfilled holes)? , componentInstantiatedWith :: [(ModuleName, OpenModule)] diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/ConfiguredConversion.hs b/cabal-install-solver/src/Distribution/Solver/Modular/ConfiguredConversion.hs index 0e2e8ad5baa..e306631aa5a 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/ConfiguredConversion.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/ConfiguredConversion.hs @@ -5,8 +5,11 @@ module Distribution.Solver.Modular.ConfiguredConversion import Data.Maybe import Prelude hiding (pi) import Data.Either (partitionEithers) +import Data.Set (Set) +import qualified Data.Set as S import Distribution.Package (UnitId, packageId) +import Distribution.Types.InstalledPackageInfo (InstalledPackageInfo(installedSublibs)) import qualified Distribution.Simple.PackageIndex as SI @@ -30,9 +33,10 @@ convCP :: SI.InstalledPackageIndex -> CP QPN -> ResolverPackage loc convCP iidx sidx (CP qpi fa es ds) = case convPI qpi of - Left pi -> PreExisting $ + Left (pi, subPis) -> + PreExisting $ InstSolverPackage { - instSolverPkgIPI = fromJust $ SI.lookupUnitId iidx pi, + instSolverPkgIPI = addSublibs iidx subPis $ fromJust $ SI.lookupUnitId iidx pi, instSolverPkgLibDeps = fmap fst ds', instSolverPkgExeDeps = fmap snd ds' } @@ -50,15 +54,29 @@ convCP iidx sidx (CP qpi fa es ds) = ds' :: ComponentDeps ([SolverId] {- lib -}, [SolverId] {- exe -}) ds' = fmap (partitionEithers . map convConfId) ds -convPI :: PI QPN -> Either UnitId PackageId -convPI (PI _ (I _ (Inst pi))) = Left pi -convPI pi = Right (packageId (either id id (convConfId pi))) + addSublibs + :: SI.InstalledPackageIndex + -> Set UnitId + -> InstalledPackageInfo + -> InstalledPackageInfo + addSublibs idx subPis info = + info { installedSublibs = + mapMaybe + (SI.lookupUnitId idx) + (S.toList subPis) + } + +convPI :: PI QPN -> Either (UnitId, Set UnitId) PackageId +convPI (PI _ (I _ (Inst pi))) = Left (pi, mempty) +convPI (PI _ (I _ (InstGroup pi subPis))) = Left (pi, subPis) +convPI pi = Right (packageId (either id id (convConfId pi))) convConfId :: PI QPN -> Either SolverId {- is lib -} SolverId {- is exe -} convConfId (PI (Q (PackagePath _ q) pn) (I v loc)) = case loc of Inst pi -> Left (PreExistingId sourceId pi) - _otherwise + InstGroup pi _subPis -> Left (PreExistingId sourceId pi) + InRepo | QualExe _ pn' <- q -- NB: the dependencies of the executable are also -- qualified. So the way to tell if this is an executable diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Dependency.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Dependency.hs index fff2dacde4e..3b0fe5a95eb 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Dependency.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Dependency.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE StandaloneDeriving #-} module Distribution.Solver.Modular.Dependency ( -- * Variables Var(..) @@ -94,6 +95,8 @@ data FlaggedDep qpn = -- | Dependencies which are always enabled, for the component 'comp'. | Simple (LDep qpn) Component +deriving instance Show qpn => Show (FlaggedDep qpn) + -- | Conservatively flatten out flagged dependencies -- -- NOTE: We do not filter out duplicates. @@ -115,6 +118,7 @@ type FalseFlaggedDeps qpn = FlaggedDeps qpn -- depending; having a 'Functor' instance makes bugs where we don't distinguish -- these two far too likely. (By rights 'LDep' ought to have two type variables.) data LDep qpn = LDep (DependencyReason qpn) (Dep qpn) + deriving Show -- | A dependency (constraint) associates a package name with a constrained -- instance. It can also represent other types of dependencies, such as @@ -123,7 +127,7 @@ data Dep qpn = Dep (PkgComponent qpn) CI -- ^ dependency on a package component | Ext Extension -- ^ dependency on a language extension | Lang Language -- ^ dependency on a language version | Pkg PkgconfigName PkgconfigVersionRange -- ^ dependency on a pkg-config package - deriving Functor + deriving (Functor, Show) -- | An exposed component within a package. This type is used to represent -- build-depends and build-tool-depends dependencies. diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Index.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Index.hs index 2f28d12de85..e04b62dd0c7 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Index.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Index.hs @@ -36,6 +36,7 @@ data PInfo = PInfo (FlaggedDeps PN) (Map ExposedComponent ComponentInfo) FlagInfo (Maybe FailReason) + deriving Show -- | Info associated with each library and executable in a package instance. data ComponentInfo = ComponentInfo { diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/IndexConversion.hs b/cabal-install-solver/src/Distribution/Solver/Modular/IndexConversion.hs index f150235631f..b3235d0dd69 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/IndexConversion.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/IndexConversion.hs @@ -6,6 +6,7 @@ import Distribution.Solver.Compat.Prelude import Prelude () import qualified Data.List as L +import qualified Data.Maybe import qualified Data.Map.Strict as M import qualified Distribution.Compat.NonEmptySet as NonEmptySet import qualified Data.Set as S @@ -18,8 +19,6 @@ import Distribution.Types.ExeDependency -- from Cabal import Distribution.Types.PkgconfigDependency -- from Cabal import Distribution.Types.ComponentName -- from Cabal import Distribution.Types.CondTree -- from Cabal -import Distribution.Types.MungedPackageId -- from Cabal -import Distribution.Types.MungedPackageName -- from Cabal import Distribution.PackageDescription -- from Cabal import Distribution.PackageDescription.Configuration import qualified Distribution.Simple.PackageIndex as SI @@ -62,43 +61,118 @@ convPIs :: OS -> Arch -> CompilerInfo -> Map PN [LabeledPackageConstraint] -> Index convPIs os arch comp constraints sip strfl solveExes iidx sidx = mkIndex $ - convIPI' sip iidx ++ convSPI' os arch comp constraints strfl solveExes sidx + groupInstalledSublibs (convIPI' sip iidx) + ++ (convSPI' os arch comp constraints strfl solveExes sidx) + +-- | Group packages with the same package name and version, +-- merge their sub-libraries and dependencies so we get +-- a similar looking package as if it came from repository. +groupInstalledSublibs + :: [(PN, I, InstanceUnitId, PInfo)] + -> [(PN, I, PInfo)] +groupInstalledSublibs xs = + remapPInfoDepsToInstGroups + $ M.elems + $ M.map (\(pn, i, _instId, pInfo) -> (pn, i, pInfo)) + $ foldl + (\acc x@(pn, I ver _, instId, _) -> + M.insertWith + (\(_, newI, newInstId, newInfo) (_, oldI, _oldInstId, oldInfo) -> + (pn, mergeIs oldI newI, newInstId, mergeInfos oldInfo newInfo) + ) + (pn, ver, instId) + x + acc + ) + M.empty + xs + where + -- flags are probably safe to ignore here as they are fixed for installed anyway + mergeInfos :: PInfo -> PInfo -> PInfo + mergeInfos (PInfo deps comps flagNfo fr) (PInfo deps' comps' _flagNfo _fr) = + PInfo + (deps <> deps') + (comps <> comps') + flagNfo + fr + + -- this pass creates InstGroup(s) + mergeIs :: I -> I -> I + mergeIs (I ver (Inst pId)) (I _ver (Inst subPId)) = + I ver (InstGroup pId (S.singleton subPId)) + mergeIs (I ver (InstGroup pId subPIds)) (I _ver (Inst subPId)) = + I ver (InstGroup pId (S.insert subPId subPIds)) + -- XXX/srk, can't really happen as they are lexicographically ordered + mergeIs a b = error $ "Absurd mergeIs" <> show (a,b) + + -- now some deps from convIP/convIPId pass refer to Inst when they should refer to InstGroup + remapPInfoDepsToInstGroups :: [(PN, I, PInfo)] -> [(PN, I, PInfo)] + remapPInfoDepsToInstGroups ps = + let + -- Inst -> InstGroup mapping, other Loc(s) are preserved + locMap :: Map Loc Loc + locMap = + M.fromList + $ concatMap + (\(_pn, I _ver loc, _pInfo) -> case loc of + ip@(Inst _pId) -> + pure (ip, ip) + g@(InstGroup pId subPIds) -> + (Inst pId, g):(map (\x -> (Inst x, g)) (S.toList subPIds)) + InRepo -> + pure (InRepo, InRepo) + ) + ps + + remapDep :: FlaggedDep PN -> FlaggedDep PN + remapDep (D.Simple (LDep dr (Dep depComp (Fixed (I ver loc)))) comp) = + let newLoc = Data.Maybe.fromJust $ M.lookup loc locMap + in (D.Simple (LDep dr (Dep depComp (Fixed (I ver newLoc)))) comp) + remapDep x = x + + in map + (\(pn, i, PInfo deps comps flagNfo fr) -> + (pn, i, PInfo (map remapDep deps) comps flagNfo fr) + ) + ps + -- | Convert a Cabal installed package index to the simpler, -- more uniform index format of the solver. -convIPI' :: ShadowPkgs -> SI.InstalledPackageIndex -> [(PN, I, PInfo)] +convIPI' :: ShadowPkgs -> SI.InstalledPackageIndex -> [(PN, I, InstanceUnitId, PInfo)] convIPI' (ShadowPkgs sip) idx = -- apply shadowing whenever there are multiple installed packages with -- the same version [ maybeShadow (convIP idx pkg) - -- IMPORTANT to get internal libraries. See - -- Note [Index conversion with internal libraries] + -- IMPORTANT to use @allPackagesBySourcePackageIdAndLibName@ to get internal libraries | (_, pkgs) <- SI.allPackagesBySourcePackageIdAndLibName idx , (maybeShadow, pkg) <- zip (id : repeat shadow) pkgs ] where -- shadowing is recorded in the package info - shadow (pn, i, PInfo fdeps comps fds _) - | sip = (pn, i, PInfo fdeps comps fds (Just Shadowed)) + shadow (pn, i, instId, PInfo fdeps comps fds _) + | sip = (pn, i, instId, PInfo fdeps comps fds (Just Shadowed)) shadow x = x -- | Extract/recover the package ID from an installed package info, and convert it to a solver's I. convId :: IPI.InstalledPackageInfo -> (PN, I) -convId ipi = (pn, I ver $ Inst $ IPI.installedUnitId ipi) - where MungedPackageId mpn ver = mungedId ipi - -- HACK. See Note [Index conversion with internal libraries] - pn = encodeCompatPackageName mpn +convId ipi = ( pkgName spi + , I (pkgVersion spi) $ Inst $ IPI.installedUnitId ipi + ) + where spi = IPI.sourcePackageId ipi -- | Convert a single installed package into the solver-specific format. -convIP :: SI.InstalledPackageIndex -> IPI.InstalledPackageInfo -> (PN, I, PInfo) +convIP + :: SI.InstalledPackageIndex + -> IPI.InstalledPackageInfo + -> (PN, I, InstanceUnitId, PInfo) convIP idx ipi = case traverse (convIPId (DependencyReason pn M.empty S.empty) comp idx) (IPI.depends ipi) of - Left u -> (pn, i, PInfo [] M.empty M.empty (Just (Broken u))) - Right fds -> (pn, i, PInfo fds components M.empty Nothing) + Left u -> (pn, i, IPI.installedInstanceUnitId ipi, PInfo [] M.empty M.empty (Just (Broken u))) + Right fds -> (pn, i, IPI.installedInstanceUnitId ipi, PInfo fds components M.empty Nothing) where - -- TODO: Handle sub-libraries and visibility. components = - M.singleton (ExposedLib LMainLibName) + M.singleton (ExposedLib $ IPI.sourceLibName ipi) ComponentInfo { compIsVisible = IsVisible True , compIsBuildable = IsBuildable True @@ -111,45 +185,22 @@ convIP idx ipi = comp = componentNameToComponent $ CLibName $ IPI.sourceLibName ipi -- TODO: Installed packages should also store their encapsulations! --- Note [Index conversion with internal libraries] --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- Something very interesting happens when we have internal libraries --- in our index. In this case, we maybe have p-0.1, which itself --- depends on the internal library p-internal ALSO from p-0.1. --- Here's the danger: --- --- - If we treat both of these packages as having PN "p", --- then the solver will try to pick one or the other, --- but never both. --- --- - If we drop the internal packages, now p-0.1 has a --- dangling dependency on an "installed" package we know --- nothing about. Oops. --- --- An expedient hack is to put p-internal into cabal-install's --- index as a MUNGED package name, so that it doesn't conflict --- with anyone else (except other instances of itself). But --- yet, we ought NOT to say that PNs in the solver are munged --- package names, because they're not; for source packages, --- we really will never see munged package names. --- --- The tension here is that the installed package index is actually --- per library, but the solver is per package. We need to smooth --- it over, and munging the package names is a pretty good way to --- do it. - -- | Convert dependencies specified by an installed package id into -- flagged dependencies of the solver. -- -- May return Nothing if the package can't be found in the index. That -- indicates that the original package having this dependency is broken -- and should be ignored. -convIPId :: DependencyReason PN -> Component -> SI.InstalledPackageIndex -> UnitId -> Either UnitId (FlaggedDep PN) +convIPId :: DependencyReason PN + -> Component + -> SI.InstalledPackageIndex + -> UnitId + -> Either UnitId (FlaggedDep PN) convIPId dr comp idx ipid = case SI.lookupUnitId idx ipid of Nothing -> Left ipid Just ipi -> let (pn, i) = convId ipi - name = ExposedLib LMainLibName -- TODO: Handle sub-libraries. + name = ExposedLib $ IPI.sourceLibName ipi in Right (D.Simple (LDep dr (Dep (PkgComponent pn name) (Fixed i))) comp) -- NB: something we pick up from the -- InstalledPackageIndex is NEVER an executable diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs index 5dbcce9194c..03c8afb2663 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs @@ -289,7 +289,7 @@ showOptions q [x] = showOption q x showOptions q xs = showQPN q ++ "; " ++ (L.intercalate ", " [if isJust linkedTo then showOption q x - else showI i -- Don't show the package, just the version + else showI q i -- Don't show the package, just the version | x@(POption i linkedTo) <- xs ]) @@ -351,7 +351,7 @@ showConflictingDep (ConflictingDep dr (PkgComponent qpn comp) ci) = ExposedLib (LSubLibName lib) -> " (lib " ++ unUnqualComponentName lib ++ ")" in case ci of Fixed i -> (if qpn /= qpn' then showDependencyReason dr ++ " => " else "") ++ - showQPN qpn ++ componentStr ++ "==" ++ showI i + showQPN qpn ++ componentStr ++ "==" ++ showI qpn i Constrained vr -> showDependencyReason dr ++ " => " ++ showQPN qpn ++ componentStr ++ showVR vr diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Package.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Package.hs index 876ac2d790c..9cda3734465 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Package.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Package.hs @@ -22,12 +22,16 @@ module Distribution.Solver.Modular.Package import Prelude () import Distribution.Solver.Compat.Prelude +import qualified Data.List as L +import qualified Data.Set as S + import Distribution.Package -- from Cabal import Distribution.Pretty (prettyShow) import Distribution.Solver.Modular.Version import Distribution.Solver.Types.PackagePath + -- | A package name. type PN = PackageName @@ -49,7 +53,10 @@ type PId = UnitId -- package instance via its 'PId'. -- -- TODO: More information is needed about the repo. -data Loc = Inst PId | InRepo +data Loc + = Inst PId + | InstGroup PId (Set PId) + | InRepo deriving (Eq, Ord, Show) -- | Instance. A version number and a location. @@ -57,14 +64,29 @@ data I = I Ver Loc deriving (Eq, Ord, Show) -- | String representation of an instance. -showI :: I -> String -showI (I v InRepo) = showVer v -showI (I v (Inst uid)) = showVer v ++ "/installed" ++ extractPackageAbiHash uid - where - extractPackageAbiHash xs = - case first reverse $ break (=='-') $ reverse (prettyShow xs) of - (ys, []) -> ys - (ys, _) -> '-' : ys +showI :: QPN -> I -> String +showI _qpn (I v InRepo) = showVer v +showI qpn (I v (Inst uid)) = + let + uidPrefix = showQPN qpn <> "-" <> showVer v <> "-" + renderUid u = + case L.stripPrefix uidPrefix (prettyShow u) of + Nothing -> showVer v + Just stripped -> stripped + in + showVer v <> "/installed-" <> renderUid uid +showI qpn (I v (InstGroup uid subUids)) = + let + uidPrefix = showQPN qpn <> "-" <> showVer v <> "-" + renderUid u = + case L.stripPrefix uidPrefix (prettyShow u) of + Nothing -> prettyShow u + Just stripped -> stripped + in + showI qpn (I v (Inst uid)) + <> " installed package group [" + <> unwords (map renderUid $ S.toList subUids) + <> "]" -- | Package instance. A package name and an instance. data PI qpn = PI qpn I @@ -72,7 +94,7 @@ data PI qpn = PI qpn I -- | String representation of a package instance. showPI :: PI QPN -> String -showPI (PI qpn i) = showQPN qpn ++ "-" ++ showI i +showPI (PI qpn i) = showQPN qpn ++ "-" ++ showI qpn i instI :: I -> Bool instI (I _ (Inst _)) = True diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs index ed01234bdba..88d494d4396 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs @@ -129,6 +129,7 @@ type PPreAssignment = Map QPN MergedPkgDep -- | A dependency on a component, including its DependencyReason. data PkgDep = PkgDep (DependencyReason QPN) (PkgComponent QPN) CI + deriving Show -- | Map from component name to one of the reasons that the component is -- required. @@ -146,6 +147,7 @@ type ComponentDependencyReasons = Map ExposedComponent (DependencyReason QPN) data MergedPkgDep = MergedDepFixed ExposedComponent (DependencyReason QPN) I | MergedDepConstrained [VROrigin] + deriving Show -- | Version ranges paired with origins. type VROrigin = (VR, ExposedComponent, DependencyReason QPN) diff --git a/cabal-install-solver/src/Distribution/Solver/Types/InstSolverPackage.hs b/cabal-install-solver/src/Distribution/Solver/Types/InstSolverPackage.hs index 871a0dd15a9..719ac0ea2ef 100644 --- a/cabal-install-solver/src/Distribution/Solver/Types/InstSolverPackage.hs +++ b/cabal-install-solver/src/Distribution/Solver/Types/InstSolverPackage.hs @@ -6,12 +6,9 @@ module Distribution.Solver.Types.InstSolverPackage import Distribution.Solver.Compat.Prelude import Prelude () -import Distribution.Package ( Package(..), HasMungedPackageId(..), HasUnitId(..) ) +import Distribution.Package ( Package(..), HasUnitId(..) ) import Distribution.Solver.Types.ComponentDeps ( ComponentDeps ) import Distribution.Solver.Types.SolverId -import Distribution.Types.MungedPackageId -import Distribution.Types.PackageId -import Distribution.Types.MungedPackageName import Distribution.InstalledPackageInfo (InstalledPackageInfo) -- | An 'InstSolverPackage' is a pre-existing installed package @@ -27,13 +24,7 @@ instance Binary InstSolverPackage instance Structured InstSolverPackage instance Package InstSolverPackage where - packageId i = - -- HACK! See Note [Index conversion with internal libraries] - let MungedPackageId mpn v = mungedId i - in PackageIdentifier (encodeCompatPackageName mpn) v - -instance HasMungedPackageId InstSolverPackage where - mungedId = mungedId . instSolverPkgIPI + packageId = packageId . instSolverPkgIPI instance HasUnitId InstSolverPackage where installedUnitId = installedUnitId . instSolverPkgIPI diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs index dd353e422a6..b050ef7a5a8 100644 --- a/cabal-install/src/Distribution/Client/Config.hs +++ b/cabal-install/src/Distribution/Client/Config.hs @@ -527,6 +527,7 @@ instance Semigroup SavedConfig where , configDeterministic = combine configDeterministic , configIPID = combine configIPID , configCID = combine configCID + , configIUID = combine configIUID , configUserInstall = combine configUserInstall , -- TODO: NubListify configPackageDBs = lastNonEmpty configPackageDBs diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs index 2168e9054c7..d29b5f24db2 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs @@ -1105,6 +1105,7 @@ convertToLegacyAllPackageConfig , configDeterministic = mempty , configIPID = mempty , configCID = mempty + , configIUID = mempty , configConfigurationsFlags = mempty , configTests = mempty , configCoverage = mempty -- TODO: don't merge @@ -1182,6 +1183,7 @@ convertToLegacyPerPackageConfig PackageConfig{..} = , configExtraIncludeDirs = fmap makeSymbolicPath packageConfigExtraIncludeDirs , configIPID = mempty , configCID = mempty + , configIUID = mempty , configDeterministic = mempty , configConfigurationsFlags = packageConfigFlagAssignment , configTests = packageConfigTests diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index 87b41a0be73..d2f7e86f694 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -1673,18 +1673,19 @@ elaborateInstallPlan preexistingInstantiatedPkgs :: Map UnitId FullUnitId preexistingInstantiatedPkgs = - Map.fromList (mapMaybe f (SolverInstallPlan.toList solverPlan)) + Map.fromList (concat $ mapMaybe f (SolverInstallPlan.toList solverPlan)) where f (SolverInstallPlan.PreExisting inst) | let ipkg = instSolverPkgIPI inst , not (IPI.indefinite ipkg) = - Just - ( IPI.installedUnitId ipkg - , ( FullUnitId - (IPI.installedComponentId ipkg) - (Map.fromList (IPI.instantiatedWith ipkg)) - ) - ) + let mkEntry x = + ( IPI.installedUnitId x + , ( FullUnitId + (IPI.installedComponentId x) + (Map.fromList (IPI.instantiatedWith x)) + ) + ) + in Just $ (mkEntry ipkg) : (map mkEntry (IPI.installedSublibs ipkg)) f _ = Nothing elaboratedInstallPlan @@ -1693,7 +1694,9 @@ elaborateInstallPlan flip InstallPlan.fromSolverInstallPlanWithProgress solverPlan $ \mapDep planpkg -> case planpkg of SolverInstallPlan.PreExisting pkg -> - return [InstallPlan.PreExisting (instSolverPkgIPI pkg)] + return $ + [InstallPlan.PreExisting (instSolverPkgIPI pkg)] + ++ map InstallPlan.PreExisting (IPI.installedSublibs (instSolverPkgIPI pkg)) SolverInstallPlan.Configured pkg -> let inplace_doc | shouldBuildInplaceOnly pkg = text "inplace" @@ -1704,7 +1707,28 @@ elaborateInstallPlan <+> text "package" <+> quotes (pretty (packageId pkg)) ) - $ map InstallPlan.Configured <$> elaborateSolverToComponents mapDep pkg + $ map InstallPlan.Configured . setCommonInstanceUnitId <$> elaborateSolverToComponents mapDep pkg + + -- Set a common 'InstanceUnitId' for all components so they can be + -- identified as belonging to the same group. + -- + -- If the package has a main library, its 'InstanceUnitId' is used. + -- Otherwise, an arbitrary component's 'InstanceUnitId' is used. + setCommonInstanceUnitId + :: [ElaboratedConfiguredPackage] + -> [ElaboratedConfiguredPackage] + setCommonInstanceUnitId [] = [] + setCommonInstanceUnitId [single] = [single] + setCommonInstanceUnitId elabPkgs@(elabPkg : _rest) = + let + assignAll instanceUnitId = map (\x -> x{elabInstanceUnitId = instanceUnitId}) elabPkgs + in + case find (matchElabPkg (== (CLibName LMainLibName))) elabPkgs of + Nothing -> + -- no main library, use arbitrary (first one) for elabInstanceUnitID assignment + assignAll (elabInstanceUnitId elabPkg) + Just mainLib -> + assignAll (elabInstanceUnitId mainLib) -- NB: We don't INSTANTIATE packages at this point. That's -- a post-pass. This makes it simpler to compute dependencies. @@ -1819,6 +1843,7 @@ elaborateInstallPlan elab0 { elabModuleShape = emptyModuleShape , elabUnitId = notImpl "elabUnitId" + , elabInstanceUnitId = notImpl "elabInstanceUnitId" , elabComponentId = notImpl "elabComponentId" , elabLinkedInstantiatedWith = Map.empty , elabInstallDirs = notImpl "elabInstallDirs" @@ -1878,6 +1903,7 @@ elaborateInstallPlan toConfiguredComponent pd (error "Distribution.Client.ProjectPlanning.cc_cid: filled in later") + (error "Distribution.Client.ProjectPlanning.cc_instance_unit_id: filled in later") (Map.unionWith Map.union external_lib_cc_map cc_map) (Map.unionWith Map.union external_exe_cc_map cc_map) comp @@ -1927,7 +1953,11 @@ elaborateInstallPlan elaboratedSharedConfig elab1 -- knot tied ) - cc = cc0{cc_ann_id = fmap (const cid) (cc_ann_id cc0)} + cc = + cc0 + { cc_ann_id = fmap (const cid) (cc_ann_id cc0) + , cc_instance_unit_id = mkInstanceUnitId $ mkUnitId $ unComponentId cid + } infoProgress $ dispConfiguredComponent cc -- 4. Perform mix-in linking @@ -1955,6 +1985,7 @@ elaborateInstallPlan elab1 { elabModuleShape = lc_shape lc , elabUnitId = abstractUnitId (lc_uid lc) + , elabInstanceUnitId = lc_instance_id lc , elabComponentId = lc_cid lc , elabLinkedInstantiatedWith = Map.fromList (lc_insts lc) , elabPkgOrComp = @@ -2123,6 +2154,7 @@ elaborateInstallPlan elab0 { elabUnitId = newSimpleUnitId pkgInstalledId , elabComponentId = pkgInstalledId + , elabInstanceUnitId = mkInstanceUnitId $ newSimpleUnitId pkgInstalledId , elabLinkedInstantiatedWith = Map.empty , elabPkgOrComp = ElabPackage $ ElaboratedPackage{..} , elabModuleShape = modShape @@ -2227,6 +2259,7 @@ elaborateInstallPlan -- These get filled in later elabUnitId = error "elaborateSolverToCommon: elabUnitId" + elabInstanceUnitId = error "elaborateSolverToCommon: elabInstanceUnitId" elabComponentId = error "elaborateSolverToCommon: elabComponentId" elabInstantiatedWith = Map.empty elabLinkedInstantiatedWith = error "elaborateSolverToCommon: elabLinkedInstantiatedWith" @@ -2676,12 +2709,7 @@ shouldBeLocal (SpecificSourcePackage pkg) = case srcpkgSource pkg of -- | Given a 'ElaboratedPlanPackage', report if it matches a 'ComponentName'. matchPlanPkg :: (ComponentName -> Bool) -> ElaboratedPlanPackage -> Bool -matchPlanPkg p = InstallPlan.foldPlanPackage (p . ipiComponentName) (matchElabPkg p) - --- | Get the appropriate 'ComponentName' which identifies an installed --- component. -ipiComponentName :: IPI.InstalledPackageInfo -> ComponentName -ipiComponentName = CLibName . IPI.sourceLibName +matchPlanPkg p = InstallPlan.foldPlanPackage (p . IPI.sourceComponentName) (matchElabPkg p) -- | Given a 'ElaboratedConfiguredPackage', report if it matches a -- 'ComponentName'. @@ -2713,7 +2741,7 @@ mkCCMapping = ( \ipkg -> ( packageName ipkg , Map.singleton - (ipiComponentName ipkg) + (IPI.sourceComponentName ipkg) -- TODO: libify ( AnnotatedId { ann_id = IPI.installedComponentId ipkg @@ -3175,7 +3203,7 @@ availableInstalledTargets ipkg = status = TargetBuildable (unitid, cname) TargetRequestedByDefault target = AvailableTarget (packageId ipkg) cname status False fake = False - in [(packageId ipkg, cname, fake, target)] + in (packageId ipkg, cname, fake, target) : (concatMap availableInstalledTargets (IPI.installedSublibs ipkg)) availableSourceTargets :: ElaboratedConfiguredPackage @@ -3637,10 +3665,11 @@ pruneInstallPlanPass1 pkgs ] availablePkgs = - Set.fromList - [ installedUnitId pkg - | InstallPlan.PreExisting pkg <- pkgs - ] + Set.fromList $ + concat + [ (installedUnitId pkg) : (map installedUnitId (IPI.installedSublibs pkg)) + | InstallPlan.PreExisting pkg <- pkgs + ] {- Note [Pruning for Multi Repl] @@ -4122,6 +4151,7 @@ setupHsConfigureFlags configCID = case elabPkgOrComp of ElabPackage _ -> mempty ElabComponent _ -> toFlag elabComponentId + configIUID = toFlag elabInstanceUnitId configProgramPaths = Map.toList elabProgramPaths configProgramArgs = Map.toList elabProgramArgs diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs index adbd8a85f5e..ed56682b388 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs @@ -203,6 +203,9 @@ instance Structured ElaboratedSharedConfig data ElaboratedConfiguredPackage = ElaboratedConfiguredPackage { elabUnitId :: UnitId -- ^ The 'UnitId' which uniquely identifies this item in a build plan + , elabInstanceUnitId :: InstanceUnitId + -- ^ The 'InstanceUnitId' which uniquely identifies package instance + -- (equal to elabUnitId for main component, sub components inherit it from main) , elabComponentId :: ComponentId , elabInstantiatedWith :: Map ModuleName Module , elabLinkedInstantiatedWith :: Map ModuleName OpenModule diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index ad043c68b7c..49476965d57 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -719,6 +719,7 @@ filterConfigureFlags' flags cabalLibVersion flags_latest { configBytecodeLib = NoFlag , configInstallDirs = (configInstallDirs flags){bytecodelibdir = NoFlag} + , configIUID = NoFlag } flags_3_13_0 = diff --git a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/Solver.hs b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/Solver.hs index 9ea020bd512..ef1d8da532b 100644 --- a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/Solver.hs +++ b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/Solver.hs @@ -932,7 +932,7 @@ tests = , runTest $ let db = [ Right $ exAv "my-package" 1 [ExFix "other-package" 3] - , Left $ exInst "other-package" 2 "other-package-AbCdEfGhIj0123456789" [] + , Left $ exInst "other-package" 2 "other-package-2-AbCdEfGhIj0123456789" [] ] msg = "rejecting: other-package-2/installed-AbCdEfGhIj0123456789" in mkTest db "show full installed package ABI hash (issue #5892)" ["my-package"] $ diff --git a/cabal.project b/cabal.project index a2075cfdc29..cc64225a0e4 100644 --- a/cabal.project +++ b/cabal.project @@ -12,3 +12,5 @@ package cabal-install package Cabal flags: +git-rev + +multi-repl: True diff --git a/changelog.d/pr-11788.md b/changelog.d/pr-11788.md new file mode 100644 index 00000000000..aef943b1184 --- /dev/null +++ b/changelog.d/pr-11788.md @@ -0,0 +1,11 @@ +--- +synopsis: Group installed multilib packages +packages: [Cabal, Cabal-syntax, cabal-install, cabal-install-solver] +prs: 11788 +--- + +Introduce `InstanceUnitId` (`instance-id`) field for `InstalledPackageInfo` uniquely identifying +group of components. + +Group components in solvers index conversion pass, allowing us to treat installed packages +similar to source packages.