{-# OPTIONS_GHC -fglasgow-exts #-} -- -- Haddock - A Haskell Documentation Tool -- -- (c) Simon Marlow 2003 -- module Main (main) where import HaddockHtml import HaddockHoogle import HaddockRename import HaddockTypes import HaddockUtil import HaddockVersion import Paths_haddock ( getDataDir ) import Binary2 import Control.Exception ( bracket, throwIO, catch, Exception(..) ) import Prelude hiding ( catch ) import Control.Monad ( when, liftM ) import Control.Monad.Writer ( Writer, runWriter, tell ) import Data.Char ( isSpace ) import Data.IORef ( writeIORef ) import Data.List ( nub, (\\), foldl', sortBy, foldl1, init, mapAccumL, find ) import Data.Maybe ( isJust, isNothing, maybeToList, listToMaybe ) --import Debug.Trace import System.Console.GetOpt ( getOpt, usageInfo, ArgOrder(..), OptDescr(..), ArgDescr(..) ) import System.Environment ( getArgs ) import System.IO ( stderr, IOMode(..), openFile, hClose, hGetContents, hPutStrLn ) import System.Directory ( doesFileExist, doesDirectoryExist ) #if defined(mingw32_HOST_OS) import Foreign import Foreign.C #endif import qualified Data.Map as Map import Data.Map (Map) import Data.Maybe import Data.List ( nubBy ) import Data.FunctorM ( fmapM ) import qualified GHC ( init ) import GHC hiding ( init ) import Outputable import SrcLoc import qualified Digraph as Digraph import Name import Module ( mkModule ) import InstEnv import Class import TypeRep import Var hiding ( varName ) import TyCon import PrelNames import FastString #define FSLIT(x) (mkFastString# (x#)) import DynFlags hiding ( Option ) import StaticFlags ( parseStaticFlags ) import Unique ( mkUnique ) import Packages ----------------------------------------------------------------------------- -- Top-level stuff type CheckedMod = (Module, FullyCheckedMod, FilePath) main :: IO () main = do args <- getArgs (libDir, rest) <- getLibDir args let (isGHCMode, rest') = parseModeFlag rest (session, dynflags) <- startGHC libDir (dynflags', rest'') <- if isGHCMode then parseGHCFlags_GHCMode dynflags rest' else parseGHCFlags_HaddockMode dynflags rest' (flags, fileArgs) <- parseHaddockOpts rest'' mbPkgName <- handleEagerFlags flags let dynflags'' = case mbPkgName of Just name -> setPackageName name dynflags' Nothing -> dynflags' setSessionDynFlags session dynflags'' modules <- sortAndCheckModules session dynflags' fileArgs (ifaces, htmls) <- getIfacesAndHtmls flags dynflags' let (modss, envs) = unzip ifaces updateHTMLXRefs htmls modss -- TODO: continue to break up the run function into parts run flags modules envs parseModeFlag :: [String] -> (Bool, [String]) parseModeFlag ("--ghc-flags":rest) = (True, rest) parseModeFlag rest = (False, rest) parseGHCFlags_GHCMode :: DynFlags -> [String] -> IO (DynFlags, [String]) parseGHCFlags_GHCMode dynflags args = do (dynflags', rest) <- parseDynamicFlags dynflags args rest' <- parseStaticFlags rest return (dynflags', rest') parseGHCFlags_HaddockMode = parseGHCFlags parseGHCFlags :: DynFlags -> [String] -> IO (DynFlags, [String]) parseGHCFlags dynflags args = case args of [] -> return (dynflags, args) ("-g":rest) -> worker rest (('-':'-':'g':'h':'c':'-':'f':'l':'a':'g':[]):rest) -> worker rest (x:xs) -> do (flags, rest) <- parseGHCFlags dynflags xs return (flags, x:rest) where worker rest = do (mbFlags, rest') <- parseGHCFlag dynflags rest case mbFlags of Just flags -> parseGHCFlags flags rest' Nothing -> parseGHCFlags dynflags rest' parseGHCFlag :: DynFlags -> [String] -> IO (Maybe DynFlags, [String]) parseGHCFlag _ [] = die "No GHC flag supplied\n" parseGHCFlag dynflags args = do mbDyn <- findDynamic case mbDyn of Just (dynflags', rest) -> return (Just dynflags', rest) Nothing -> do mbStat <- findStatic case mbStat of Just (_, rest) -> return (Nothing, rest) Nothing -> die ("Not a GHC flag: " ++ (head args) ++ "\n") where findDynamic = findFlag ( \xs -> (do (fs, xs') <- parseDynamicFlags dynflags xs if xs' /= xs then return (Just fs) else return Nothing ) `catch` (\_ -> return Nothing) ) findStatic = findFlag (\xs -> do xs' <- parseStaticFlags xs if xs /= xs' then return (Just ()) else return Nothing) findFlag p = do xs <- (sequence . snd) (mapAccumL (f p) [] args) case [ (x, index) | Just x <- xs | index <- [1..] ] of ((x, index):_) -> return (Just (x, drop index args)) _ -> return Nothing f :: ([String] -> IO a) -> [String] -> String -> ([String], IO a) f parser previousArgs arg = let args' = previousArgs ++ [arg] in (args', parser args') parseHaddockOpts :: [String] -> IO ([Flag], [String]) parseHaddockOpts words = case getOpt Permute (options True) words of (flags, args, []) -> return (flags, args) (_, _, errors) -> do prog <- getProgramName die (concat errors ++ usageInfo (usageHeader prog) (options False)) usageHeader :: String -> String usageHeader prog = "Usage: " ++ prog ++ " [OPTION...] file...\n" getLibDir :: [String] -> IO (String, [String]) getLibDir ("-B":dir:rest) = return (dir, rest) getLibDir (('-':'B':dir):rest) | not (null dir) = return (dir, rest) getLibDir _ = die "Missing GHC lib dir option: -B