Commit 9b705686 authored by Andrey Mokhov's avatar Andrey Mokhov

Major refactoring of path settings

* Move buildRoot into the Action monad, so it can be configured from command line in future

* Move settings from Setting.Path to Base and Context

* Simplify build rule matching and prepare to factoring out common build rules into the library, #347
parent d2ca01bb
......@@ -93,8 +93,6 @@ executable hadrian
, Settings.Packages.IntegerGmp
, Settings.Packages.Rts
, Settings.Packages.RunGhc
, Settings.Path
, Settings.Install
, Stage
, Target
, UserSettings
......
......@@ -20,7 +20,10 @@ module Base (
module Way,
-- * Paths
configPath, configFile, sourcePath, configH
hadrianPath, configPath, configFile, sourcePath, configH, shakeFilesDir,
bootPackageConstraints, packageDependencies, generatedDir, inplaceBinPath,
inplaceLibBinPath, inplaceLibPath, inplaceLibCopyTargets, templateHscPath,
stage0PackageDbDir, inplacePackageDbPath, packageDbStamp
) where
import Control.Applicative
......@@ -40,24 +43,85 @@ import Package
import Stage
import Way
-- | Hadrian lives in 'hadrianPath' directory of the GHC tree.
-- | Hadrian lives in the 'hadrianPath' directory of the GHC tree.
hadrianPath :: FilePath
hadrianPath = "hadrian"
-- TODO: Move this to build directory?
-- | Path to system configuration files, such as 'configFile'.
configPath :: FilePath
configPath = hadrianPath -/- "cfg"
-- | Path to the file with configuration settings.
-- | Path to the system configuration file generated by the @configure@ script.
configFile :: FilePath
configFile = configPath -/- "system.config"
-- | Path to source files of the build system, e.g. this file is located at
-- sourcePath -/- "Base.hs". We use this to `need` some of the source files.
-- @sourcePath -/- "Base.hs"@. We use this to track some of the source files.
sourcePath :: FilePath
sourcePath = hadrianPath -/- "src"
-- TODO: change @mk/config.h@ to @shake-build/cfg/config.h@
-- | Path to the generated @mk/config.h file.
-- TODO: Change @mk/config.h@ to @shake-build/cfg/config.h@.
-- | Path to the generated @mk/config.h@ file.
configH :: FilePath
configH = "mk/config.h"
-- | The directory in 'buildRoot' containing the Shake database and other
-- auxiliary files generated by Hadrian.
shakeFilesDir :: FilePath
shakeFilesDir = "hadrian"
-- | The file storing boot package versions extracted from @.cabal@ files. It
-- is generated by "Rules.Cabal".
bootPackageConstraints :: FilePath
bootPackageConstraints = shakeFilesDir -/- "boot-package-constraints"
-- | The file storing package dependencies extracted from @.cabal@ files. It
-- is generated by "Rules.Cabal".
packageDependencies :: FilePath
packageDependencies = shakeFilesDir -/- "package-dependencies"
-- | The directory in 'buildRoot' containing generated source files that are not
-- package-specific, e.g. @ghcplatform.h@.
generatedDir :: FilePath
generatedDir = "generated"
-- | The directory in 'buildRoot' containing the 'Stage0' package database.
stage0PackageDbDir :: FilePath
stage0PackageDbDir = "stage0/bootstrapping.conf"
-- | Path to the inplace package database used in 'Stage1' and later.
inplacePackageDbPath :: FilePath
inplacePackageDbPath = "inplace/lib/package.conf.d"
-- | We use a stamp file to track the existence of a package database.
packageDbStamp :: FilePath
packageDbStamp = ".stamp"
-- | Directory for binaries that are built "in place".
inplaceBinPath :: FilePath
inplaceBinPath = "inplace/bin"
-- | Directory for libraries that are built "in place".
inplaceLibPath :: FilePath
inplaceLibPath = "inplace/lib"
-- | Directory for binary wrappers, and auxiliary binaries such as @touchy@.
inplaceLibBinPath :: FilePath
inplaceLibBinPath = "inplace/lib/bin"
-- ref: ghc/ghc.mk:142
-- ref: driver/ghc.mk
-- ref: utils/hsc2hs/ghc.mk:35
-- | Files that need to be copied over to 'inplaceLibPath'.
inplaceLibCopyTargets :: [FilePath]
inplaceLibCopyTargets = map (inplaceLibPath -/-)
[ "ghc-usage.txt"
, "ghci-usage.txt"
, "platformConstants"
, "settings"
, "template-hsc.h" ]
-- | Path to hsc2hs template.
templateHscPath :: FilePath
templateHscPath = "inplace/lib/template-hsc.h"
module Context (
Context (..), vanillaContext, stageContext, getStage, getPackage, getWay,
getStagedSettingList
-- * Context
Context (..), vanillaContext, stageContext,
-- * Expressions
getStage, getPackage, getWay, getStagedSettingList, getBuildPath,
-- * Paths
contextDir, buildPath, pkgInplaceConfig, pkgDataFile, pkgSetupConfigFile,
pkgHaddockFile, pkgLibraryFile, pkgLibraryFile0, pkgGhciLibraryFile,
pkgConfFile, objectPath
) where
import GHC.Generics
import Hadrian.Expression
import Base
import Oracles.PackageData
import Oracles.Setting
-- | Build context for a currently built 'Target'. We generate potentially
......@@ -45,3 +54,91 @@ getWay = way <$> getContext
-- | Get a list of configuration settings for the current stage.
getStagedSettingList :: (Stage -> SettingList) -> Args Context b
getStagedSettingList f = getSettingList . f =<< getStage
-- | Get the build path of the current 'Context'.
getBuildPath :: Expr Context b FilePath
getBuildPath = expr . buildPath =<< getContext
-- | Path to the directory containing build artefacts of a given 'Context'.
buildPath :: Context -> Action FilePath
buildPath context = buildRoot <&> (-/- contextDir context)
-- | The directory in 'buildRoot' containing build artefacts of a given 'Context'.
contextDir :: Context -> FilePath
contextDir Context {..} = stageString stage -/- pkgPath package
pkgFile :: Context -> String -> String -> Action FilePath
pkgFile context prefix suffix = do
path <- buildPath context
componentId <- pkgData $ ComponentId path
return $ path -/- prefix ++ componentId ++ suffix
-- | Path to inplace package configuration file of a given 'Context'.
pkgInplaceConfig :: Context -> Action FilePath
pkgInplaceConfig context = do
path <- buildPath context
return $ path -/- "inplace-pkg-config"
-- | Path to the @package-data.mk@ of a given 'Context'.
pkgDataFile :: Context -> Action FilePath
pkgDataFile context = do
path <- buildPath context
return $ path -/- "package-data.mk"
-- | Path to the @setup-config@ of a given 'Context'.
pkgSetupConfigFile :: Context -> Action FilePath
pkgSetupConfigFile context = do
path <- buildPath context
return $ path -/- "setup-config"
-- | Path to the haddock file of a given 'Context', e.g.:
-- @_build/stage1/libraries/array/doc/html/array/array.haddock@.
pkgHaddockFile :: Context -> Action FilePath
pkgHaddockFile context@Context {..} = do
path <- buildPath context
let name = pkgNameString package
return $ path -/- "doc/html" -/- name -/- name <.> "haddock"
-- | Path to the library file of a given 'Context', e.g.:
-- @_build/stage1/libraries/array/build/libHSarray-0.5.1.0.a@.
pkgLibraryFile :: Context -> Action FilePath
pkgLibraryFile context@Context {..} = do
extension <- libsuf way
pkgFile context "libHS" extension
-- | Path to the auxiliary library file of a given 'Context', e.g.:
-- @_build/stage1/compiler/build/libHSghc-8.1-0.a@.
pkgLibraryFile0 :: Context -> Action FilePath
pkgLibraryFile0 context@Context {..} = do
extension <- libsuf way
pkgFile context "libHS" ("-0" ++ extension)
-- | Path to the GHCi library file of a given 'Context', e.g.:
-- @_build/stage1/libraries/array/build/HSarray-0.5.1.0.o@.
pkgGhciLibraryFile :: Context -> Action FilePath
pkgGhciLibraryFile context = pkgFile context "HS" ".o"
-- | Path to the configuration file of a given 'Context'.
pkgConfFile :: Context -> Action FilePath
pkgConfFile context@Context {..} = do
root <- buildRoot
path <- buildPath context
componentId <- pkgData $ ComponentId path
let dbDir | stage == Stage0 = root -/- stage0PackageDbDir
| otherwise = inplacePackageDbPath
return $ dbDir -/- componentId <.> "conf"
-- | Given a 'Context' and a 'FilePath' to a source file, compute the 'FilePath'
-- to its object file. For example:
-- * "Task.c" -> "_build/stage1/rts/Task.thr_o"
-- * "_build/stage1/rts/cmm/AutoApply.cmm" -> "_build/stage1/rts/cmm/AutoApply.o"
objectPath :: Context -> FilePath -> Action FilePath
objectPath context@Context {..} src = do
isGenerated <- isGeneratedSource src
path <- buildPath context
let extension = drop 1 $ takeExtension src
obj = src -<.> osuf way
result | isGenerated = obj
| "*hs*" ?== extension = path -/- obj
| otherwise = path -/- extension -/- obj
return result
......@@ -16,8 +16,8 @@ module Expression (
Context, vanillaContext, stageContext, Target,
-- * Convenient accessors
getContext, getStage, getPackage, getBuilder, getOutputs, getInputs, getWay,
getInput, getOutput,
getBuildRoot, getBuildPath, getContext, getStage, getPackage, getBuilder,
getOutputs, getInputs, getWay, getInput, getOutput,
-- * Re-exports
module Base
......@@ -27,7 +27,7 @@ import qualified Hadrian.Expression as H
import Hadrian.Expression hiding (Expr, Predicate, Args)
import Base
import Context (Context, vanillaContext, stageContext, getStage, getPackage, getWay)
import Context (Context, vanillaContext, stageContext, getBuildPath, getStage, getPackage, getWay)
import Target hiding (builder, inputs, outputs)
-- | @Expr a@ is a computation that produces a value of type @Action a@ and can
......
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
module GHC (
-- * GHC packages
array, base, binary, bytestring, cabal, checkApiAnnotations, compareSizes,
compiler, containers, deepseq, deriveConstants, directory, dllSplit, filepath,
genapply, genprimopcode, ghc, ghcBoot, ghcBootTh, ghcCabal, ghcCompact, ghci,
......@@ -8,14 +9,21 @@ module GHC (
hpc, hpcBin, integerGmp, integerSimple, iservBin, libffi, mkUserGuidePart,
parallel, pretty, primitive, process, rts, runGhc, stm, templateHaskell,
terminfo, time, touchy, transformers, unlit, unix, win32, xhtml,
defaultKnownPackages, builderProvenance, programName, nonCabalContext,
nonHsMainPackage
defaultKnownPackages,
-- * Package information
builderProvenance, programName, nonCabalContext, nonHsMainPackage, autogenPath,
-- * RTS library
rtsContext, rtsBuildPath, rtsConfIn,
-- * Miscellaneous
ghcSplitPath, stripCmdPath, inplaceInstallPath
) where
import Builder
import Base
import Context
import Package
import Stage
import Oracles.Setting
-- | These are all GHC packages we know about. Build rules will be generated for
-- all of them. However, not all of these packages will be built. For example,
......@@ -132,3 +140,55 @@ nonCabalContext Context {..} = (package `elem` [hp2ps, rts, touchy, unlit])
-- | Some program packages should not be linked with Haskell main function.
nonHsMainPackage :: Package -> Bool
nonHsMainPackage = (`elem` [ghc, hp2ps, iservBin, touchy, unlit])
-- | Path to the autogen directory generated by @ghc-cabal@ of a given 'Context'.
autogenPath :: Context -> Action FilePath
autogenPath context@Context {..}
| isLibrary package = autogen "build"
| package == ghc = autogen "build/ghc"
| package == hpcBin = autogen "build/hpc"
| package == iservBin = autogen "build/iserv"
| otherwise = autogen $ "build" -/- pkgNameString package
where
autogen dir = buildPath context <&> (-/- dir -/- "autogen")
-- | Given a 'Package', return the path where the corresponding program is
-- installed. Most programs are installed in 'programInplacePath'.
inplaceInstallPath :: Package -> FilePath
inplaceInstallPath pkg
| pkg == touchy = inplaceLibBinPath
| pkg == unlit = inplaceLibBinPath
| pkg == iservBin = inplaceLibBinPath
| otherwise = inplaceBinPath
-- | @ghc-split@ is a Perl script used by GHC with @-split-objs@ flag. It is
-- generated in "Rules.Generators.GhcSplit".
ghcSplitPath :: FilePath
ghcSplitPath = inplaceLibBinPath -/- "ghc-split"
-- ref: mk/config.mk
-- | Command line tool for stripping.
stripCmdPath :: Action FilePath
stripCmdPath = do
targetPlatform <- setting TargetPlatform
top <- topDirectory
case targetPlatform of
"x86_64-unknown-mingw32" ->
return (top -/- "inplace/mingw/bin/strip.exe")
"arm-unknown-linux" ->
return ":" -- HACK: from the make-based system, see the ref above
_ -> return "strip"
-- TODO: Move to RTS-specific package?
-- | RTS is considered a Stage1 package. This determines RTS build directory.
rtsContext :: Context
rtsContext = vanillaContext Stage1 rts
-- | Path to the RTS build directory.
rtsBuildPath :: Action FilePath
rtsBuildPath = buildPath rtsContext
-- | Path to RTS package configuration file, to be processed by HsCpp.
rtsConfIn :: FilePath
rtsConfIn = pkgPath rts -/- "package.conf.in"
......@@ -13,7 +13,7 @@ module Hadrian.Expression (
interpret, interpretInContext,
-- * Convenient accessors
getContext, getBuilder, getOutputs, getInputs, getInput, getOutput
getBuildRoot, getContext, getBuilder, getOutputs, getInputs, getInput, getOutput
) where
import Control.Monad.Extra
......@@ -95,6 +95,10 @@ interpretInContext c = interpret $ target c
(error "contextOnlyTarget: inputs not set" )
(error "contextOnlyTarget: outputs not set")
-- | Get the directory of build results.
getBuildRoot :: Expr c b FilePath
getBuildRoot = expr buildRoot
-- | Get the current build 'Context'.
getContext :: Expr c b c
getContext = Expr $ asks Target.context
......
......@@ -6,11 +6,14 @@ module Hadrian.Utilities (
quote, yesNo,
-- * FilePath manipulation
unifyPath, (-/-), matchVersionedFilePath,
unifyPath, (-/-),
-- * Accessing Shake's type-indexed map
insertExtra, userSetting,
-- * Paths
BuildRoot (..), buildRoot, isGeneratedSource,
-- * File system operations
copyFile, copyFileUntracked, fixFile, makeExecutable, moveFile, removeFile,
createDirectory, copyDirectory, moveDirectory, removeDirectory,
......@@ -21,12 +24,14 @@ module Hadrian.Utilities (
putProgressInfo, renderAction, renderProgram, renderLibrary, renderBox,
renderUnicorn,
-- * Miscellaneous
(<&>),
-- * Useful re-exports
Dynamic, fromDynamic, toDyn, TypeRep, typeOf
) where
import Control.Monad.Extra
import Data.Char
import Data.Dynamic (Dynamic, fromDynamic, toDyn)
import Data.HashMap.Strict (HashMap)
import Data.List.Extra
......@@ -111,25 +116,6 @@ a -/- b
infixr 6 -/-
-- | Given a @prefix@ and a @suffix@ check whether a 'FilePath' matches the
-- template @prefix ++ version ++ suffix@ where @version@ is an arbitrary string
-- comprising digits (@0-9@), dashes (@-@), and dots (@.@). Examples:
--
-- @
-- 'matchVersionedFilePath' "foo/bar" ".a" "foo/bar.a" '==' 'True'
-- 'matchVersionedFilePath' "foo/bar" ".a" "foo\bar.a" '==' 'False'
-- 'matchVersionedFilePath' "foo/bar" "a" "foo/bar.a" '==' 'True'
-- 'matchVersionedFilePath' "foo/bar" "" "foo/bar.a" '==' 'False'
-- 'matchVersionedFilePath' "foo/bar" "a" "foo/bar-0.1.a" '==' 'True'
-- 'matchVersionedFilePath' "foo/bar-" "a" "foo/bar-0.1.a" '==' 'True'
-- 'matchVersionedFilePath' "foo/bar/" "a" "foo/bar-0.1.a" '==' 'False'
-- @
matchVersionedFilePath :: String -> String -> FilePath -> Bool
matchVersionedFilePath prefix suffix filePath =
case stripPrefix prefix filePath >>= stripSuffix suffix of
Nothing -> False
Just version -> all (\c -> isDigit c || c == '-' || c == '.') version
-- | Insert a value into Shake's type-indexed map.
insertExtra :: Typeable a => a -> HashMap TypeRep Dynamic -> HashMap TypeRep Dynamic
insertExtra value = Map.insert (typeOf value) (toDyn value)
......@@ -142,6 +128,32 @@ userSetting defaultValue = do
let maybeValue = fromDynamic =<< Map.lookup (typeOf defaultValue) extra
return $ fromMaybe defaultValue maybeValue
newtype BuildRoot = BuildRoot FilePath deriving Typeable
-- | All build results are put into the 'buildRoot' directory.
buildRoot :: Action FilePath
buildRoot = do
BuildRoot path <- userSetting (BuildRoot "")
return path
-- | A version of 'fmap' with flipped arguments. Useful for manipulating values
-- in context, e.g. 'buildRoot', as in the example below.
--
-- @
-- buildRoot <&> (-/- "dir") == fmap (-/- "dir") buildRoot
-- @
(<&>) :: Functor f => f a -> (a -> b) -> f b
(<&>) = flip fmap
infixl 1 <&>
-- | Given a 'FilePath' to a source file, return 'True' if it is generated.
-- The current implementation simply assumes that a file is generated if it
-- lives in the 'buildRoot' directory. Since most files are not generated the
-- test is usually very fast.
isGeneratedSource :: FilePath -> Action Bool
isGeneratedSource file = buildRoot <&> (`isPrefixOf` file)
-- | Copy a file tracking the source. Create the target directory if missing.
copyFile :: FilePath -> FilePath -> Action ()
copyFile source target = do
......@@ -162,7 +174,7 @@ copyFileUntracked source target = do
-- | Transform a given file by applying a function to its contents.
fixFile :: FilePath -> (String -> String) -> Action ()
fixFile file f = do
putBuild $ "| Fix " ++ file
putProgressInfo $ "| Fix " ++ file
contents <- liftIO $ IO.withFile file IO.ReadMode $ \h -> do
old <- IO.hGetContents h
let new = f old
......@@ -173,7 +185,7 @@ fixFile file f = do
-- | Make a given file executable by running the @chmod +x@ command.
makeExecutable :: FilePath -> Action ()
makeExecutable file = do
putBuild $ "| Make " ++ quote file ++ " executable."
putProgressInfo $ "| Make " ++ quote file ++ " executable."
quietly $ cmd "chmod +x " [file]
-- | Move a file. Note that we cannot track the source, because it is moved.
......@@ -185,13 +197,13 @@ moveFile source target = do
-- | Remove a file that doesn't necessarily exist.
removeFile :: FilePath -> Action ()
removeFile file = do
putBuild $ "| Remove file " ++ file
putProgressInfo $ "| Remove file " ++ file
liftIO . whenM (IO.doesFileExist file) $ IO.removeFile file
-- | Create a directory if it does not already exist.
createDirectory :: FilePath -> Action ()
createDirectory dir = do
putBuild $ "| Create directory " ++ dir
putProgressInfo $ "| Create directory " ++ dir
liftIO $ IO.createDirectoryIfMissing True dir
-- | Copy a directory. The contents of the source directory is untracked.
......@@ -209,7 +221,7 @@ moveDirectory source target = do
-- | Remove a directory that doesn't necessarily exist.
removeDirectory :: FilePath -> Action ()
removeDirectory dir = do
putBuild $ "| Remove directory " ++ dir
putProgressInfo $ "| Remove directory " ++ dir
liftIO . whenM (IO.doesDirectoryExist dir) $ IO.removeDirectoryRecursive dir
data UseColour = Never | Auto | Always deriving (Eq, Show, Typeable)
......
......@@ -3,6 +3,7 @@ module Main (main) where
import Development.Shake
import Hadrian.Utilities
import qualified Base
import qualified CommandLine
import qualified Environment
import qualified Rules
......@@ -11,7 +12,6 @@ import qualified Rules.Install
import qualified Rules.SourceDist
import qualified Rules.Selftest
import qualified Rules.Test
import qualified Settings.Path
import qualified UserSettings
main :: IO ()
......@@ -20,12 +20,15 @@ main = do
-- Shake's type-indexed map 'shakeExtra'.
argsMap <- CommandLine.cmdLineArgsMap
let extra = insertExtra UserSettings.buildProgressColour
$ insertExtra UserSettings.successColour argsMap
$ insertExtra UserSettings.successColour
$ insertExtra UserSettings.userBuildRoot argsMap
BuildRoot buildRoot = UserSettings.userBuildRoot
options :: ShakeOptions
options = shakeOptions
{ shakeChange = ChangeModtimeAndDigest
, shakeFiles = Settings.Path.shakeFilesPath
, shakeFiles = buildRoot -/- Base.shakeFilesDir
, shakeProgress = progressSimple
, shakeTimings = True
, shakeExtra = extra }
......
......@@ -6,8 +6,8 @@ import qualified Data.HashMap.Strict as Map
import Base
import Context
import GHC
import Oracles.PackageData
import Settings.Path
newtype ModuleFiles = ModuleFiles (Stage, Package)
deriving (Binary, Eq, Hashable, NFData, Show, Typeable)
......@@ -75,22 +75,25 @@ hsSources :: Context -> Action [FilePath]
hsSources context = do
let modFile (m, Nothing ) = generatedFile context m
modFile (m, Just file )
| takeExtension file `elem` haskellExtensions = file
| takeExtension file `elem` haskellExtensions = return file
| otherwise = generatedFile context m
map modFile <$> contextFiles context
mapM modFile =<< contextFiles context
-- | Find all Haskell object files for a given 'Context'. Note: this is a much
-- simpler function compared to 'hsSources', because all object files live in
-- the build directory regardless of whether they are generated or not.
hsObjects :: Context -> Action [FilePath]
hsObjects context = do
modules <- pkgDataList $ Modules (buildPath context)
path <- buildPath context
modules <- pkgDataList (Modules path)
-- GHC.Prim module is only for documentation, we do not actually build it.
return . map (objectPath context . moduleSource) $ filter (/= "GHC.Prim") modules
mapM (objectPath context . moduleSource) (filter (/= "GHC.Prim") modules)
-- | Generated module files live in the 'Context' specific build directory.
generatedFile :: Context -> String -> FilePath
generatedFile context moduleName = buildPath context -/- moduleSource moduleName
generatedFile :: Context -> String -> Action FilePath
generatedFile context moduleName = do
path <- buildPath context
return $ path -/- moduleSource moduleName
moduleSource :: String -> FilePath
moduleSource moduleName = replaceEq '.' '/' moduleName <.> "hs"
......@@ -98,7 +101,8 @@ moduleSource moduleName = replaceEq '.' '/' moduleName <.> "hs"
-- | Module files for a given 'Context'.
contextFiles :: Context -> Action [(String, Maybe FilePath)]
contextFiles context@Context {..} = do
modules <- fmap sort . pkgDataList . Modules $ buildPath context
path <- buildPath context
modules <- fmap sort . pkgDataList $ Modules path
zip modules <$> askOracle (ModuleFiles (stage, package))
-- | This is an important oracle whose role is to find and cache module source
......@@ -116,10 +120,11 @@ moduleFilesOracle :: Rules ()
moduleFilesOracle = void $ do
void . addOracle $ \(ModuleFiles (stage, package)) -> do
let context = vanillaContext stage package
path = buildPath context
path <- buildPath context
srcDirs <- pkgDataList $ SrcDirs path
modules <- fmap sort . pkgDataList $ Modules path
let dirs = autogenPath context : map (pkgPath package -/-) srcDirs
autogen <- autogenPath context
let dirs = autogen : map (pkgPath package -/-) srcDirs
modDirFiles = groupSort $ map decodeModule modules
result <- concatForM dirs $ \dir -> do
todo <- filterM (doesDirectoryExist . (dir -/-) . fst) modDirFiles
......@@ -142,9 +147,10 @@ moduleFilesOracle = void $ do
generators <- newCache $ \(stage, package) -> do
let context = vanillaContext stage package
files <- contextFiles context
return $ Map.fromList [ (generatedFile context modName, src)
| (modName, Just src) <- files
, takeExtension src `notElem` haskellExtensions ]
list <- sequence [ (,src) <$> (generatedFile context modName)
| (modName, Just src) <- files
, takeExtension src `notElem` haskellExtensions ]
return $ Map.fromList list
addOracle $ \(Generator (stage, package, file)) ->
Map.lookup file <$> generators (stage, package)
......@@ -24,7 +24,6 @@ import qualified Rules.Perl
import qualified Rules.Program
import qualified Rules.Register
import Settings
import Settings.Path
import Target
import Utilities
......@@ -55,12 +54,14 @@ packageTargets stage pkg = do
then return [] -- Skip inactive packages.
else if isLibrary pkg