Follow extensible exception changes
[ghc-hetmet.git] / compiler / main / Packages.lhs
index d5cfbd1..1bafe6c 100644 (file)
@@ -4,13 +4,6 @@
 % Package manipulation
 %
 \begin{code}
-{-# OPTIONS -w #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and fix
--- any warnings in the module. See
---     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
--- for details
-
 module Packages (
        module PackageConfig,
 
@@ -26,7 +19,6 @@ module Packages (
 
        -- * Inspecting the set of packages in scope
        getPackageIncludePath,
-       getPackageCIncludes,
        getPackageLibraryPath,
        getPackageLinkOpts,
        getPackageExtraCcOpts,
@@ -34,6 +26,8 @@ module Packages (
        getPackageFrameworks,
        getPreloadPackagesAnd,
 
+        collectIncludeDirs, collectLibraryPaths, collectLinkOpts,
+
        -- * Utils
        isDllName
     )
@@ -54,13 +48,10 @@ import Maybes               ( expectJust, MaybeErr(..) )
 import Panic
 import Outputable
 
-#if __GLASGOW_HASKELL__ < 603
-import Compat.Directory        ( getAppUserDataDirectory )
-#endif
-
 import System.Environment ( getEnv )
-import Distribution.InstalledPackageInfo
-import Distribution.Package
+import Distribution.InstalledPackageInfo hiding (depends)
+import Distribution.Package hiding (depends)
+import Distribution.Text
 import Distribution.Version
 import FastString
 import ErrUtils         ( debugTraceMsg, putMsg, Message )
@@ -70,7 +61,6 @@ import System.FilePath
 import Data.Maybe
 import Control.Monad
 import Data.List
-import Control.Exception        ( throwDyn )
 
 -- ---------------------------------------------------------------------------
 -- The Package state
@@ -147,7 +137,7 @@ extendPackageConfigMap pkg_map new_pkgs
   where add pkg_map p = addToUFM pkg_map (packageConfigId p) p
 
 getPackageDetails :: PackageState -> PackageId -> PackageConfig
-getPackageDetails dflags ps = expectJust "getPackageDetails" (lookupPackage (pkgIdMap dflags) ps)
+getPackageDetails ps pid = expectJust "getPackageDetails" (lookupPackage (pkgIdMap ps) pid)
 
 -- ----------------------------------------------------------------------------
 -- Loading the package config files and building up the package state
@@ -243,7 +233,7 @@ readPackageConfig
    :: DynFlags -> PackageConfigMap -> FilePath -> IO PackageConfigMap
 readPackageConfig dflags pkg_map conf_file = do
   debugTraceMsg dflags 2 (text "Using package config file:" <+> text conf_file)
-  proto_pkg_configs <- loadPackageConfig conf_file
+  proto_pkg_configs <- loadPackageConfig dflags conf_file
   let top_dir = topDir dflags
       pkg_configs1 = mungePackagePaths top_dir proto_pkg_configs
       pkg_configs2 = maybeHidePackages dflags pkg_configs1
@@ -264,7 +254,10 @@ mungePackagePaths top_dir ps = map munge_pkg ps
   munge_pkg p = p{ importDirs  = munge_paths (importDirs p),
                   includeDirs = munge_paths (includeDirs p),
                   libraryDirs = munge_paths (libraryDirs p),
-                  frameworkDirs = munge_paths (frameworkDirs p) }
+                  frameworkDirs = munge_paths (frameworkDirs p),
+                   haddockInterfaces = munge_paths (haddockInterfaces p),
+                  haddockHTMLs = munge_paths (haddockHTMLs p)
+                    }
 
   munge_paths = map munge_path
 
@@ -290,6 +283,7 @@ applyPackageFlag pkgs flag =
         ExposePackage str ->
           case matchingPackages str pkgs of
                Nothing -> missingPackageErr str
+               Just ([], _) -> panic "applyPackageFlag"
                Just (p:ps,qs) -> return (p':ps')
                  where p' = p {exposed=True}
                        ps' = hideAll (pkgName (package p)) (ps++qs)
@@ -303,7 +297,7 @@ applyPackageFlag pkgs flag =
        IgnorePackage str ->
            case matchingPackages str pkgs of
                 Nothing -> return pkgs
-                Just (ps,qs) -> return qs
+                Just (_, qs) -> return qs
                -- missing package is not an error for -ignore-package,
                -- because a common usage is to -ignore-package P as
                -- a preventative measure just in case P exists.
@@ -325,14 +319,17 @@ matchingPackages str pkgs
         -- A package named on the command line can either include the
        -- version, or just the name if it is unambiguous.
        matches str p
-               =  str == showPackageId (package p)
-               || str == pkgName (package p)
-
+               =  str == display (package p)
+               || str == display (pkgName (package p))
 
+pickPackages :: [PackageConfig] -> [String] -> [PackageConfig]
 pickPackages pkgs strs = 
-  [ p | p <- strs, Just (p:ps,_) <- [matchingPackages p pkgs] ]
+  [ p | p <- strs, Just (p:_, _) <- [matchingPackages p pkgs] ]
 
+sortByVersion :: [InstalledPackageInfo_ m] -> [InstalledPackageInfo_ m]
 sortByVersion = sortBy (flip (comparing (pkgVersion.package)))
+
+comparing :: Ord a => (t -> a) -> t -> t -> Ordering
 comparing f a b = f a `compare` f b
 
 -- -----------------------------------------------------------------------------
@@ -350,10 +347,10 @@ hideOldPackages dflags pkgs = mapM maybe_hide pkgs
           | not (exposed p) = return p
           | (p' : _) <- later_versions = do
                debugTraceMsg dflags 2 $
-                  (ptext SLIT("hiding package") <+> 
-                    text (showPackageId (package p)) <+>
-                   ptext SLIT("to avoid conflict with later version") <+>
-                   text (showPackageId (package p')))
+                  (ptext (sLit "hiding package") <+> 
+                    text (display (package p)) <+>
+                   ptext (sLit "to avoid conflict with later version") <+>
+                   text (display (package p')))
                return (p {exposed=False})
           | otherwise = return p
          where myname = pkgName (package p)
@@ -381,13 +378,21 @@ findWiredInPackages dflags pkgs preload this_package = do
   -- their canonical names (eg. base-1.0 ==> base).
   --
   let
-       wired_in_pkgids = [ basePackageId,
-                           rtsPackageId,
-                           haskell98PackageId,
-                           thPackageId,
-                            ndpPackageId ]
-
-       wired_in_names = map packageIdString wired_in_pkgids
+        wired_in_pkgids :: [(PackageId, [String])]
+        wired_in_pkgids = [ (primPackageId, [""]),
+                            (integerPackageId, [""]),
+                            (basePackageId, [""]),
+                            (rtsPackageId, [""]),
+                            (haskell98PackageId, [""]),
+                            (thPackageId, [""]),
+                            (dphSeqPackageId, [""]),
+                            (dphParPackageId, [""]),
+                            (ndpPackageId, ["-seq", "-par"]) ]
+
+        matches :: PackageConfig -> (PackageId, [String]) -> Bool
+        pc `matches` (pid, suffixes)
+            = display (pkgName (package pc)) `elem`
+              (map (packageIdString pid ++) suffixes)
 
        -- find which package corresponds to each wired-in package
        -- delete any other packages with the same name
@@ -399,46 +404,53 @@ findWiredInPackages dflags pkgs preload this_package = do
         -- version.  To override the default choice, -hide-package
         -- could be used to hide newer versions.
         --
-       findWiredInPackage :: [PackageConfig] -> String
-                          -> IO (Maybe PackageIdentifier)
+       findWiredInPackage :: [PackageConfig] -> (PackageId, [String])
+                          -> IO (Maybe (PackageIdentifier, PackageId))
        findWiredInPackage pkgs wired_pkg =
-           let all_ps = [ p | p <- pkgs, pkgName (package p) == wired_pkg ] in
+           let all_ps = [ p | p <- pkgs, p `matches` wired_pkg ] in
           case filter exposed all_ps of
                [] -> case all_ps of
                         []   -> notfound
                         many -> pick (head (sortByVersion many))
                many  -> pick (head (sortByVersion many))
           where
+                suffixes = snd wired_pkg
                 notfound = do
                          debugTraceMsg dflags 2 $
-                           ptext SLIT("wired-in package ")
-                                <> text wired_pkg
-                                <> ptext SLIT(" not found.")
+                           ptext (sLit "wired-in package ")
+                                <> ppr (fst wired_pkg)
+                                 <> (if null suffixes
+                                     then empty
+                                     else text (show suffixes))
+                                <> ptext (sLit " not found.")
                          return Nothing
+               pick :: InstalledPackageInfo_ ModuleName
+                     -> IO (Maybe (PackageIdentifier, PackageId))
                 pick pkg = do
                         debugTraceMsg dflags 2 $
-                           ptext SLIT("wired-in package ")
-                                <> text wired_pkg
-                                <> ptext SLIT(" mapped to ")
-                                <> text (showPackageId (package pkg))
-                       return (Just (package pkg))
+                           ptext (sLit "wired-in package ")
+                                <> ppr (fst wired_pkg)
+                                <> ptext (sLit " mapped to ")
+                                <> text (display (package pkg))
+                       return (Just (package pkg, fst wired_pkg))
 
 
-  mb_wired_in_ids <- mapM (findWiredInPackage pkgs) wired_in_names
+  mb_wired_in_ids <- mapM (findWiredInPackage pkgs) wired_in_pkgids
   let 
         wired_in_ids = catMaybes mb_wired_in_ids
 
-       deleteOtherWiredInPackages pkgs = filter ok pkgs
-         where ok p = pkgName (package p) `notElem` wired_in_names
-                     || package p `elem` wired_in_ids
+       deleteOtherWiredInPackages pkgs = filterOut bad pkgs
+         where bad p = any (p `matches`) wired_in_pkgids
+                     && package p `notElem` map fst wired_in_ids
 
        updateWiredInDependencies pkgs = map upd_pkg pkgs
          where upd_pkg p = p{ package = upd_pid (package p),
                               depends = map upd_pid (depends p) }
 
-       upd_pid pid = case filter (== pid) wired_in_ids of
+       upd_pid pid = case filter ((== pid) . fst) wired_in_ids of
                                [] -> pid
-                               (x:_) -> x{ pkgVersion = Version [] [] }
+                               ((x, y):_) -> x{ pkgName = PackageName (packageIdString y),
+                                                 pkgVersion = Version [] [] }
 
         pkgs1 = deleteOtherWiredInPackages pkgs
 
@@ -453,10 +465,13 @@ findWiredInPackages dflags pkgs preload this_package = do
 
   return (pkgs2, preload1, new_this_pkg)
 
--- -----------------------------------------------------------------------------
+-- ----------------------------------------------------------------------------
 --
--- Eliminate any packages which have dangling dependencies (
--- because the dependency was removed by -ignore-package).
+-- Detect any packages that have missing dependencies, and also any
+-- mutually-recursive groups of packages (loops in the package graph
+-- are not allowed).  We do this by taking the least fixpoint of the
+-- dependency graph, repeatedly adding packages whose dependencies are
+-- satisfied until no more can be added.
 --
 elimDanglingDeps
    :: DynFlags
@@ -464,22 +479,28 @@ elimDanglingDeps
    -> [PackageId]       -- ignored packages
    -> IO [PackageConfig]
 
-elimDanglingDeps dflags pkgs ignored = 
-   case partition (not.null.snd) (map (getDanglingDeps pkgs ignored) pkgs) of
-        ([],ps) -> return (map fst ps)
-        (ps,qs) -> do
-            mapM_ reportElim ps
-            elimDanglingDeps dflags (map fst qs)
-                (ignored ++ map packageConfigId (map fst ps))
+elimDanglingDeps dflags pkgs ignored = go [] pkgs'
  where
+   pkgs' = filter (\p -> packageConfigId p `notElem` ignored) pkgs
+
+   go avail not_avail =
+     case partitionWith (depsAvailable avail) not_avail of
+        ([],        not_avail) -> do mapM_ reportElim not_avail; return avail
+        (new_avail, not_avail) -> go (new_avail ++ avail) (map fst not_avail)
+
+   depsAvailable :: [PackageConfig] -> PackageConfig
+                 -> Either PackageConfig (PackageConfig, [PackageIdentifier])
+   depsAvailable pkgs_ok pkg 
+        | null dangling = Left pkg
+        | otherwise     = Right (pkg, dangling)
+        where dangling = filter (`notElem` pids) (depends pkg)
+              pids = map package pkgs_ok
+
    reportElim (p, deps) = 
         debugTraceMsg dflags 2 $
-             (ptext SLIT("package") <+> pprPkg p <+> 
-                  ptext SLIT("will be ignored due to missing dependencies:") $$ 
-             nest 2 (hsep (map (text.showPackageId) deps)))
-
-   getDanglingDeps pkgs ignored p = (p, filter dangling (depends p))
-        where dangling pid = mkPackageId pid `elem` ignored
+             (ptext (sLit "package") <+> pprPkg p <+> 
+                  ptext (sLit "will be ignored due to missing or recursive dependencies:") $$ 
+             nest 2 (hsep (map (text.display) deps)))
 
 -- -----------------------------------------------------------------------------
 -- When all the command-line options are in, we can process our package
@@ -526,11 +547,12 @@ mkPackageState dflags orig_pkg_db preload0 this_package = do
   pkgs <- elimDanglingDeps dflags pkgs3 ignored
 
   let pkg_db = extendPackageConfigMap emptyPackageConfigMap pkgs
-      pkgids = map packageConfigId pkgs
 
       -- add base & rts to the preload packages
-      basicLinkedPackages = filter (flip elemUFM pkg_db)
-                                [basePackageId,rtsPackageId]
+      basicLinkedPackages
+       | dopt Opt_AutoLinkPackages dflags
+          = filter (flip elemUFM pkg_db) [basePackageId, rtsPackageId]
+       | otherwise = []
       -- but in any case remove the current package from the set of
       -- preloaded packages so that base/rts does not end up in the
       -- set up preloaded package when we are just building it
@@ -569,7 +591,7 @@ mkModuleMap pkg_db = foldr extend_modmap emptyUFM pkgids
                hidden_mods  = hiddenModules pkg
 
 pprPkg :: PackageConfig -> SDoc
-pprPkg p = text (showPackageId (package p))
+pprPkg p = text (display (package p))
 
 -- -----------------------------------------------------------------------------
 -- Extracting information from the packages in scope
@@ -583,26 +605,29 @@ pprPkg p = text (showPackageId (package p))
 -- use.
 
 getPackageIncludePath :: DynFlags -> [PackageId] -> IO [String]
-getPackageIncludePath dflags pkgs = do
-  ps <- getPreloadPackagesAnd dflags pkgs
-  return (nub (filter notNull (concatMap includeDirs ps)))
+getPackageIncludePath dflags pkgs =
+  collectIncludeDirs `fmap` getPreloadPackagesAnd dflags pkgs
 
-       -- includes are in reverse dependency order (i.e. rts first)
-getPackageCIncludes :: [PackageConfig] -> IO [String]
-getPackageCIncludes pkg_configs = do
-  return (reverse (nub (filter notNull (concatMap includes pkg_configs))))
+collectIncludeDirs :: [PackageConfig] -> [FilePath] 
+collectIncludeDirs ps = nub (filter notNull (concatMap includeDirs ps))
 
 getPackageLibraryPath :: DynFlags -> [PackageId] -> IO [String]
-getPackageLibraryPath dflags pkgs = do 
-  ps <- getPreloadPackagesAnd dflags pkgs
-  return (nub (filter notNull (concatMap libraryDirs ps)))
+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 = do
-  ps <- getPreloadPackagesAnd dflags pkgs
-  let tag = buildTag dflags
-      rts_tag = rtsBuildTag dflags
-  let 
+getPackageLinkOpts dflags pkgs = 
+  collectLinkOpts dflags `fmap` getPreloadPackagesAnd dflags pkgs
+
+collectLinkOpts :: DynFlags -> [PackageConfig] -> [String]
+collectLinkOpts dflags ps = concat (map all_opts ps)
+  where
+        tag = buildTag dflags
+        rts_tag = rtsBuildTag dflags
+
        mkDynName | opt_Static = id
                  | otherwise = (++ ("-ghc" ++ cProjectVersion))
        libs p     = map (mkDynName . addSuffix) (hsLibraries p)
@@ -615,8 +640,6 @@ getPackageLinkOpts dflags pkgs = do
         expandTag t | null t = ""
                    | otherwise = '_':t
 
-  return (concat (map all_opts ps))
-
 getPackageExtraCcOpts :: DynFlags -> [PackageId] -> IO [String]
 getPackageExtraCcOpts dflags pkgs = do
   ps <- getPreloadPackagesAnd dflags pkgs
@@ -663,7 +686,7 @@ closeDeps pkg_map ps = throwErr (closeDepsErr pkg_map ps)
 
 throwErr :: MaybeErr Message a -> IO a
 throwErr m = case m of
-               Failed e    -> throwDyn (CmdLineError (showSDoc e))
+               Failed e    -> ghcError (CmdLineError (showSDoc e))
                Succeeded r -> return r
 
 closeDepsErr :: PackageConfigMap -> [(PackageId,Maybe PackageId)]
@@ -685,12 +708,16 @@ add_package pkg_db ps (p, mb_parent)
           ps' <- foldM (add_package pkg_db) ps (zip deps (repeat (Just p)))
           return (p : ps')
 
-missingPackageErr p = throwDyn (CmdLineError (showSDoc (missingPackageMsg p)))
-missingPackageMsg p = ptext SLIT("unknown package:") <+> text p
+missingPackageErr :: String -> IO [PackageConfig]
+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))
+  = space <> parens (ptext (sLit "dependency of") <+> ftext (packageIdFS parent))
 
 -- -----------------------------------------------------------------------------
 
@@ -708,10 +735,7 @@ dumpPackages :: DynFlags -> IO ()
 dumpPackages dflags
   = do  let pkg_map = pkgIdMap (pkgState dflags)
        putMsg dflags $
-             vcat (map (text.showInstalledPackageInfo.to_ipi) (eltsUFM pkg_map))
- where
-  to_ipi pkgconf@InstalledPackageInfo_{ exposedModules = e,
-                                        hiddenModules = h } = 
-    pkgconf{ exposedModules = map moduleNameString e,
-             hiddenModules  = map moduleNameString h }
+              vcat (map (text . showInstalledPackageInfo
+                              . packageConfigToInstalledPackageInfo)
+                        (eltsUFM pkg_map))
 \end{code}