diff options
Diffstat (limited to 'src/Haddock/GHC.hs')
-rw-r--r-- | src/Haddock/GHC.hs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/Haddock/GHC.hs b/src/Haddock/GHC.hs new file mode 100644 index 00000000..b4b9dd3f --- /dev/null +++ b/src/Haddock/GHC.hs @@ -0,0 +1,108 @@ +-- +-- Haddock - A Haskell Documentation Tool +-- +-- (c) Simon Marlow 2003 +-- + + +module Haddock.GHC ( + startGhc, + loadPackages, + tryParseStaticFlags, + parseGhcFlags, + module Haddock.GHC.Typecheck, + module Haddock.GHC.Utils +) where + + +import Haddock.GHC.Typecheck +import Haddock.GHC.Utils +import Haddock.Exception +import Haddock.Options + +import Data.Foldable (foldlM) +import Data.Maybe +import Control.Monad + +import GHC +import DynFlags hiding (Option) +import Packages hiding (package) +import StaticFlags + + +-- | Start a GHC session with the -haddock flag set. Also turn off +-- compilation and linking. +startGhc :: String -> IO (Session, DynFlags) +startGhc libDir = do + session <- newSession (Just libDir) + flags <- getSessionDynFlags session + let flags' = dopt_set flags Opt_Haddock + let flags'' = flags' { + hscTarget = HscNothing, + ghcMode = CompManager, + ghcLink = NoLink + } + setSessionDynFlags session flags'' + return (session, flags'') + + +-- | Expose the list of packages to GHC. Then initialize GHC's package state +-- and get the name of the actually loaded packages matching the supplied +-- list of packages. The matching packages might be newer versions of the +-- supplied ones. For each matching package, return its InstalledPackageInfo. + +loadPackages :: Session -> [String] -> IO [InstalledPackageInfo] + +-- It would be better to try to get the "in scope" packages from GHC instead. +-- This would make the -use-package flag unnecessary. But currently it +-- seems all you can get from the GHC api is all packages that are linked in +-- (i.e the closure of the "in scope" packages). + +loadPackages session pkgStrs = do + + -- expose the packages + + dfs <- getSessionDynFlags session + let dfs' = dfs { packageFlags = packageFlags dfs ++ map ExposePackage pkgStrs } + setSessionDynFlags session dfs' + + -- try to parse the packages and get their names, without versions + pkgNames <- mapM (handleParse . unpackPackageId . stringToPackageId) pkgStrs + + -- init GHC's package state + (dfs'', depPackages) <- initPackages dfs' + + -- compute the pkgIds of the loaded packages matching the + -- supplied ones + + let depPkgs = map (fromJust . unpackPackageId) depPackages + matchingPackages = [ mkPackageId pkg | pkg <- depPkgs, + pkgName pkg `elem` pkgNames ] + + -- get InstalledPackageInfos for each package + let pkgInfos = map (getPackageDetails (pkgState dfs'')) matchingPackages + + return pkgInfos + where + handleParse (Just pkg) = return (pkgName pkg) + handleParse Nothing = throwE "Could not parse package identifier" + + +-- | Filter out the GHC specific flags and try to parse and set them as static +-- flags. Return a list of flags that couldn't be parsed. +tryParseStaticFlags flags = do + let ghcFlags = [ str | Flag_GhcFlag str <- flags ] + parseStaticFlags ghcFlags + + +-- | Try to parse dynamic GHC flags +parseGhcFlags session ghcFlags = do + dflags <- getSessionDynFlags session + foldlM parseFlag dflags (map words ghcFlags) + where + -- try to parse a flag as either a dynamic or static GHC flag + parseFlag dynflags ghcFlag = do + (dynflags', rest) <- parseDynamicFlags dynflags ghcFlag + when (rest == ghcFlag) $ + throwE ("Couldn't parse GHC flag: " ++ (unwords ghcFlag)) + return dynflags' |