a4b1278660e689c57165cb2d2a3c6ab6436f3cf8
[ghc.git] / src / Rules / Compile.hs
1 module Rules.Compile (compilePackage) where
2
3 import Hadrian.Oracles.TextFile
4
5 import Base
6 import Context
7 import Expression
8 import Rules.Generate
9 import Target
10 import Utilities
11
12 compilePackage :: [(Resource, Int)] -> Context -> Rules ()
13 compilePackage rs context@Context {..} = do
14 let dir = "//" ++ contextDir context
15 nonHs extension = dir -/- extension <//> "*" <.> osuf way
16 compile compiler obj2src obj = do
17 src <- obj2src context obj
18 need [src]
19 needDependencies context src $ obj <.> "d"
20 buildWithResources rs $ target context (compiler stage) [src] [obj]
21 compileHs = \[obj, _hi] -> do
22 path <- buildPath context
23 (src, deps) <- lookupDependencies (path -/- ".dependencies") obj
24 need $ src : deps
25 when (isLibrary package) $ need =<< return <$> pkgConfFile context
26 needLibrary =<< contextDependencies context
27 buildWithResources rs $ target context (Ghc CompileHs stage) [src] [obj]
28
29 priority 2.0 $ do
30 nonHs "c" %> compile (Ghc CompileCWithGhc) (obj2src "c" isGeneratedCFile )
31 nonHs "cmm" %> compile (Ghc CompileHs) (obj2src "cmm" isGeneratedCmmFile)
32 nonHs "s" %> compile (Ghc CompileHs) (obj2src "S" $ const False )
33
34 -- TODO: Add dependencies for #include of .h and .hs-incl files (gcc -MM?).
35 [ dir <//> "*" <.> suf way | suf <- [ osuf, hisuf] ] &%> compileHs
36 [ dir <//> "*" <.> suf way | suf <- [obootsuf, hibootsuf] ] &%> compileHs
37
38 -- | Discover dependencies of a given source file by iteratively calling @gcc@
39 -- in the @-MM -MG@ mode and building generated dependencies if they are missing
40 -- until reaching a fixed point.
41 needDependencies :: Context -> FilePath -> FilePath -> Action ()
42 needDependencies context@Context {..} src depFile = discover
43 where
44 discover = do
45 build $ target context (Cc FindCDependencies stage) [src] [depFile]
46 deps <- parseFile depFile
47 -- Generated dependencies, if not yet built, will not be found and hence
48 -- will be referred to simply by their file names.
49 let notFound = filter (\file -> file == takeFileName file) deps
50 -- We find the full paths to generated dependencies, so we can request
51 -- to build them by calling 'need'.
52 todo <- catMaybes <$> mapM (fullPathIfGenerated context) notFound
53
54 if null todo
55 then need deps -- The list of dependencies is final, need all
56 else do
57 need todo -- Build newly discovered generated dependencies
58 discover -- Continue the discovery process
59
60 parseFile :: FilePath -> Action [String]
61 parseFile file = do
62 input <- liftIO $ readFile file
63 case parseMakefile input of
64 [(_file, deps)] -> return deps
65 _ -> return []
66
67 -- | Find a given 'FilePath' in the list of generated files in the given
68 -- 'Context' and return its full path.
69 fullPathIfGenerated :: Context -> FilePath -> Action (Maybe FilePath)
70 fullPathIfGenerated context file = interpretInContext context $ do
71 generated <- generatedDependencies
72 return $ find ((== file) . takeFileName) generated
73
74 obj2src :: String -> (FilePath -> Bool) -> Context -> FilePath -> Action FilePath
75 obj2src extension isGenerated context@Context {..} obj
76 | isGenerated src = return src
77 | otherwise = (pkgPath package ++) <$> suffix
78 where
79 src = obj -<.> extension
80 suffix = do
81 path <- buildPath context
82 return $ fromMaybe ("Cannot determine source for " ++ obj)
83 $ stripPrefix (path -/- extension) src