shake-0.1.3: Build system library, like Make, but properly supports generated files.

Development.Shake

Contents

Description

Main module for defining Shake build systems. You may also want to include Development.Shake.FilePath, for manipulating file paths. As a simple example, let us build a result.tar file from the contents of 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

For the background theory behind a previous version of Shake the online video: http://vimeo.com/15465133.

Synopsis

Documentation

shake :: ShakeOptions -> Rules () -> IO ()Source

Main entry point for running Shake build systems. For an example see Development.Shake.

Core of Shake

data ShakeOptions Source

Options to control shake.

Constructors

ShakeOptions 

Fields

shakeFiles :: FilePath

Where shall I store the database and journal files (defaults to .shake).

shakeParallel :: Int

What is the maximum number of rules I should run in parallel (defaults to 1).

shakeVersion :: Int

What is the version of your build system, increment to force a complete rebuild.

shakeVerbosity :: Int

1 = normal, 0 = quiet, 2 = loud.

run :: ShakeOptions -> Rules () -> IO ()Source

This function is not actually exported, but Haddock is buggy. Please ignore.

class (Show key, Typeable key, Eq key, Hashable key, Binary key, Show value, Typeable value, Eq value, Hashable value, Binary value) => Rule key value | key -> value whereSource

Define a pair of types that can be used by Shake rules.

Methods

validStored :: key -> value -> IO BoolSource

Given that the database contains key/value, does that still match the on-disk contents?

As an example for filenames/timestamps, if the file exists and had the same timestamp, you would return True, but otherwise return False. For rule values which are not also stored on disk, validStored should always return True.

Instances

Rule File FileTime 
Rule GetDir GetDir_ 
Rule Exist Bool 

data Rules a Source

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 using the Monad instance and do notation.

Instances

defaultRule :: Rule key value => (key -> Maybe (Action value)) -> Rules ()Source

Like rule, but lower priority, if no rule exists then defaultRule is checked. All default rules must be disjoint.

rule :: Rule key value => (key -> Maybe (Action value)) -> Rules ()Source

Add a rule to build a key, returning an appropriate Action. All rules must be disjoint. To define lower priority rules use defaultRule.

action :: Action a -> Rules ()Source

Run an action, usually used for specifying top-level requirements.

data Action a Source

The Action monad, use liftIO to raise IO actions into it, and need to execute files. Action values are used by rule and action.

apply :: Rule key value => [key] -> Action [value]Source

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.

apply1 :: Rule key value => key -> Action valueSource

Apply a single rule, equivalent to calling apply with a singleton list. Where possible, use apply to allow the potential for parallelism.

traced :: String -> IO a -> Action aSource

Write an action to the trace list, along with the start/end time of running the IO action. The system' command automatically calls traced.

currentStack :: Action [Key]Source

Get the stack of Keys for the current rule - usually used to improve error messages. Returns '[]' if being run by action, otherwise returns the stack with the oldest rule first.

putLoud, putQuiet, putNormal :: String -> Action ()Source

Write a message to the output when the verbosity is appropriate. The output will not be interleaved with any other Shake messages (other than those generated by system commands).

Utility functions

system' :: FilePath -> [String] -> Action ()Source

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.

copyFile' :: FilePath -> FilePath -> Action ()Source

copyFile old new copies the existing file from old to new. The old file is has need called on it before copying the file.

readFile' :: FilePath -> Action StringSource

Read a file, after calling need.

writeFile' :: FilePath -> String -> Action ()Source

Write a file, lifted to the Action monad.

readFileLines :: FilePath -> Action [String]Source

A version of readFile' which also splits the result into lines.

writeFileLines :: FilePath -> [String] -> Action ()Source

A version of writeFile' which writes out a list of lines.

File rules

type FilePattern = StringSource

A type synonym for file patterns, containing // and *. For the syntax and semantics of FilePattern see ?==.

need :: [FilePath] -> Action ()Source

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]

want :: [FilePath] -> Rules ()Source

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.

defaultRuleFile :: Rules ()Source

This function is not actually exported, but Haddock is buggy. Please ignore.

(?==) :: FilePattern -> FilePath -> BoolSource

Match a FilePattern against a FilePath, There are only two special forms:

  • * matches an entire path component, excluding any separators.
  • // matches an arbitrary number of path componenets.

Some examples that match:

 "//*.c" ?== "foo/bar/baz.c"
 "*.c" ?== "baz.c"
 "//*.c" ?== "baz.c"
 "test.c" ?== "test.c"

Examples that don't match:

 "*.c" ?== "foor/bar.c"
 "*/*.c" ?== "foo/bar/baz.c"

(*>) :: FilePattern -> (FilePath -> Action ()) -> Rules ()Source

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.

(**>) :: [FilePattern] -> (FilePath -> Action ()) -> Rules ()Source

Define a set of patterns, and if any of them match, run the associate rule. See *>.

(?>) :: (FilePath -> Bool) -> (FilePath -> Action ()) -> Rules ()Source

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

Directory rules

doesFileExist :: FilePath -> Action BoolSource

Returns True if the file exists.

getDirectoryContents :: FilePath -> Action [FilePath]Source

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.

getDirectoryFiles :: FilePath -> FilePattern -> Action [FilePath]Source

Get the files in a directory that match a particular pattern. For the interpretation of the pattern see ?==.

getDirectoryDirs :: FilePath -> Action [FilePath]Source

Get the directories contained by a directory, does not include . or ...

defaultRuleDirectory :: Rules ()Source

This function is not actually exported, but Haddock is buggy. Please ignore.