%
% (c) The University of Glasgow, 2006
%
\begin{code}
module Packages (
module PackageConfig,
PackageConfigMap, emptyPackageConfigMap, lookupPackage,
extendPackageConfigMap, dumpPackages,
PackageState(..),
initPackages,
getPackageDetails,
lookupModuleInAllPackages, lookupModuleWithSuggestions,
getPackageIncludePath,
getPackageLibraryPath,
getPackageLinkOpts,
getPackageExtraCcOpts,
getPackageFrameworkPath,
getPackageFrameworks,
getPreloadPackagesAnd,
collectIncludeDirs, collectLibraryPaths, collectLinkOpts,
packageHsLibs,
isDllName
)
where
#include "HsVersions.h"
import PackageConfig
import DynFlags
import StaticFlags
import Config ( cProjectVersion )
import Name ( Name, nameModule_maybe )
import UniqFM
import Module
import Util
import Panic
import Outputable
import Maybes
import System.Environment ( getEnv )
import Distribution.InstalledPackageInfo
import Distribution.InstalledPackageInfo.Binary
import Distribution.Package hiding (PackageId,depends)
import FastString
import ErrUtils ( debugTraceMsg, putMsg, Message )
import Exception
import System.Directory
import System.FilePath as FilePath
import qualified System.FilePath.Posix as FilePath.Posix
import Control.Monad
import Data.List as List
import Data.Map (Map)
import qualified Data.Map as Map
import qualified FiniteMap as Map
import qualified Data.Set as Set
data PackageState = PackageState {
pkgIdMap :: PackageConfigMap,
preloadPackages :: [PackageId],
moduleToPkgConfAll :: UniqFM [(PackageConfig,Bool)],
installedPackageIdMap :: InstalledPackageIdMap
}
type PackageConfigMap = UniqFM PackageConfig
type InstalledPackageIdMap = Map InstalledPackageId PackageId
type InstalledPackageIndex = Map InstalledPackageId PackageConfig
emptyPackageConfigMap :: PackageConfigMap
emptyPackageConfigMap = emptyUFM
lookupPackage :: PackageConfigMap -> PackageId -> Maybe PackageConfig
lookupPackage = lookupUFM
extendPackageConfigMap
:: PackageConfigMap -> [PackageConfig] -> PackageConfigMap
extendPackageConfigMap pkg_map new_pkgs
= foldl add pkg_map new_pkgs
where add pkg_map p = addToUFM pkg_map (packageConfigId p) p
getPackageDetails :: PackageState -> PackageId -> PackageConfig
getPackageDetails ps pid = expectJust "getPackageDetails" (lookupPackage (pkgIdMap ps) pid)
initPackages :: DynFlags -> IO (DynFlags, [PackageId])
initPackages dflags = do
pkg_db <- case pkgDatabase dflags of
Nothing -> readPackageConfigs dflags
Just db -> return $ setBatchPackageFlags dflags db
(pkg_state, preload, this_pkg)
<- mkPackageState dflags pkg_db [] (thisPackage dflags)
return (dflags{ pkgDatabase = Just pkg_db,
pkgState = pkg_state,
thisPackage = this_pkg },
preload)
readPackageConfigs :: DynFlags -> IO [PackageConfig]
readPackageConfigs dflags = do
e_pkg_path <- tryIO (getEnv "GHC_PACKAGE_PATH")
system_pkgconfs <- getSystemPackageConfigs dflags
let pkgconfs = case e_pkg_path of
Left _ -> system_pkgconfs
Right path
| last cs == "" -> init cs ++ system_pkgconfs
| otherwise -> cs
where cs = parseSearchPath path
pkgs <- mapM (readPackageConfig dflags)
(pkgconfs ++ reverse (extraPkgConfs dflags))
return (concat pkgs)
getSystemPackageConfigs :: DynFlags -> IO [FilePath]
getSystemPackageConfigs dflags = do
let system_pkgconf = systemPackageConfig dflags
user_pkgconf <- do
if not (dopt Opt_ReadUserPackageConf dflags) then return [] else do
appdir <- getAppUserDataDirectory "ghc"
let
dir = appdir </> (TARGET_ARCH ++ '-':TARGET_OS ++ '-':cProjectVersion)
pkgconf = dir </> "package.conf.d"
exist <- doesDirectoryExist pkgconf
if exist then return [pkgconf] else return []
`catchIO` (\_ -> return [])
return (system_pkgconf : user_pkgconf)
readPackageConfig :: DynFlags -> FilePath -> IO [PackageConfig]
readPackageConfig dflags conf_file = do
isdir <- doesDirectoryExist conf_file
proto_pkg_configs <-
if isdir
then do let filename = conf_file </> "package.cache"
debugTraceMsg dflags 2 (text "Using binary package database:" <+> text filename)
conf <- readBinPackageDB filename
return (map installedPackageInfoToPackageConfig conf)
else do
isfile <- doesFileExist conf_file
when (not isfile) $
ghcError $ InstallationError $
"can't find a package database at " ++ conf_file
debugTraceMsg dflags 2 (text "Using package config file:" <+> text conf_file)
str <- readFile conf_file
return (map installedPackageInfoToPackageConfig $ read str)
let
top_dir = topDir dflags
pkgroot = takeDirectory conf_file
pkg_configs1 = map (mungePackagePaths top_dir pkgroot) proto_pkg_configs
pkg_configs2 = setBatchPackageFlags dflags pkg_configs1
return pkg_configs2
setBatchPackageFlags :: DynFlags -> [PackageConfig] -> [PackageConfig]
setBatchPackageFlags dflags pkgs = (maybeDistrustAll . maybeHideAll) pkgs
where
maybeHideAll pkgs'
| dopt Opt_HideAllPackages dflags = map hide pkgs'
| otherwise = pkgs'
maybeDistrustAll pkgs'
| dopt Opt_DistrustAllPackages dflags = map distrust pkgs'
| otherwise = pkgs'
hide pkg = pkg{ exposed = False }
distrust pkg = pkg{ exposed = False }
mungePackagePaths :: FilePath -> FilePath -> PackageConfig -> PackageConfig
mungePackagePaths top_dir pkgroot pkg =
pkg {
importDirs = munge_paths (importDirs pkg),
includeDirs = munge_paths (includeDirs pkg),
libraryDirs = munge_paths (libraryDirs pkg),
frameworkDirs = munge_paths (frameworkDirs pkg),
haddockInterfaces = munge_paths (haddockInterfaces pkg),
haddockHTMLs = munge_urls (haddockHTMLs pkg)
}
where
munge_paths = map munge_path
munge_urls = map munge_url
munge_path p
| Just p' <- stripVarPrefix "${pkgroot}" p = pkgroot ++ p'
| Just p' <- stripVarPrefix "$topdir" p = top_dir ++ p'
| otherwise = p
munge_url p
| Just p' <- stripVarPrefix "${pkgrooturl}" p = toUrlPath pkgroot p'
| Just p' <- stripVarPrefix "$httptopdir" p = toUrlPath top_dir p'
| otherwise = p
toUrlPath r p = "file:///"
++ FilePath.Posix.joinPath
(r :
dropWhile (all isPathSeparator)
(FilePath.splitDirectories p))
stripVarPrefix var path = case stripPrefix var path of
Just [] -> Just []
Just cs@(c : _) | isPathSeparator c -> Just cs
_ -> Nothing
applyPackageFlag
:: UnusablePackages
-> [PackageConfig]
-> PackageFlag
-> IO [PackageConfig]
applyPackageFlag unusable pkgs flag =
case flag of
ExposePackage str ->
case selectPackages (matchingStr str) pkgs unusable of
Left ps -> packageFlagErr flag ps
Right (p:ps,qs) -> return (p':ps')
where p' = p {exposed=True}
ps' = hideAll (pkgName (sourcePackageId p)) (ps++qs)
_ -> panic "applyPackageFlag"
ExposePackageId str ->
case selectPackages (matchingId str) pkgs unusable of
Left ps -> packageFlagErr flag ps
Right (p:ps,qs) -> return (p':ps')
where p' = p {exposed=True}
ps' = hideAll (pkgName (sourcePackageId p)) (ps++qs)
_ -> panic "applyPackageFlag"
HidePackage str ->
case selectPackages (matchingStr str) pkgs unusable of
Left ps -> packageFlagErr flag ps
Right (ps,qs) -> return (map hide ps ++ qs)
where hide p = p {exposed=False}
TrustPackage str ->
case selectPackages (matchingStr str) pkgs unusable of
Left ps -> packageFlagErr flag ps
Right (ps,qs) -> return (map trust ps ++ qs)
where trust p = p {trusted=True}
DistrustPackage str ->
case selectPackages (matchingStr str) pkgs unusable of
Left ps -> packageFlagErr flag ps
Right (ps,qs) -> return (map distrust ps ++ qs)
where distrust p = p {trusted=False}
_ -> panic "applyPackageFlag"
where
hideAll name ps = map maybe_hide ps
where maybe_hide p
| pkgName (sourcePackageId p) == name = p {exposed=False}
| otherwise = p
selectPackages :: (PackageConfig -> Bool) -> [PackageConfig]
-> UnusablePackages
-> Either [(PackageConfig, UnusablePackageReason)]
([PackageConfig], [PackageConfig])
selectPackages matches pkgs unusable
= let
(ps,rest) = partition matches pkgs
reasons = [ (p, Map.lookup (installedPackageId p) unusable)
| p <- ps ]
in
if all (isJust.snd) reasons
then Left [ (p, reason) | (p,Just reason) <- reasons ]
else Right (sortByVersion [ p | (p,Nothing) <- reasons ], rest)
matchingStr :: String -> PackageConfig -> Bool
matchingStr str p
= str == display (sourcePackageId p)
|| str == display (pkgName (sourcePackageId p))
matchingId :: String -> PackageConfig -> Bool
matchingId str p = InstalledPackageId str == installedPackageId p
sortByVersion :: [InstalledPackageInfo_ m] -> [InstalledPackageInfo_ m]
sortByVersion = sortBy (flip (comparing (pkgVersion.sourcePackageId)))
comparing :: Ord a => (t -> a) -> t -> t -> Ordering
comparing f a b = f a `compare` f b
packageFlagErr :: PackageFlag
-> [(PackageConfig, UnusablePackageReason)]
-> IO a
packageFlagErr (ExposePackage pkg) [] | is_dph_package pkg
= ghcError (CmdLineError (showSDoc $ dph_err))
where dph_err = text "the " <> text pkg <> text " package is not installed."
$$ text "To install it: \"cabal install dph\"."
is_dph_package pkg = "dph" `isPrefixOf` pkg
packageFlagErr flag reasons = ghcError (CmdLineError (showSDoc $ err))
where err = text "cannot satisfy " <> ppr_flag <>
(if null reasons then empty else text ": ") $$
nest 4 (ppr_reasons $$
text "(use -v for more information)")
ppr_flag = case flag of
IgnorePackage p -> text "-ignore-package " <> text p
HidePackage p -> text "-hide-package " <> text p
ExposePackage p -> text "-package " <> text p
ExposePackageId p -> text "-package-id " <> text p
TrustPackage p -> text "-trust " <> text p
DistrustPackage p -> text "-distrust " <> text p
ppr_reasons = vcat (map ppr_reason reasons)
ppr_reason (p, reason) = pprReason (pprIPkg p <+> text "is") reason
hideOldPackages :: DynFlags -> [PackageConfig] -> IO [PackageConfig]
hideOldPackages dflags pkgs = mapM maybe_hide pkgs
where maybe_hide p
| not (exposed p) = return p
| (p' : _) <- later_versions = do
debugTraceMsg dflags 2 $
(ptext (sLit "hiding package") <+> pprSPkg p <+>
ptext (sLit "to avoid conflict with later version") <+>
pprSPkg p')
return (p {exposed=False})
| otherwise = return p
where myname = pkgName (sourcePackageId p)
myversion = pkgVersion (sourcePackageId p)
later_versions = [ p | p <- pkgs, exposed p,
let pkg = sourcePackageId p,
pkgName pkg == myname,
pkgVersion pkg > myversion ]
findWiredInPackages
:: DynFlags
-> [PackageConfig]
-> IO [PackageConfig]
findWiredInPackages dflags pkgs = do
let
wired_in_pkgids :: [String]
wired_in_pkgids = map packageIdString
[ primPackageId,
integerPackageId,
basePackageId,
rtsPackageId,
thPackageId,
dphSeqPackageId,
dphParPackageId ]
matches :: PackageConfig -> String -> Bool
pc `matches` pid = display (pkgName (sourcePackageId pc)) == pid
findWiredInPackage :: [PackageConfig] -> String
-> IO (Maybe InstalledPackageId)
findWiredInPackage pkgs wired_pkg =
let all_ps = [ p | p <- pkgs, p `matches` wired_pkg ] in
case all_ps of
[] -> notfound
many -> pick (head (sortByVersion many))
where
notfound = do
debugTraceMsg dflags 2 $
ptext (sLit "wired-in package ")
<> text wired_pkg
<> ptext (sLit " not found.")
return Nothing
pick :: InstalledPackageInfo_ ModuleName
-> IO (Maybe InstalledPackageId)
pick pkg = do
debugTraceMsg dflags 2 $
ptext (sLit "wired-in package ")
<> text wired_pkg
<> ptext (sLit " mapped to ")
<> pprIPkg pkg
return (Just (installedPackageId pkg))
mb_wired_in_ids <- mapM (findWiredInPackage pkgs) wired_in_pkgids
let
wired_in_ids = catMaybes mb_wired_in_ids
updateWiredInDependencies pkgs = map upd_pkg pkgs
where upd_pkg p
| installedPackageId p `elem` wired_in_ids
= p { sourcePackageId = (sourcePackageId p){ pkgVersion = Version [] [] } }
| otherwise
= p
return $ updateWiredInDependencies pkgs
data UnusablePackageReason
= IgnoredWithFlag
| MissingDependencies [InstalledPackageId]
| ShadowedBy InstalledPackageId
type UnusablePackages = Map InstalledPackageId UnusablePackageReason
pprReason :: SDoc -> UnusablePackageReason -> SDoc
pprReason pref reason = case reason of
IgnoredWithFlag ->
pref <+> ptext (sLit "ignored due to an -ignore-package flag")
MissingDependencies deps ->
pref <+>
ptext (sLit "unusable due to missing or recursive dependencies:") $$
nest 2 (hsep (map (text.display) deps))
ShadowedBy ipid ->
pref <+> ptext (sLit "shadowed by package ") <> text (display ipid)
reportUnusable :: DynFlags -> UnusablePackages -> IO ()
reportUnusable dflags pkgs = mapM_ report (Map.toList pkgs)
where
report (ipid, reason) =
debugTraceMsg dflags 2 $
pprReason
(ptext (sLit "package") <+>
text (display ipid) <+> text "is") reason
findBroken :: [PackageConfig] -> UnusablePackages
findBroken pkgs = go [] Map.empty pkgs
where
go avail ipids not_avail =
case partitionWith (depsAvailable ipids) not_avail of
([], not_avail) ->
Map.fromList [ (installedPackageId p, MissingDependencies deps)
| (p,deps) <- not_avail ]
(new_avail, not_avail) ->
go (new_avail ++ avail) new_ipids (map fst not_avail)
where new_ipids = Map.insertList
[ (installedPackageId p, p) | p <- new_avail ]
ipids
depsAvailable :: InstalledPackageIndex
-> PackageConfig
-> Either PackageConfig (PackageConfig, [InstalledPackageId])
depsAvailable ipids pkg
| null dangling = Left pkg
| otherwise = Right (pkg, dangling)
where dangling = filter (not . (`Map.member` ipids)) (depends pkg)
shadowPackages :: [PackageConfig] -> [InstalledPackageId] -> UnusablePackages
shadowPackages pkgs preferred
= let (shadowed,_) = foldl check ([],emptyUFM) pkgs
in Map.fromList shadowed
where
check (shadowed,pkgmap) pkg
| Just oldpkg <- lookupUFM pkgmap (packageConfigId pkg)
, let
ipid_new = installedPackageId pkg
ipid_old = installedPackageId oldpkg
, ipid_old /= ipid_new
= if ipid_old `elem` preferred
then ( (ipid_new, ShadowedBy ipid_old) : shadowed, pkgmap )
else ( (ipid_old, ShadowedBy ipid_new) : shadowed, pkgmap' )
| otherwise
= (shadowed, pkgmap')
where
pkgmap' = addToUFM pkgmap (packageConfigId pkg) pkg
ignorePackages :: [PackageFlag] -> [PackageConfig] -> UnusablePackages
ignorePackages flags pkgs = Map.fromList (concatMap doit flags)
where
doit (IgnorePackage str) =
case partition (matchingStr str) pkgs of
(ps, _) -> [ (installedPackageId p, IgnoredWithFlag)
| p <- ps ]
doit _ = panic "ignorePackages"
depClosure :: InstalledPackageIndex
-> [InstalledPackageId]
-> [InstalledPackageId]
depClosure index ipids = closure Map.empty ipids
where
closure set [] = Map.keys set
closure set (ipid : ipids)
| ipid `Map.member` set = closure set ipids
| Just p <- Map.lookup ipid index = closure (Map.insert ipid p set)
(depends p ++ ipids)
| otherwise = closure set ipids
mkPackageState
:: DynFlags
-> [PackageConfig]
-> [PackageId]
-> PackageId
-> IO (PackageState,
[PackageId],
PackageId)
mkPackageState dflags pkgs0 preload0 this_package = do
let
flags = reverse (packageFlags dflags) ++ dphPackage
dphPackage = case dphBackend dflags of
DPHPar -> [ExposePackage "dph-prim-par", ExposePackage "dph-par"]
DPHSeq -> [ExposePackage "dph-prim-seq", ExposePackage "dph-seq"]
DPHThis -> []
DPHNone -> []
pkgs0_unique = snd $ foldr del (Set.empty,[]) pkgs0
where del p (s,ps)
| pid `Set.member` s = (s,ps)
| otherwise = (Set.insert pid s, p:ps)
where pid = installedPackageId p
ipid_map = Map.fromList [ (installedPackageId p, p) | p <- pkgs0 ]
ipid_selected = depClosure ipid_map [ InstalledPackageId i
| ExposePackageId i <- flags ]
(ignore_flags, other_flags) = partition is_ignore flags
is_ignore IgnorePackage{} = True
is_ignore _ = False
shadowed = shadowPackages pkgs0_unique ipid_selected
ignored = ignorePackages ignore_flags pkgs0_unique
pkgs0' = filter (not . (`Map.member` (Map.union shadowed ignored)) . installedPackageId) pkgs0_unique
broken = findBroken pkgs0'
unusable = shadowed `Map.union` ignored `Map.union` broken
reportUnusable dflags unusable
pkgs1 <- foldM (applyPackageFlag unusable) pkgs0_unique other_flags
let pkgs2 = filter (not . (`Map.member` unusable) . installedPackageId) pkgs1
let preload1 = [ installedPackageId p | f <- flags, p <- get_exposed f ]
get_exposed (ExposePackage s) = filter (matchingStr s) pkgs2
get_exposed (ExposePackageId s) = filter (matchingId s) pkgs2
get_exposed _ = []
pkgs3 <- hideOldPackages dflags pkgs2
pkgs4 <- findWiredInPackages dflags pkgs3
let pkg_db = extendPackageConfigMap emptyPackageConfigMap pkgs4
ipid_map = Map.fromList [ (installedPackageId p, packageConfigId p)
| p <- pkgs4 ]
lookupIPID ipid@(InstalledPackageId str)
| Just pid <- Map.lookup ipid ipid_map = return pid
| otherwise = missingPackageErr str
preload2 <- mapM lookupIPID preload1
let
basicLinkedPackages
| dopt Opt_AutoLinkPackages dflags
= filter (flip elemUFM pkg_db) [basePackageId, rtsPackageId]
| otherwise = []
preload3 = nub $ filter (/= this_package)
$ (basicLinkedPackages ++ preload2)
dep_preload <- closeDeps pkg_db ipid_map (zip preload3 (repeat Nothing))
let new_dep_preload = filter (`notElem` preload0) dep_preload
let pstate = PackageState{ preloadPackages = dep_preload,
pkgIdMap = pkg_db,
moduleToPkgConfAll = mkModuleMap pkg_db,
installedPackageIdMap = ipid_map
}
return (pstate, new_dep_preload, this_package)
mkModuleMap
:: PackageConfigMap
-> UniqFM [(PackageConfig, Bool)]
mkModuleMap pkg_db = foldr extend_modmap emptyUFM pkgids
where
pkgids = map packageConfigId (eltsUFM pkg_db)
extend_modmap pkgid modmap =
addListToUFM_C (++) modmap
([(m, [(pkg, True)]) | m <- exposed_mods] ++
[(m, [(pkg, False)]) | m <- hidden_mods])
where
pkg = expectJust "mkModuleMap" (lookupPackage pkg_db pkgid)
exposed_mods = exposedModules pkg
hidden_mods = hiddenModules pkg
pprSPkg :: PackageConfig -> SDoc
pprSPkg p = text (display (sourcePackageId p))
pprIPkg :: PackageConfig -> SDoc
pprIPkg p = text (display (installedPackageId p))
getPackageIncludePath :: DynFlags -> [PackageId] -> IO [String]
getPackageIncludePath dflags pkgs =
collectIncludeDirs `fmap` getPreloadPackagesAnd dflags pkgs
collectIncludeDirs :: [PackageConfig] -> [FilePath]
collectIncludeDirs ps = nub (filter notNull (concatMap includeDirs ps))
getPackageLibraryPath :: DynFlags -> [PackageId] -> IO [String]
getPackageLibraryPath dflags pkgs =
collectLibraryPaths `fmap` getPreloadPackagesAnd dflags pkgs
collectLibraryPaths :: [PackageConfig] -> [FilePath]
collectLibraryPaths ps = nub (filter notNull (concatMap libraryDirs ps))
getPackageLinkOpts :: DynFlags -> [PackageId] -> IO [String]
getPackageLinkOpts dflags pkgs =
collectLinkOpts dflags `fmap` getPreloadPackagesAnd dflags pkgs
collectLinkOpts :: DynFlags -> [PackageConfig] -> [String]
collectLinkOpts dflags ps = concat (map all_opts ps)
where
libs p = packageHsLibs dflags p ++ extraLibraries p
all_opts p = map ("-l" ++) (libs p) ++ ldOptions p
packageHsLibs :: DynFlags -> PackageConfig -> [String]
packageHsLibs dflags p = map (mkDynName . addSuffix) (hsLibraries p)
where
ways0 = ways dflags
ways1 = filter ((/= WayDyn) . wayName) ways0
ways2 | WayDebug `elem` map wayName ways1
= filter ((/= WayEventLog) . wayName) ways1
| otherwise
= ways1
tag = mkBuildTag (filter (not . wayRTSOnly) ways2)
rts_tag = mkBuildTag ways2
mkDynName | opt_Static = id
| otherwise = (++ ("-ghc" ++ cProjectVersion))
addSuffix rts@"HSrts" = rts ++ (expandTag rts_tag)
addSuffix other_lib = other_lib ++ (expandTag tag)
expandTag t | null t = ""
| otherwise = '_':t
getPackageExtraCcOpts :: DynFlags -> [PackageId] -> IO [String]
getPackageExtraCcOpts dflags pkgs = do
ps <- getPreloadPackagesAnd dflags pkgs
return (concatMap ccOptions ps)
getPackageFrameworkPath :: DynFlags -> [PackageId] -> IO [String]
getPackageFrameworkPath dflags pkgs = do
ps <- getPreloadPackagesAnd dflags pkgs
return (nub (filter notNull (concatMap frameworkDirs ps)))
getPackageFrameworks :: DynFlags -> [PackageId] -> IO [String]
getPackageFrameworks dflags pkgs = do
ps <- getPreloadPackagesAnd dflags pkgs
return (concatMap frameworks ps)
lookupModuleInAllPackages :: DynFlags -> ModuleName -> [(PackageConfig,Bool)]
lookupModuleInAllPackages dflags m
= case lookupModuleWithSuggestions dflags m of
Right pbs -> pbs
Left _ -> []
lookupModuleWithSuggestions
:: DynFlags -> ModuleName
-> Either [Module] [(PackageConfig,Bool)]
lookupModuleWithSuggestions dflags m
= case lookupUFM (moduleToPkgConfAll pkg_state) m of
Nothing -> Left suggestions
Just ps -> Right ps
where
pkg_state = pkgState dflags
suggestions
| dopt Opt_HelpfulErrors dflags = fuzzyLookup (moduleNameString m) all_mods
| otherwise = []
all_mods :: [(String, Module)]
all_mods = [ (moduleNameString mod_nm, mkModule pkg_id mod_nm)
| pkg_config <- eltsUFM (pkgIdMap pkg_state)
, let pkg_id = packageConfigId pkg_config
, mod_nm <- exposedModules pkg_config ]
getPreloadPackagesAnd :: DynFlags -> [PackageId] -> IO [PackageConfig]
getPreloadPackagesAnd dflags pkgids =
let
state = pkgState dflags
pkg_map = pkgIdMap state
ipid_map = installedPackageIdMap state
preload = preloadPackages state
pairs = zip pkgids (repeat Nothing)
in do
all_pkgs <- throwErr (foldM (add_package pkg_map ipid_map) preload pairs)
return (map (getPackageDetails state) all_pkgs)
closeDeps :: PackageConfigMap
-> Map InstalledPackageId PackageId
-> [(PackageId, Maybe PackageId)]
-> IO [PackageId]
closeDeps pkg_map ipid_map ps = throwErr (closeDepsErr pkg_map ipid_map ps)
throwErr :: MaybeErr Message a -> IO a
throwErr m = case m of
Failed e -> ghcError (CmdLineError (showSDoc e))
Succeeded r -> return r
closeDepsErr :: PackageConfigMap
-> Map InstalledPackageId PackageId
-> [(PackageId,Maybe PackageId)]
-> MaybeErr Message [PackageId]
closeDepsErr pkg_map ipid_map ps = foldM (add_package pkg_map ipid_map) [] ps
add_package :: PackageConfigMap
-> Map InstalledPackageId PackageId
-> [PackageId]
-> (PackageId,Maybe PackageId)
-> MaybeErr Message [PackageId]
add_package pkg_db ipid_map ps (p, mb_parent)
| p `elem` ps = return ps
| otherwise =
case lookupPackage pkg_db p of
Nothing -> Failed (missingPackageMsg (packageIdString p) <>
missingDependencyMsg mb_parent)
Just pkg -> do
ps' <- foldM add_package_ipid ps (depends pkg)
return (p : ps')
where
add_package_ipid ps ipid@(InstalledPackageId str)
| Just pid <- Map.lookup ipid ipid_map
= add_package pkg_db ipid_map ps (pid, Just p)
| otherwise
= Failed (missingPackageMsg str <> missingDependencyMsg mb_parent)
missingPackageErr :: String -> IO a
missingPackageErr p = ghcError (CmdLineError (showSDoc (missingPackageMsg p)))
missingPackageMsg :: String -> SDoc
missingPackageMsg p = ptext (sLit "unknown package:") <+> text p
missingDependencyMsg :: Maybe PackageId -> SDoc
missingDependencyMsg Nothing = empty
missingDependencyMsg (Just parent)
= space <> parens (ptext (sLit "dependency of") <+> ftext (packageIdFS parent))
isDllName :: PackageId -> Name -> Bool
isDllName this_pkg name
| opt_Static = False
| Just mod <- nameModule_maybe name = modulePackageId mod /= this_pkg
| otherwise = False
dumpPackages :: DynFlags -> IO ()
dumpPackages dflags
= do let pkg_map = pkgIdMap (pkgState dflags)
putMsg dflags $
vcat (map (text . showInstalledPackageInfo
. packageConfigToInstalledPackageInfo)
(eltsUFM pkg_map))
\end{code}