module Main (main) where import Control.Monad import Data.Function import Data.List import Data.Map (Map) import qualified Data.Map as Map import Data.Maybe import Data.Set (Set) import qualified Data.Set as Set import System.Environment import System.Exit import System.FilePath main :: IO () main = do args <- getArgs case args of [depfile, startModule, reachableModules] -> doit depfile (Module startModule) (Set.fromList $ map Module $ words reachableModules) _ -> error "dll-split: Bad args" doit :: FilePath -> Module -> Set Module -> IO () doit depfile startModule expectedReachableMods = do xs <- readFile depfile let ys = catMaybes $ map mkEdge $ lines xs mapping = mkMap ys actualReachableMods = reachable mapping startModule unless (actualReachableMods == expectedReachableMods) $ do let extra = actualReachableMods Set.\\ expectedReachableMods redundant = expectedReachableMods Set.\\ actualReachableMods tellSet name set = unless (Set.null set) $ let ms = map moduleName (Set.toList set) in putStrLn (name ++ ": " ++ unwords ms) putStrLn ("Reachable modules from " ++ moduleName startModule ++ " out of date") putStrLn "Please fix compiler/ghc.mk, or building DLLs on Windows may break (#7780)" tellSet "Redundant modules" redundant tellSet "Extra modules" extra exitFailure newtype Module = Module String deriving (Eq, Ord) moduleName :: Module -> String moduleName (Module name) = name -- Given: -- compiler/stage2/build/X86/Regs.o : compiler/stage2/build/CodeGen/Platform.hi -- Produce: -- Just ("X86.Regs", "CodeGen.Platform") mkEdge :: String -> Maybe (Module, Module) mkEdge str = case words str of [from, ":", to] | Just from' <- getModule from , Just to' <- getModule to -> Just (from', to') _ -> Nothing where getModule xs = case stripPrefix "compiler/stage2/build/" xs of Just xs' -> let name = filePathToModuleName $ dropExtension xs' in Just $ Module name Nothing -> Nothing filePathToModuleName = map filePathToModuleNameChar filePathToModuleNameChar '/' = '.' filePathToModuleNameChar c = c mkMap :: [(Module, Module)] -> (Map Module (Set Module)) mkMap edges = let groupedEdges = groupBy ((==) `on` fst) $ sort edges mkEdgeMap ys = (fst (head ys), Set.fromList (map snd ys)) in Map.fromList $ map mkEdgeMap groupedEdges reachable :: Map Module (Set Module) -> Module -> Set Module reachable mapping startModule = f Set.empty startModule where f done m = if m `Set.member` done then done else foldl' f (m `Set.insert` done) (get m) get m = Set.toList (Map.findWithDefault Set.empty m mapping)