aboutsummaryrefslogtreecommitdiff
path: root/src/Haddock/GHC.hs
blob: 7856273e9322c74a79b4bb209a323b16314144a4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
--
-- Haddock - A Haskell Documentation Tool
--
-- (c) Simon Marlow 2003
--


module Haddock.GHC (
  startGhc,
  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
import SrcLoc


-- | Start a GHC session with the -haddock flag set. Also turn off 
-- compilation and linking.  
#if __GLASGOW_HASKELL__ >= 609 
startGhc :: String -> [String] -> (DynFlags -> Ghc a) -> IO a
startGhc libDir flags ghcActs = do
  -- TODO: handle warnings?
  (restFlags, _) <- parseStaticFlags (map noLoc flags)
  runGhc (Just libDir) $ do
    dynflags  <- getSessionDynFlags
#else
startGhc :: String -> [String] -> IO (Session, DynFlags)
startGhc libDir flags = do
  restFlags <- parseStaticFlags flags
  session <- newSession (Just libDir)
  dynflags <- getSessionDynFlags session
  do
#endif
    let dynflags' = dopt_set dynflags Opt_Haddock
    let dynflags'' = dynflags' {
        hscTarget = HscNothing,
        ghcMode   = CompManager,
        ghcLink   = NoLink
      }
    dynflags''' <- parseGhcFlags dynflags'' restFlags flags
    defaultCleanupHandler dynflags''' $ do
#if __GLASGOW_HASKELL__ >= 609
        setSessionDynFlags dynflags'''
        ghcActs dynflags'''
#else
        setSessionDynFlags session dynflags'''
        return (session, dynflags''')
#endif


-- | 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. 

-- Commented out, since it is unused and doesn't build with GHC >= 6.9
{-
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"
-}

-- | Try to parse dynamic GHC flags
parseGhcFlags dynflags flags origFlags = do
  -- TODO: handle warnings?
#if __GLASGOW_HASKELL__ >= 609
  (dynflags', rest, _) <- parseDynamicFlags dynflags flags
#else
  (dynflags', rest) <- parseDynamicFlags dynflags flags
#endif
  if not (null rest)
    then throwE ("Couldn't parse GHC options: " ++ (unwords origFlags))
    else return dynflags'