packages feed

ghc-make-0.3: src/Makefile.hs

{-# LANGUAGE RecordWildCards, PatternGuards, DeriveDataTypeable #-}

module Makefile(Makefile(..), Module(..), makefile) where

import Data.List
import Development.Shake.FilePath
import Development.Shake.Classes
import Development.Shake.Util
import Data.Bits
import qualified Data.HashMap.Strict as Map


data Module = Module {moduleName :: [String], moduleBoot :: Bool}
    deriving (Typeable, Eq)

instance Show Module where
    show (Module name boot) = intercalate "." name ++ (if boot then "[boot]" else "")

instance Hashable Module where
    hashWithSalt salt (Module a b) = hashWithSalt salt a `xor` hashWithSalt salt b

instance NFData Module where
    rnf (Module a b) = rnf (a,b)

instance Binary Module where
    put (Module a b) = put a >> put b
    get = do a <- get; b <- get; return $ Module a b

data Makefile = Makefile
    {imports :: !(Map.HashMap Module [Either FilePath Module]) -- What does a module import
    ,source :: !(Map.HashMap Module FilePath) -- Where is that modules source located
    }
    deriving Show


makefile :: FilePath -> IO Makefile
makefile file = fmap (foldl' f z . parseMakefile) $ readFile file
    where
        z = Makefile Map.empty Map.empty

        -- We rely on the order of the generated makefile, in particular
        -- * The Foo.o : Foo.hs line is always the first with Foo.o on the LHS
        -- * The root module (often Main.o) is always last
        f m (a,[b])
            | Just o <- fromExt "o" a, not $ Map.member o $ source m = m{source=Map.insert o b $ source m}
            | Just o <- fromExt "o" a, Just hi <- fromExt "hi" b = m{imports = Map.insertWith (++) o [Right hi] $ imports m}
            | Just o <- fromExt "o" a = m{imports = Map.insertWith (++) o [Left b] $ imports m}
            | otherwise = m
        f m (a,bs) = foldl' f m [(a,[b]) | b <- bs]


fromExt ext x
    | "-boot" `isSuffixOf` x, Just (Module m _) <- fromExt ext $ take (length x - 5) x = Just $ Module m True
    | takeExtension x == "." ++ ext, isRelative x = Just $ Module (splitDirectories $ dropExtension x) False
    | otherwise = Nothing