summaryrefslogtreecommitdiff
path: root/hadrian/src/Rules/Dependencies.hs
blob: 8b09a82b56642b0107a6d93039df82301041a99d (plain)
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
module Rules.Dependencies (buildPackageDependencies) where

import Data.Bifunctor
import Data.Function

import Base
import Context
import Expression
import Hadrian.BuildPath
import Oracles.ModuleFiles
import Rules.Generate
import Settings.Default
import Target
import Utilities

import qualified Text.Parsec as Parsec

buildPackageDependencies :: [(Resource, Int)] -> Rules ()
buildPackageDependencies rs = do
    root <- buildRootRules
    root -/- "**/.dependencies.mk" %> \mk -> do
        depfile <- getDepMkFile root mk
        context <- depMkFileContext depfile
        srcs <- hsSources context
        need srcs
        orderOnly =<< interpretInContext context generatedDependencies
        if null srcs
        then writeFileChanged mk ""
        else buildWithResources rs $
            target context
                   (Ghc FindHsDependencies $ Context.stage context)
                   srcs [mk]
        removeFile $ mk <.> "bak"

    root -/- "**/.dependencies" %> \deps -> do
        mkDeps <- readFile' (deps <.> "mk")
        writeFileChanged deps . unlines
                              . map (\(src, deps) -> unwords $ src : deps)
                              . map (bimap unifyPath (map unifyPath))
                              . map (bimap head concat . unzip)
                              . groupBy ((==) `on` fst)
                              . sortBy (compare `on` fst)
                              $ parseMakefile mkDeps


data DepMkFile = DepMkFile Stage FilePath
  deriving (Eq, Show)

parseDepMkFile :: FilePath -> Parsec.Parsec String () DepMkFile
parseDepMkFile root = do
  _ <- Parsec.string root *> Parsec.optional (Parsec.char '/')
  stage <- parseStage
  _ <- Parsec.char '/'
  pkgPath <- Parsec.manyTill Parsec.anyChar
    (Parsec.try $ Parsec.string "/.dependencies.mk")
  return (DepMkFile stage pkgPath)

getDepMkFile :: FilePath -> FilePath -> Action DepMkFile
getDepMkFile root = parsePath (parseDepMkFile root) "<dependencies file>"

depMkFileContext :: DepMkFile -> Action Context
depMkFileContext (DepMkFile stage pkgpath) = do
  pkg <- getPackageByPath pkgpath
  return (Context stage pkg vanilla)