-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Build system library, like Make, but more accurate dependencies. -- -- Shake is a Haskell library for writing build systems - designed as a -- replacement for make. See Development.Shake for an -- introduction, including an example. Further examples are included in -- the Cabal tarball, under the Examples directory. -- -- To use Shake the user writes a Haskell program that imports the Shake -- library, defines some build rules, and calls shake. Thanks to -- do notation and infix operators, a simple Shake program is not too -- dissimilar from a simple Makefile. However, as build systems get more -- complex, Shake is able to take advantage of the excellent abstraction -- facilities offered by Haskell and easily support much larger projects. -- -- The Shake library provides all the standard features available in -- other build systems, including automatic parallelism and minimal -- rebuilds. Shake provides highly accurate dependency tracking, -- including seamless support for generated files, and dependencies on -- system information (i.e. compiler version). Shake can produce profile -- reports, indicating which files and take longest to build, and -- providing an analysis of the parallelism. -- -- The theory behind Shake is described in an ICFP 2012 paper, Shake -- Before Building -- Replacing Make with Haskell -- http://community.haskell.org/~ndm/downloads/paper-shake_before_building-10_sep_2012.pdf. -- The associated talk forms a short overview of Shake -- http://www.youtube.com/watch?v=xYCPpXVlqFM. @package shake @version 0.7 -- | A module for FilePath operations, to be used instead of -- System.FilePath when writing build systems. In build systems, -- when using the file name as a key for indexing rules, it is important -- that two different strings do not refer to the same on-disk file. We -- therefore follow the conventions: -- --
-- dropDirectory1 "aaa/bbb" == "bbb" -- dropDirectory1 "aaa/" == "" -- dropDirectory1 "aaa" == "" -- dropDirectory1 "" == "" --dropDirectory1 :: FilePath -> FilePath -- | Take the first component of a FilePath. Should only be used on -- relative paths. -- --
-- takeDirectory1 "aaa/bbb" == "aaa" -- takeDirectory1 "aaa/" == "aaa" -- takeDirectory1 "aaa" == "aaa" --takeDirectory1 :: FilePath -> FilePath -- | Normalise a FilePath, applying the standard FilePath -- normalisation, plus translating any path separators to / and -- removing foo/.. components where possible. normalise :: FilePath -> FilePath -- | Convert to native path separators, namely \ on Windows. toNative :: FilePath -> FilePath -- | Combine two file paths, an alias for combine. (>) :: FilePath -> FilePath -> FilePath -- | Combine two file paths. Any leading ./ or ../ -- components in the right file are eliminated. -- --
-- combine "aaa/bbb" "ccc" == "aaa/bbb/ccc" -- combine "aaa/bbb" "./ccc" == "aaa/bbb/ccc" -- combine "aaa/bbb" "../ccc" == "aaa/ccc" --combine :: FilePath -> FilePath -> FilePath -- | This module reexports the six necessary type classes that every -- Rule type must support. You can use this module to define new -- rules without depending on the binary, deepseq and -- hashable packages. module Development.Shake.Classes -- | Conversion of values to readable Strings. -- -- Minimal complete definition: showsPrec or show. -- -- Derived instances of Show have the following properties, which -- are compatible with derived instances of Read: -- --
-- infixr 5 :^: -- data Tree a = Leaf a | Tree a :^: Tree a ---- -- the derived instance of Show is equivalent to -- --
-- instance (Show a) => Show (Tree a) where -- -- showsPrec d (Leaf m) = showParen (d > app_prec) $ -- showString "Leaf " . showsPrec (app_prec+1) m -- where app_prec = 10 -- -- showsPrec d (u :^: v) = showParen (d > up_prec) $ -- showsPrec (up_prec+1) u . -- showString " :^: " . -- showsPrec (up_prec+1) v -- where up_prec = 5 ---- -- Note that right-associativity of :^: is ignored. For example, -- --
-- decode . encode == id ---- -- That is, the get and put methods should be the inverse -- of each other. A range of instances are provided for basic Haskell -- types. class Binary t put :: Binary t => t -> Put get :: Binary t => Get t -- | A class of types that can be fully evaluated. class NFData a rnf :: NFData a => a -> () -- | This module is used for defining Shake build systems. As a simple -- example of a Shake build system, let us build the file -- result.tar from the files listed by result.txt: -- --
-- import Development.Shake -- import Development.Shake.FilePath -- -- main = shake shakeOptions $ do -- want ["result.tar"] -- "*.tar" *> \out -> do -- contents <- readFileLines $ replaceExtension out "txt" -- need contents -- system' "tar" $ ["-cf",out] ++ contents ---- -- We start by importing the modules defining both Shake and routines for -- manipulating FilePath values. We define main to call -- shake with the default shakeOptions. As the second -- argument to shake, we provide a set of rules. There are two -- common forms of rules, want to specify target files, and -- *> to define a rule which builds a FilePattern. We -- use want to require that after the build completes the file -- result.tar should be ready. -- -- The *.tar rule describes how to build files with the -- extension .tar, including result.tar. We -- readFileLines on result.txt, after changing the -- .tar extension to .txt. We read each line into the -- variable contents -- being a list of the files that should go -- into result.tar. Next, we depend (need) all the files -- in contents. If any of these files change, the rule will be -- repeated. Finally we call the tar program. If either -- result.txt changes, or any of the files listed by -- result.txt change, then result.tar will be rebuilt. -- -- When writing a Shake build system, start by defining what you -- want, then write rules with *> to produce the -- results. Before calling system' you should ensure that any -- files the command requires are demanded with calls to need. We -- offer the following advice to Shake users: -- --
-- newtype MyType = MyType (String, Bool) deriving (Show,Typeable,Eq,Hashable,Binary,NFData) --type ShakeValue a = (Show a, Typeable a, Eq a, Hashable a, Binary a, NFData a) -- | Define a pair of types that can be used by Shake rules. To import all -- the type classes required see Development.Shake.Classes. class (ShakeValue key, ShakeValue value) => Rule key value | key -> value storedValue :: Rule key value => key -> IO (Maybe value) -- | Define a set of rules. Rules can be created with calls to rule, -- defaultRule or action. Rules are combined with either -- the Monoid instance, or (more commonly) the Monad -- instance and do notation. data Rules a -- | Like rule, but lower priority, if no rule exists then -- defaultRule is checked. All default rules must be disjoint. defaultRule :: Rule key value => (key -> Maybe (Action value)) -> Rules () -- | Add a rule to build a key, returning an appropriate Action. All -- rules must be disjoint. To define lower priority rules use -- defaultRule. rule :: Rule key value => (key -> Maybe (Action value)) -> Rules () -- | Run an action, usually used for specifying top-level requirements. action :: Action a -> Rules () -- | Remove all actions specified in a set of rules, usually used for -- implementing command line specification of what to build. withoutActions :: Rules () -> Rules () -- | The Action monad, use liftIO to raise IO actions -- into it, and need to execute files. Action values are used by -- rule and action. data Action a -- | Execute a rule, returning the associated values. If possible, the -- rules will be run in parallel. This function requires that appropriate -- rules have been added with rule or defaultRule. apply :: Rule key value => [key] -> Action [value] -- | Apply a single rule, equivalent to calling apply with a -- singleton list. Where possible, use apply to allow parallelism. apply1 :: Rule key value => key -> Action value -- | Write an action to the trace list, along with the start/end time of -- running the IO action. The system' command automatically calls -- traced. The trace list is used for profile reports (see -- shakeReport). traced :: String -> IO a -> Action a -- | Lift a computation from the IO monad. liftIO :: MonadIO m => forall a. IO a -> m a -- | Options to control the execution of Shake, usually specified by -- overriding fields in shakeOptions: -- --
-- shakeOptions{shakeThreads=4, shakeReport=Just "report.html"}
--
--
-- The Data instance for this type reports the
-- shakeProgress field as having the abstract type
-- ShakeProgress, because Data cannot be defined for
-- functions.
data ShakeOptions
ShakeOptions :: FilePath -> Int -> Int -> Verbosity -> Bool -> Maybe FilePath -> Bool -> Bool -> Maybe Double -> Maybe Assume -> [(String, String)] -> (IO Progress -> IO ()) -> ShakeOptions
-- | Defaults to .shake. The prefix of the filename used for
-- storing Shake metadata files. All metadata files will be named
-- shakeFiles.extension, for some
-- extension.
shakeFiles :: ShakeOptions -> FilePath
-- | Defaults to 1. Maximum number of rules to run in parallel,
-- similar to make --jobs=N. To enable parallelism you
-- may need to compile with -threaded. For many build systems, a
-- number equal to or slightly less than the number of physical
-- processors works well.
shakeThreads :: ShakeOptions -> Int
-- | Defaults to 1. The version number of your build rules.
-- Increment the version number to force a complete rebuild, such as when
-- making significant changes to the rules that require a wipe. The
-- version number should be set in the source code, and not passed on the
-- command line.
shakeVersion :: ShakeOptions -> Int
-- | Defaults to Normal. What level of messages should be printed
-- out.
shakeVerbosity :: ShakeOptions -> Verbosity
-- | Defaults to False. Operate in staunch mode, where building
-- continues even after errors, similar to make --keep-going.
shakeStaunch :: ShakeOptions -> Bool
-- | Defaults to Nothing. Write an HTML profiling report to a file,
-- showing which rules rebuilt, why, and how much time they took. Useful
-- for improving the speed of your build systems.
shakeReport :: ShakeOptions -> Maybe FilePath
-- | Defaults to False. Perform basic sanity checks after building,
-- checking files have not been modified several times during the build.
-- These sanity checks fail to catch most interesting errors.
shakeLint :: ShakeOptions -> Bool
-- | Defaults to False. Run rules in a deterministic order, as far
-- as possible. Typically used in conjunction with
-- shakeThreads=1 for reproducing a build. If this field
-- is set to False, Shake will run rules in a random order, which
-- typically decreases contention for resources and speeds up the build.
shakeDeterministic :: ShakeOptions -> Bool
-- | Defaults to Just 10. How often to flush Shake metadata
-- files in seconds, or Nothing to never flush explicitly. It is
-- possible that on abnormal termination (not Haskell exceptions) any
-- rules that completed in the last shakeFlush seconds will be
-- lost.
shakeFlush :: ShakeOptions -> Maybe Double
-- | Defaults to Nothing. Assume all build objects are clean/dirty,
-- see Assume for details. Can be used to implement make
-- --touch.
shakeAssume :: ShakeOptions -> Maybe Assume
-- | Defaults to []. A list of substrings that should be
-- abbreviated in status messages, and their corresponding abbreviation.
-- Commonly used to replace the long paths (e.g.
-- .makei586-linux-gccoutput) with an abbreviation (e.g.
-- $OUT).
shakeAbbreviations :: ShakeOptions -> [(String, String)]
-- | Defaults to no action. A function called on a separate thread when the
-- build starts, allowing progress to be reported. For applications that
-- want to display progress messages, progressSimple is often
-- sufficient, but more advanced users should look at the Progress
-- data type.
shakeProgress :: ShakeOptions -> IO Progress -> IO ()
-- | The current assumptions made by the build system, used by
-- shakeAssume. These options allow the end user to specify that
-- any rules run are either to be treated as clean, or as dirty,
-- regardless of what the build system thinks.
--
-- These assumptions only operate on files reached by the current
-- action commands. Any other files in the database are left
-- unchanged.
data Assume
-- | Assume that all rules reached are dirty and require rebuilding,
-- equivalent to storedValue always returning Nothing.
-- Useful to undo the results of AssumeClean, for benchmarking
-- rebuild speed and for rebuilding if untracked dependencies have
-- changed. This assumption is safe, but may cause more rebuilding than
-- necessary.
AssumeDirty :: Assume
-- | This assumption is unsafe, and may lead to incorrect build
-- results. Assume that all rules reached are clean and do not
-- require rebuilding, provided the rule has a storedValue and has
-- been built before. Useful if you have modified a file in some
-- inconsequential way, such as only the comments or whitespace, and wish
-- to avoid a rebuild.
AssumeClean :: Assume
-- | Information about the current state of the build, obtained by passing
-- a callback function to shakeProgress. Typically a program will
-- use progressDisplay to poll this value and produce status
-- messages, which is implemented using this data type.
data Progress
Progress :: !Bool -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !(Double, Int) -> Progress
-- | Starts out True, becomes False once the build has
-- completed.
isRunning :: Progress -> !Bool
-- | Number of rules which were required, but were already in a valid
-- state.
countSkipped :: Progress -> {-# UNPACK #-} !Int
-- | Number of rules which were have been built in this run.
countBuilt :: Progress -> {-# UNPACK #-} !Int
-- | Number of rules which have been built previously, but are not yet
-- known to be required.
countUnknown :: Progress -> {-# UNPACK #-} !Int
-- | Number of rules which are currently required (ignoring dependencies
-- that do not change), but not built.
countTodo :: Progress -> {-# UNPACK #-} !Int
-- | Time spent building countSkipped rules in previous runs.
timeSkipped :: Progress -> {-# UNPACK #-} !Double
-- | Time spent building countBuilt rules.
timeBuilt :: Progress -> {-# UNPACK #-} !Double
-- | Time spent building countUnknown rules in previous runs.
timeUnknown :: Progress -> {-# UNPACK #-} !Double
-- | Time spent building countTodo rules in previous runs, plus the
-- number which have no known time (have never been built before).
timeTodo :: Progress -> {-# UNPACK #-} !(Double, Int)
-- | A simple method for displaying progress messages, suitable for using
-- as shakeProgress. This function writes the current progress to
-- the titlebar every five seconds. The function is defined as:
--
-- -- progressSimple = progressDisplay 5 progressTitlebar --progressSimple :: IO Progress -> IO () -- | Given a sampling interval (in seconds) and a way to display the status -- message, produce a function suitable for using as -- shakeProgress. This function polls the progress information -- every n seconds, produces a status message and displays it -- using the display function. -- -- Typical status messages will take the form of 1:25m (15%), -- indicating that the build is predicted to complete in 1min 25sec, and -- 15% of the necessary build time has elapsed. This function uses past -- observations to predict future behaviour, and as such, is only -- guessing. The time is likely to go up as well as down, and will be -- less accurate from a clean build (as the system has fewer past -- observations). -- -- The current implementation is to predict the time remaining (based on -- timeTodo) and the work already done (timeBuilt). The -- percentage is then calculated as remaining / (done + -- remaining), while time left is calculated by scaling -- remaining by the observed work rate in this build, namely -- done / time_elapsed. progressDisplay :: Double -> (String -> IO ()) -> IO Progress -> IO () -- | Set the title of the current console window to the given text. On -- Windows this function uses the SetConsoleTitle API, elsewhere -- it uses an xterm escape sequence. This function may not work for all -- terminals. progressTitlebar :: String -> IO () -- | The verbosity data type, used by shakeVerbosity. data Verbosity -- | Don't print any messages. Silent :: Verbosity -- | Only print essential messages (typically errors). Quiet :: Verbosity -- | Print normal messages (typically errors and warnings). Normal :: Verbosity -- | Print lots of messages (typically errors, warnings and status -- updates). Loud :: Verbosity -- | Print messages for virtually everything (for debugging a build -- system). Diagnostic :: Verbosity -- | Get the current verbosity level, as set by shakeVerbosity. If -- you want to output information to the console, you are recommended to -- use putLoud / putNormal / putQuiet, which ensures -- multiple messages are not interleaved. getVerbosity :: Action Verbosity -- | Write a message to the output when the verbosity -- (shakeVerbosity) is appropriate. The output will not be -- interleaved with any other Shake messages (other than those generated -- by system commands). putLoud :: String -> Action () -- | Write a message to the output when the verbosity -- (shakeVerbosity) is appropriate. The output will not be -- interleaved with any other Shake messages (other than those generated -- by system commands). putNormal :: String -> Action () -- | Write a message to the output when the verbosity -- (shakeVerbosity) is appropriate. The output will not be -- interleaved with any other Shake messages (other than those generated -- by system commands). putQuiet :: String -> Action () -- | Run an action with Quiet verbosity, in particular messages -- produced by traced (including from system') will not be -- printed to the screen. quietly :: Action a -> Action a -- | Execute a system command. This function will raise an error if the -- exit code is non-zero. Before running system' make sure you -- need any required files. system' :: FilePath -> [String] -> Action () -- | Execute a system command with a specified current working directory -- (first argument). This function will raise an error if the exit code -- is non-zero. Before running systemCwd make sure you need -- any required files. -- --
-- systemCwd "/usr/MyDirectory" "pwd" [] --systemCwd :: FilePath -> FilePath -> [String] -> Action () -- | Execute a system command, returning (stdout,stderr). This -- function will raise an error if the exit code is non-zero. Before -- running systemOutput make sure you need any required -- files. systemOutput :: FilePath -> [String] -> Action (String, String) -- | copyFile old new copies the existing file from old -- to new. The old file is has need called on it -- before copying the file. copyFile' :: FilePath -> FilePath -> Action () -- | Read a file, after calling need. readFile' :: FilePath -> Action String -- | A version of readFile' which also splits the result into lines. readFileLines :: FilePath -> Action [String] -- | Write a file, lifted to the Action monad. writeFile' :: FilePath -> String -> Action () -- | A version of writeFile' which writes out a list of lines. writeFileLines :: FilePath -> [String] -> Action () -- | Write a file, but only if the contents would change. writeFileChanged :: FilePath -> String -> Action () -- | Require that the following files are built before continuing. -- Particularly necessary when calling system'. As an example: -- --
-- "*.rot13" *> \out -> do -- let src = dropExtension out -- need [src] -- system' ["rot13",src,"-o",out] --need :: [FilePath] -> Action () -- | Require that the following are built by the rules, used to specify the -- target. -- --
-- main = shake shakeOptions $ do -- want ["Main.exe"] -- ... ---- -- This program will build Main.exe, given sufficient rules. want :: [FilePath] -> Rules () -- | Define a rule that matches a FilePattern. No file required by -- the system must be matched by more than one pattern. For the pattern -- rules, see ?==. -- --
-- "*.asm.o" *> \out -> do -- let src = dropExtension out -- need [src] -- system' ["as",src,"-o",out] ---- -- To define a build system for multiple compiled languages, we recommend -- using .asm.o, .cpp.o, .hs.o, to indicate -- which language produces an object file. I.e., the file -- foo.cpp produces object file foo.cpp.o. -- -- Note that matching is case-sensitive, even on Windows. (*>) :: FilePattern -> (FilePath -> Action ()) -> Rules () -- | Define a set of patterns, and if any of them match, run the associated -- rule. See *>. (**>) :: [FilePattern] -> (FilePath -> Action ()) -> Rules () -- | Define a rule to build files. If the first argument returns -- True for a given file, the second argument will be used to -- build it. Usually *> is sufficient, but ?> gives -- additional power. For any file used by the build system, only one rule -- should return True. -- --
-- (all isUpper . takeBaseName) ?> \out -> do -- let src = replaceBaseName out $ map toLower $ takeBaseName out -- writeFile' . map toUpper =<< readFile' src --(?>) :: (FilePath -> Bool) -> (FilePath -> Action ()) -> Rules () -- | Define a rule for building multiple files at the same time, a more -- powerful and more dangerous version of *>>. -- -- Given an application test ?>> ..., test should -- return Just if the rule applies, and should return the list -- of files that will be produced. This list must include the file -- passed as an argument and should obey the invariant: -- --
-- test x == Just ys ==> x `elem` ys && all ((== Just ys) . test) ys ---- -- As an example of a function satisfying the invariaint: -- --
-- test x | takeExtension x `elem` [".hi",".o"] -- = Just [dropExtension x <.> "hi", dropExtension x <.> "o"] -- test _ = Nothing ---- -- Regardless of whether Foo.hi or Foo.o is passed, the -- function always returns [Foo.hi, Foo.o]. (?>>) :: (FilePath -> Maybe [FilePath]) -> ([FilePath] -> Action ()) -> Rules () -- | Define a rule for building multiple files at the same time. As an -- example, a single invokation of GHC produces both .hi and -- .o files: -- --
-- ["*.o","*.hi"] *>> \[o,hi] -> do -- let hs = replaceExtension o "hs" -- need ... -- all files the .hs import -- system' "ghc" ["-c",hs] ---- -- However, in practice, it's usually easier to define rules with -- *> and make the .hi depend on the .o. When -- defining rules that build multiple files, all the FilePattern -- values must have the same sequence of // and * -- wildcards in the same order. (*>>) :: [FilePattern] -> ([FilePath] -> Action ()) -> Rules () -- | A type synonym for file patterns, containing // and -- *. For the syntax and semantics of FilePattern see -- ?==. type FilePattern = String -- | Match a FilePattern against a FilePath, There are only -- two special forms: -- --
-- "*.c" ?== "foo/bar/baz.c" -- "*.c" ?== "baz.c" -- "*.c" ?== "baz.c" -- "test.c" ?== "test.c" ---- -- Examples that don't match: -- --
-- "*.c" ?== "foo/bar.c" -- "*/*.c" ?== "foo/bar/baz.c" ---- -- An example that only matches on Windows: -- --
-- "foo/bar" ?== "foo\\bar" --(?==) :: FilePattern -> FilePath -> Bool -- | Returns True if the file exists. doesFileExist :: FilePath -> Action Bool -- | Returns True if the directory exists. doesDirectoryExist :: FilePath -> Action Bool -- | Get the contents of a directory. The result will be sorted, and will -- not contain the files . or .. (unlike the standard -- Haskell version). It is usually better to call either -- getDirectoryFiles or getDirectoryDirs. The resulting -- paths will be relative to the first argument. getDirectoryContents :: FilePath -> Action [FilePath] -- | Get the files in a directory that match any of a set of patterns. For -- the interpretation of the pattern see ?==. getDirectoryFiles :: FilePath -> [FilePattern] -> Action [FilePath] -- | Get the directories contained by a directory, does not include -- . or ... getDirectoryDirs :: FilePath -> Action [FilePath] -- | Add extra information which your build should depend on. For example: -- --
-- newtype GhcVersion = GhcVersion () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) -- addOracle $ \(GhcVersion _) -> return "7.2.1" ---- -- If a rule depends on the GHC version, it can use askOracle -- (GhcVersion ()), and if the GHC version changes, the rule will -- rebuild. We use a newtype around () to allow the use -- of GeneralizedNewtypeDeriving. It is common for the value -- returned by askOracle to be ignored, in which case -- askOracleWith may help avoid ambiguous type messages -- -- although a wrapper function with an explicit type is encouraged. The -- result of addOracle is simply askOracle restricted to -- the specific type of the added oracle. To import all the type classes -- required see Development.Shake.Classes. -- -- We require that each call to addOracle uses a different type of -- question from any other calls in a given set of Rules, -- otherwise a runtime error will be raised. -- -- Actions passed to addOracle will be run in every build they are -- required, but if their value does not change they will not invalidate -- any rules depending on them. To get a similar behaviour using files, -- see alwaysRerun. -- -- As an example, consider tracking package versions installed with GHC: -- --
-- newtype GhcPkgList = GhcPkgList () deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
-- newtype GhcPkgVersion = GhcPkgVersion String deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
--
-- do
-- getPkgList <- addOracle $ \GhcPkgList{} -> do
-- (out,_) <- systemOutput "ghc-pkg" ["list","--simple-output"]
-- return [(reverse b, reverse a) | x <- words out, let (a,_:b) = break (== '-') $ reverse x]
-- --
-- getPkgVersion <- addOracle $ \(GhcPkgVersion pkg) -> do
-- pkgs <- getPkgList
-- return $ lookup pkg pkgs
--
--
-- Using these definitions, any rule depending on the version of
-- shake should call getPkgVersion "shake" to rebuild
-- when shake is upgraded.
addOracle :: (ShakeValue q, ShakeValue a) => (q -> Action a) -> Rules (q -> Action a)
-- | Get information previously added with addOracle, the
-- question/answer types must match those provided to
-- addOracle.
askOracle :: (ShakeValue q, ShakeValue a) => q -> Action a
-- | Get information previously added with addOracle. The second
-- argument is unused, but can be useful to avoid ambiguous type error
-- messages.
askOracleWith :: (ShakeValue q, ShakeValue a) => q -> a -> Action a
-- | Always rerun the associated action. Useful for defining rules that
-- query the environment. For example:
--
-- -- "ghcVersion.txt" *> \out -> do -- alwaysRerun -- (stdout,_) <- systemOutput "ghc" ["--version"] -- writeFileChanged out stdout --alwaysRerun :: Action () -- | The type representing a finite resource, which multiple build actions -- should respect. Created with newResource in the IO monad -- before calling shake, and used with withResource in the -- Action monad when defining rules. -- -- As an example, only one set of calls to the Excel API can occur at one -- time, therefore Excel is a finite resource of quantity 1. You can -- write: -- --
-- do excel <- newResource "Excel" 1
-- shake shakeOptions{shakeThreads=2} $ do
-- want ["a.xls","b.xls"]
-- "*.xls" *> \out ->
-- withResource excel 1 $
-- system' "excel" [out,...]
--
--
-- Now the two calls to excel will not happen in parallel. Using
-- Resource is better than MVar as it will not block any
-- other threads from executing. Be careful that the actions run within
-- withResource do not themselves require further quantities of
-- this resource, or you may get a "thread blocked indefinitely in an
-- MVar operation" exception. Typically only system commands (such as
-- system') will be run inside withResource, not commands
-- such as need.
--
-- As another example, calls to compilers are usually CPU bound but calls
-- to linkers are usually disk bound. Running 8 linkers will often cause
-- an 8 CPU system to grid to a halt. We can limit ourselves to 4 linkers
-- with:
--
--
-- do disk <- newResource "Disk" 4
-- shake shakeOptions{shakeThreads=8} $ do
-- want [show i <.> "exe" | i <- [1..100]]
-- "*.exe" *> \out ->
-- withResource disk 1 $
-- system' "ld" ["-o",out,...]
-- "*.o" *> \out ->
-- system' "cl" ["-o",out,...]
--
data Resource
-- | Create a new finite resource, given a name (for error messages) and a
-- quantity of the resource that exists. For an example see
-- Resource.
newResource :: String -> Int -> IO Resource
-- | Run an action which uses part of a finite resource. For an example see
-- Resource.
withResource :: Resource -> Int -> Action a -> Action a