Commit a3d3273a authored by Duncan Coutts's avatar Duncan Coutts
Browse files

Change rep of module re-exports, and do resolution ourselves

The initial support for module re-exports relied on ghc-pkg to resolve
user-specified re-exports to references to specific installed packages.
This resolution is something that can fail so it's better for Cabal to
do it during the package configure phase.

In addition, it is inconvenient in ghc-pkg to be doing this resolution,
and it just seems fishy as a design. Also, the same ModuleExport type
was being used both for user-specified source re-exports and also for
the specific re-exports in the package db.

This patch splits the type into two: one for source level, and one for
resolved ones for use in the package db. The configure phase resolves
one to the other.

One minor change: it is now possible to re-export a module defined in
the same package that is not itself exported (ie it's in other-modules,
rather than exposed-modules). Previously for modules definied in the
same package they had to be themselves exported. Of course for
re-exports from other packages they have to be exposed.
parent 20e35704
...@@ -154,7 +154,6 @@ library ...@@ -154,7 +154,6 @@ library
Distribution.License Distribution.License
Distribution.Make Distribution.Make
Distribution.ModuleName Distribution.ModuleName
Distribution.ModuleExport
Distribution.Package Distribution.Package
Distribution.PackageDescription Distribution.PackageDescription
Distribution.PackageDescription.Check Distribution.PackageDescription.Check
......
...@@ -56,6 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -} ...@@ -56,6 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -}
module Distribution.InstalledPackageInfo ( module Distribution.InstalledPackageInfo (
InstalledPackageInfo_(..), InstalledPackageInfo, InstalledPackageInfo_(..), InstalledPackageInfo,
ModuleReexport(..),
ParseResult(..), PError(..), PWarning, ParseResult(..), PError(..), PWarning,
emptyInstalledPackageInfo, emptyInstalledPackageInfo,
parseInstalledPackageInfo, parseInstalledPackageInfo,
...@@ -82,12 +83,12 @@ import qualified Distribution.Package as Package ...@@ -82,12 +83,12 @@ import qualified Distribution.Package as Package
( Package(..) ) ( Package(..) )
import Distribution.ModuleName import Distribution.ModuleName
( ModuleName ) ( ModuleName )
import Distribution.ModuleExport
( ModuleExport(..) )
import Distribution.Version import Distribution.Version
( Version(..) ) ( Version(..) )
import Distribution.Text import Distribution.Text
( Text(disp, parse) ) ( Text(disp, parse) )
import Text.PrettyPrint as Disp
import qualified Distribution.Compat.ReadP as Parse
-- ----------------------------------------------------------------------------- -- -----------------------------------------------------------------------------
-- The InstalledPackageInfo type -- The InstalledPackageInfo type
...@@ -112,7 +113,7 @@ data InstalledPackageInfo_ m ...@@ -112,7 +113,7 @@ data InstalledPackageInfo_ m
-- these parts are required by an installed package only: -- these parts are required by an installed package only:
exposed :: Bool, exposed :: Bool,
exposedModules :: [m], exposedModules :: [m],
reexportedModules :: [ModuleExport m], reexportedModules :: [ModuleReexport],
hiddenModules :: [m], hiddenModules :: [m],
trusted :: Bool, trusted :: Bool,
importDirs :: [FilePath], -- contain sources in case of Hugs importDirs :: [FilePath], -- contain sources in case of Hugs
...@@ -180,6 +181,31 @@ emptyInstalledPackageInfo ...@@ -180,6 +181,31 @@ emptyInstalledPackageInfo
noVersion :: Version noVersion :: Version
noVersion = Version{ versionBranch=[], versionTags=[] } noVersion = Version{ versionBranch=[], versionTags=[] }
-- -----------------------------------------------------------------------------
-- Module re-exports
data ModuleReexport = ModuleReexport {
moduleReexportDefiningPackage :: InstalledPackageId,
moduleReexportDefiningName :: ModuleName,
moduleReexportName :: ModuleName
}
deriving (Read, Show)
instance Text ModuleReexport where
disp (ModuleReexport pkgid origname newname) =
disp pkgid <> Disp.char ':' <> disp origname
<+> Disp.text "as" <+> disp newname
parse = do
pkgid <- parse
_ <- Parse.char ':'
origname <- parse
Parse.skipSpaces
_ <- Parse.string "as"
Parse.skipSpaces
newname <- parse
return (ModuleReexport pkgid origname newname)
-- ----------------------------------------------------------------------------- -- -----------------------------------------------------------------------------
-- Parsing -- Parsing
......
{-# LANGUAGE DeriveDataTypeable #-}
module Distribution.ModuleExport(ModuleExport(..)) where
import Distribution.Text
( Text(disp, parse) )
import Distribution.Compat.ReadP
( (+++) )
import Distribution.Package
( PackageName, InstalledPackageId )
import qualified Distribution.Compat.ReadP as Parse
import qualified Text.PrettyPrint as Disp
import Text.PrettyPrint ((<+>),(<>))
import Data.Data
-- | Defines a reexport of module 'exportOrigName' from package
-- 'exportOrigPackageId' as new module name 'exportName'. This data type has an
-- interesting invariant: in the installed package database, a ModuleExport is
-- guaranteed to point to the original module which defined the module. Of
-- course, when a user writes a ModuleExport, it may not have this property.
-- ghc-pkg is responsible for enforcing this invariant.
data ModuleExport m = ModuleExport {
-- | Original package name of the reexported module, or Nothing if
-- the user wants us to figure it out automatically. (Note: this package
-- could have reexported the module itself.)
exportOrigPackageName :: Maybe PackageName,
-- | Original module name of reexported module.
exportOrigName :: m,
-- | New module name of reexported module, available to clients
-- of this package.
exportName :: m,
-- | A hack! When ghc-pkg processes 'ModuleExport', it is able to resolve
-- the true, original location an identifier lived in (this cannot be done
-- without consulting the package database), it fills it in here so that
-- GHC can use it. When we get GHC to stop using 'InstalledPackageInfo',
-- this hack can go away.
exportCachedTrueOrig :: Maybe (InstalledPackageId, m)
} deriving (Read, Show, Eq, Data, Typeable)
-- Handy when we need to convert from one ModuleName representation to
-- another (it's used in GHC.)
instance Functor ModuleExport where
fmap f (ModuleExport pnm m m' c) = ModuleExport pnm (f m) (f m')
(fmap (\(x,y)->(x,f y)) c)
instance (Eq m, Text m) => Text (ModuleExport m) where
disp ModuleExport{ exportOrigPackageName = mpnm
, exportOrigName = m
, exportName = m'
, exportCachedTrueOrig = c }
= (maybe Disp.empty (\pnm -> disp pnm <> Disp.char ':') mpnm)
<> disp m
<+> (if m == m'
then Disp.empty
else Disp.text "as" <+> disp m')
<+> (maybe Disp.empty (\(c_ipid, c_m) ->
Disp.parens (disp c_m <> Disp.char '@' <> disp c_ipid)) c)
parse = do Parse.skipSpaces
mpnm <- (do pnm <- parse
_ <- Parse.char ':'
return (Just pnm)
+++ return Nothing)
m <- parse
m' <- (do Parse.skipSpaces
_ <- Parse.string "as"
Parse.skipSpaces
parse)
+++ return m
c <- (do Parse.skipSpaces
_ <- Parse.char '('
c_m <- parse
_ <- Parse.char '@'
c_ipid <- parse
_ <- Parse.char ')'
return (Just (c_ipid, c_m))
+++ return Nothing)
return ModuleExport{ exportOrigPackageName = mpnm
, exportOrigName = m
, exportName = m'
, exportCachedTrueOrig = c }
...@@ -113,7 +113,7 @@ instance Text InstalledPackageId where ...@@ -113,7 +113,7 @@ instance Text InstalledPackageId where
disp (InstalledPackageId str) = text str disp (InstalledPackageId str) = text str
parse = InstalledPackageId `fmap` Parse.munch1 abi_char parse = InstalledPackageId `fmap` Parse.munch1 abi_char
where abi_char c = Char.isAlphaNum c || c `elem` ":-_." where abi_char c = Char.isAlphaNum c || c `elem` "-_."
-- ------------------------------------------------------------ -- ------------------------------------------------------------
-- * Package Keys -- * Package Keys
......
...@@ -33,6 +33,7 @@ module Distribution.PackageDescription ( ...@@ -33,6 +33,7 @@ module Distribution.PackageDescription (
-- ** Libraries -- ** Libraries
Library(..), Library(..),
ModuleReexport(..),
emptyLibrary, emptyLibrary,
withLib, withLib,
hasLibs, hasLibs,
...@@ -109,7 +110,6 @@ import Distribution.Package ...@@ -109,7 +110,6 @@ import Distribution.Package
( PackageName(PackageName), PackageIdentifier(PackageIdentifier) ( PackageName(PackageName), PackageIdentifier(PackageIdentifier)
, Dependency, Package(..) ) , Dependency, Package(..) )
import Distribution.ModuleName ( ModuleName ) import Distribution.ModuleName ( ModuleName )
import Distribution.ModuleExport ( ModuleExport )
import Distribution.Version import Distribution.Version
( Version(Version), VersionRange, anyVersion, orLaterVersion ( Version(Version), VersionRange, anyVersion, orLaterVersion
, asVersionIntervals, LowerBound(..) ) , asVersionIntervals, LowerBound(..) )
...@@ -270,7 +270,7 @@ instance Text BuildType where ...@@ -270,7 +270,7 @@ instance Text BuildType where
data Library = Library { data Library = Library {
exposedModules :: [ModuleName], exposedModules :: [ModuleName],
reexportedModules :: [ModuleExport ModuleName], reexportedModules :: [ModuleReexport],
libExposed :: Bool, -- ^ Is the lib to be exposed by default? libExposed :: Bool, -- ^ Is the lib to be exposed by default?
libBuildInfo :: BuildInfo libBuildInfo :: BuildInfo
} }
...@@ -318,6 +318,37 @@ libModules :: Library -> [ModuleName] ...@@ -318,6 +318,37 @@ libModules :: Library -> [ModuleName]
libModules lib = exposedModules lib libModules lib = exposedModules lib
++ otherModules (libBuildInfo lib) ++ otherModules (libBuildInfo lib)
-- -----------------------------------------------------------------------------
-- Module re-exports
data ModuleReexport = ModuleReexport {
moduleReexportOriginalPackage :: Maybe PackageName,
moduleReexportOriginalName :: ModuleName,
moduleReexportName :: ModuleName
}
deriving (Eq, Read, Show, Typeable, Data)
instance Text ModuleReexport where
disp (ModuleReexport mpkgname origname newname) =
maybe Disp.empty (\pkgname -> disp pkgname <> Disp.char ':') mpkgname
<> disp origname
<+> if newname == origname
then Disp.empty
else Disp.text "as" <+> disp newname
parse = do
mpkgname <- Parse.option Nothing $ do
pkgname <- parse
_ <- Parse.char ':'
return (Just pkgname)
origname <- parse
newname <- Parse.option origname $ do
Parse.skipSpaces
_ <- Parse.string "as"
Parse.skipSpaces
parse
return (ModuleReexport mpkgname origname newname)
-- --------------------------------------------------------------------------- -- ---------------------------------------------------------------------------
-- The Executable type -- The Executable type
......
...@@ -65,8 +65,6 @@ import Distribution.Version ...@@ -65,8 +65,6 @@ import Distribution.Version
import Distribution.Package import Distribution.Package
( PackageName(PackageName), packageName, packageVersion ( PackageName(PackageName), packageName, packageVersion
, Dependency(..), pkgName ) , Dependency(..), pkgName )
import Distribution.ModuleExport
( ModuleExport(..) )
import Distribution.Text import Distribution.Text
( display, disp ) ( display, disp )
...@@ -224,7 +222,7 @@ checkLibrary _pkg lib = ...@@ -224,7 +222,7 @@ checkLibrary _pkg lib =
where where
moduleDuplicates = dups (libModules lib ++ moduleDuplicates = dups (libModules lib ++
map exportName (reexportedModules lib)) map moduleReexportName (reexportedModules lib))
checkExecutable :: PackageDescription -> Executable -> [PackageCheck] checkExecutable :: PackageDescription -> Executable -> [PackageCheck]
checkExecutable pkg exe = checkExecutable pkg exe =
......
...@@ -199,12 +199,11 @@ buildComponent verbosity numJobs pkg_descr lbi suffixes ...@@ -199,12 +199,11 @@ buildComponent verbosity numJobs pkg_descr lbi suffixes
-- Register the library in-place, so exes can depend -- Register the library in-place, so exes can depend
-- on internally defined libraries. -- on internally defined libraries.
pwd <- getCurrentDirectory pwd <- getCurrentDirectory
let installedPkgInfo = let -- The in place registration uses the "-inplace" suffix, not an ABI hash
(inplaceInstalledPackageInfo pwd distPref pkg_descr lib lbi clbi) { ipkgid = inplacePackageId (packageId installedPkgInfo)
-- The in place registration uses the "-inplace" suffix, installedPkgInfo = inplaceInstalledPackageInfo pwd distPref pkg_descr
-- not an ABI hash. ipkgid lib lbi clbi
IPI.installedPackageId = inplacePackageId (packageId installedPkgInfo)
}
registerPackage verbosity registerPackage verbosity
installedPkgInfo pkg_descr lbi True -- True meaning in place installedPkgInfo pkg_descr lbi True -- True meaning in place
(withPackageDB lbi) (withPackageDB lbi)
...@@ -364,6 +363,7 @@ testSuiteLibV09AsLibAndExe pkg_descr ...@@ -364,6 +363,7 @@ testSuiteLibV09AsLibAndExe pkg_descr
libClbi = LibComponentLocalBuildInfo libClbi = LibComponentLocalBuildInfo
{ componentPackageDeps = componentPackageDeps clbi { componentPackageDeps = componentPackageDeps clbi
, componentLibraries = [LibraryName (testName test)] , componentLibraries = [LibraryName (testName test)]
, componentModuleReexports = []
} }
pkg = pkg_descr { pkg = pkg_descr {
package = (package pkg_descr) { package = (package pkg_descr) {
...@@ -382,9 +382,8 @@ testSuiteLibV09AsLibAndExe pkg_descr ...@@ -382,9 +382,8 @@ testSuiteLibV09AsLibAndExe pkg_descr
pkgKey = mkPackageKey (packageKeySupported (compiler lbi)) pkgKey = mkPackageKey (packageKeySupported (compiler lbi))
(package pkg) [] (package pkg) []
} }
ipi = (inplaceInstalledPackageInfo pwd distPref pkg lib lbi libClbi) { ipkgid = inplacePackageId (packageId pkg)
IPI.installedPackageId = inplacePackageId $ packageId ipi ipi = inplaceInstalledPackageInfo pwd distPref pkg ipkgid lib lbi libClbi
}
testDir = buildDir lbi </> stubName test testDir = buildDir lbi </> stubName test
</> stubName test ++ "-tmp" </> stubName test ++ "-tmp"
testLibDep = thisPackageVersion $ package pkg testLibDep = thisPackageVersion $ package pkg
......
...@@ -59,13 +59,18 @@ import Distribution.Package ...@@ -59,13 +59,18 @@ import Distribution.Package
import Distribution.InstalledPackageInfo as Installed import Distribution.InstalledPackageInfo as Installed
( InstalledPackageInfo, InstalledPackageInfo_(..) ( InstalledPackageInfo, InstalledPackageInfo_(..)
, emptyInstalledPackageInfo ) , emptyInstalledPackageInfo )
import qualified Distribution.InstalledPackageInfo as Installed
( ModuleReexport(..) )
import qualified Distribution.Simple.PackageIndex as PackageIndex import qualified Distribution.Simple.PackageIndex as PackageIndex
import Distribution.Simple.PackageIndex (PackageIndex) import Distribution.Simple.PackageIndex (PackageIndex)
import Distribution.PackageDescription as PD import Distribution.PackageDescription as PD
( PackageDescription(..), specVersion, GenericPackageDescription(..) ( PackageDescription(..), specVersion, GenericPackageDescription(..)
, Library(..), hasLibs, Executable(..), BuildInfo(..), allExtensions , Library(..), hasLibs, Executable(..), BuildInfo(..), allExtensions
, HookedBuildInfo, updatePackageDescription, allBuildInfo , HookedBuildInfo, updatePackageDescription, allBuildInfo
, Flag(flagName), FlagName(..), TestSuite(..), Benchmark(..) ) , Flag(flagName), FlagName(..), TestSuite(..), Benchmark(..)
, ModuleReexport(..) )
import Distribution.ModuleName
( ModuleName )
import Distribution.PackageDescription.Configuration import Distribution.PackageDescription.Configuration
( finalizePackageDescription, mapTreeData ) ( finalizePackageDescription, mapTreeData )
import Distribution.PackageDescription.Check import Distribution.PackageDescription.Check
...@@ -120,10 +125,13 @@ import Data.List ...@@ -120,10 +125,13 @@ import Data.List
( (\\), nub, partition, isPrefixOf, inits ) ( (\\), nub, partition, isPrefixOf, inits )
import Data.Maybe import Data.Maybe
( isNothing, catMaybes, fromMaybe ) ( isNothing, catMaybes, fromMaybe )
import Data.Either
( partitionEithers )
import Data.Monoid import Data.Monoid
( Monoid(..) ) ( Monoid(..) )
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Map (Map) import Data.Map (Map)
import qualified Data.Set as Set
import Data.Traversable import Data.Traversable
( mapM ) ( mapM )
import System.Directory import System.Directory
...@@ -393,7 +401,7 @@ configure (pkg_descr0, pbi) cfg ...@@ -393,7 +401,7 @@ configure (pkg_descr0, pbi) cfg
when (maybe False (not.null.PD.reexportedModules) (PD.library pkg_descr) when (maybe False (not.null.PD.reexportedModules) (PD.library pkg_descr)
&& not (reexportedModulesSupported comp)) $ do && not (reexportedModulesSupported comp)) $ do
die $ "Your compiler does not support module reexports. To use" die $ "Your compiler does not support module re-exports. To use "
++ "this feature you probably must use GHC 7.9 or later." ++ "this feature you probably must use GHC 7.9 or later."
checkPackageProblems verbosity pkg_descr0 checkPackageProblems verbosity pkg_descr0
...@@ -468,10 +476,14 @@ configure (pkg_descr0, pbi) cfg ...@@ -468,10 +476,14 @@ configure (pkg_descr0, pbi) cfg
-- internal component graph -- internal component graph
buildComponents <- buildComponents <-
case mkComponentsLocalBuildInfo pkg_descr case mkComponentsGraph pkg_descr internalPkgDeps of
internalPkgDeps externalPkgDeps pkg_key of
Left componentCycle -> reportComponentCycle componentCycle Left componentCycle -> reportComponentCycle componentCycle
Right components -> return components Right components ->
case mkComponentsLocalBuildInfo packageDependsIndex pkg_descr
internalPkgDeps externalPkgDeps
pkg_key components of
Left problems -> reportModuleReexportProblems problems
Right components' -> return components'
-- installation directories -- installation directories
defaultDirs <- defaultInstallDirs flavor userInstall (hasLibs pkg_descr) defaultDirs <- defaultInstallDirs flavor userInstall (hasLibs pkg_descr)
...@@ -1025,20 +1037,16 @@ configCompilerAux = fmap (\(a,_,b) -> (a,b)) . configCompilerAuxEx ...@@ -1025,20 +1037,16 @@ configCompilerAux = fmap (\(a,_,b) -> (a,b)) . configCompilerAuxEx
-- Making the internal component graph -- Making the internal component graph
mkComponentsLocalBuildInfo :: PackageDescription mkComponentsGraph :: PackageDescription
-> [PackageId] -> [InstalledPackageInfo] -> [PackageId]
-> PackageKey -> Either [ComponentName]
-> Either [ComponentName] [(Component, [ComponentName])]
[(ComponentName, mkComponentsGraph pkg_descr internalPkgDeps =
ComponentLocalBuildInfo, [ComponentName])]
mkComponentsLocalBuildInfo pkg_descr internalPkgDeps externalPkgDeps pkg_key =
let graph = [ (c, componentName c, componentDeps c) let graph = [ (c, componentName c, componentDeps c)
| c <- pkgEnabledComponents pkg_descr ] | c <- pkgEnabledComponents pkg_descr ]
in case checkComponentsCyclic graph of in case checkComponentsCyclic graph of
Just ccycle -> Left [ cname | (_,cname,_) <- ccycle ] Just ccycle -> Left [ cname | (_,cname,_) <- ccycle ]
Nothing -> Right [ (cname, clbi, cdeps) Nothing -> Right [ (c, cdeps) | (c, _, cdeps) <- graph ]
| (c, cname, cdeps) <- graph
, let clbi = componentLocalBuildInfo c ]
where where
-- The dependencies for the given component -- The dependencies for the given component
componentDeps component = componentDeps component =
...@@ -1052,6 +1060,28 @@ mkComponentsLocalBuildInfo pkg_descr internalPkgDeps externalPkgDeps pkg_key = ...@@ -1052,6 +1060,28 @@ mkComponentsLocalBuildInfo pkg_descr internalPkgDeps externalPkgDeps pkg_key =
where where
bi = componentBuildInfo component bi = componentBuildInfo component
reportComponentCycle :: [ComponentName] -> IO a
reportComponentCycle cnames =
die $ "Components in the package depend on each other in a cyclic way:\n "
++ intercalate " depends on "
[ "'" ++ showComponentName cname ++ "'"
| cname <- cnames ++ [head cnames] ]
mkComponentsLocalBuildInfo :: PackageIndex
-> PackageDescription
-> [PackageId] -> [InstalledPackageInfo]
-> PackageKey
-> [(Component, [ComponentName])]
-> Either [(ModuleReexport, String)] -- errors
[(ComponentName, ComponentLocalBuildInfo,
[ComponentName])] -- ok
mkComponentsLocalBuildInfo installedPackages pkg_descr
internalPkgDeps externalPkgDeps pkg_key graph =
sequence
[ do clbi <- componentLocalBuildInfo c
return (componentName c, clbi, cdeps)
| (c, cdeps) <- graph ]
where
-- The allPkgDeps contains all the package deps for the whole package -- The allPkgDeps contains all the package deps for the whole package
-- but we need to select the subset for this specific component. -- but we need to select the subset for this specific component.
-- we just take the subset for the package names this component -- we just take the subset for the package names this component
...@@ -1059,22 +1089,25 @@ mkComponentsLocalBuildInfo pkg_descr internalPkgDeps externalPkgDeps pkg_key = ...@@ -1059,22 +1089,25 @@ mkComponentsLocalBuildInfo pkg_descr internalPkgDeps externalPkgDeps pkg_key =
-- versions of the same package. -- versions of the same package.
componentLocalBuildInfo component = componentLocalBuildInfo component =
case component of case component of
CLib _ -> CLib lib -> do
LibComponentLocalBuildInfo { reexports <- resolveModuleReexports installedPackages
(packageId pkg_descr)
externalPkgDeps lib
return LibComponentLocalBuildInfo {
componentPackageDeps = cpds, componentPackageDeps = cpds,
componentLibraries = [LibraryName componentLibraries = [LibraryName ("HS" ++ display pkg_key)],
("HS" ++ display pkg_key)] componentModuleReexports = reexports
} }
CExe _ -> CExe _ ->
ExeComponentLocalBuildInfo { return ExeComponentLocalBuildInfo {
componentPackageDeps = cpds componentPackageDeps = cpds
} }
CTest _ -> CTest _ ->
TestComponentLocalBuildInfo { return TestComponentLocalBuildInfo {
componentPackageDeps = cpds componentPackageDeps = cpds
} }
CBench _ -> CBench _ ->
BenchComponentLocalBuildInfo { return BenchComponentLocalBuildInfo {
componentPackageDeps = cpds componentPackageDeps = cpds
} }
where where
...@@ -1093,13 +1126,134 @@ mkComponentsLocalBuildInfo pkg_descr internalPkgDeps externalPkgDeps pkg_key = ...@@ -1093,13 +1126,134 @@ mkComponentsLocalBuildInfo pkg_descr internalPkgDeps externalPkgDeps pkg_key =
where where
names = [ name | Dependency name _ <- targetBuildDepends bi ] names = [ name | Dependency name _ <- targetBuildDepends bi ]
reportComponentCycle :: [ComponentName] -> IO a -- | Given the author-specified re-export declarations from the .cabal file,
reportComponentCycle cnames = -- resolve them to the form that we need for the package database.
die $ "Components in the package depend on each other in a cyclic way:\n " --
++ intercalate " depends on " -- An invariant of the package database is that we always link the re-export
[ "'" ++ showComponentName cname ++ "'" -- directly to its original defining location (rather than indirectly via a
| cname <- cnames ++ [head cnames] ] -- chain of re-exporting packages).
--
resolveModuleReexports :: PackageIndex
-> PackageId
-> [InstalledPackageInfo]
-> Library
-> Either [(ModuleReexport, String)] -- errors
[Installed.ModuleReexport] -- ok
resolveModuleReexports installedPackages srcpkgid externalPkgDeps lib =
case partitionEithers (map resolveModuleReexport (PD.reexportedModules lib)) of
([], ok) -> Right ok
(errs, _) -> Left errs
where
-- A mapping from visible module names to their original defining
-- module name and package.
visibleModules :: Map ModuleName [(PackageName, ModuleName, InstalledPackageId)]
visibleModules =
Map.fromListWith (++) $
[ (visibleModuleName, [(exportingPackageName,
definingModuleName,
definingPackageId)])
-- The package index here contains all the indirect deps of the
-- package we're configuring, but we want just the direct deps
| let directDeps = Set.fromList (map installedPackageId externalPkgDeps)
, pkg <- PackageIndex.allPackages installedPackages
, installedPackageId pkg `Set.member` directDeps
, let exportingPackageName = packageName pkg
, (visibleModuleName, definingModuleName, definingPackageId)
<- visibleModuleDetails pkg
]
++ [ (visibleModuleName, [(exportingPackageName,
definingModuleName,
definingPackageId)])