Development.Shake.Forward

shake-0.19.8: Build system library, like Make, but more accurate dependencies.

Safe Haskell | None
Language | Haskell2010

Development.Shake.Forward

Description

A module for producing forward-defined build systems, in contrast to standard backwards-defined build systems such as shake. Based around ideas from fabricate. As an example:

    import Development.Shake
    import Development.Shake.Forward
    import Development.Shake.FilePath

    main = shakeArgsForward shakeOptions $ do
        contents <- readFileLines "result.txt"
        cache $ cmd "tar -cf result.tar" contents

Compared to backward-defined build systems (such as normal Shake), forward-defined build systems tend to be simpler for simple systems (less boilerplate, more direct style), but more complex for larger build systems (requires explicit parallelism, explicit sharing of build products, no automatic command line targets). As a general approach for writing forward-defined systems:

- Figure out the sequence of system commands that will build your project.
- Write a simple `Action` that builds your project.
- Insert `cache` in front of most system commands.
- Replace most loops with `forP`, where they can be executed in parallel.
- Where Haskell performs real computation, if zero-build performance is insufficient, use `cacheAction`.

All forward-defined systems use `AutoDeps`, which requires `fsatrace` to be on the `$PATH`. You can obtain `fsatrace` from https://github.com/jacereda/fsatrace. You must set `shakeLintInside` to specify where `AutoDeps` will look for dependencies - if you want all dependencies everywhere use `[""]`.

This module is considered experimental - it has not been battle tested. There are now a few possible alternatives in this space:

- Pier http://hackage.haskell.org/package/pier/docs/Pier-Core-Artifact.html (built on Shake).
- Rattle https://github.com/ndmitchell/rattle (by the same author as Shake).
- Stroll https://github.com/snowleopard/stroll.

Synopsis

- shakeForward :: ShakeOptions -> Action () -> IO ()
- shakeArgsForward :: ShakeOptions -> Action () -> IO ()
- forwardOptions :: ShakeOptions -> ShakeOptions
- forwardRule :: Action () -> Rules ()
- cache :: (forall r. CmdArguments r => r) -> Action ()
- cacheAction :: (Typeable a, Binary a, Show a, Typeable b, Binary b, Show b) => a -> Action b -> Action b
- cacheActionWith :: (Typeable a, Binary a, Show a, Typeable b, Binary b, Show b, Typeable c, Binary c, Show c) => a -> b -> Action c -> Action c

# Documentation

shakeForward :: ShakeOptions -> Action () -> IO () #

Run a forward-defined build system.

shakeArgsForward :: ShakeOptions -> Action () -> IO () #

Run a forward-defined build system, interpreting command-line arguments.

forwardOptions :: ShakeOptions -> ShakeOptions #

Given a `ShakeOptions`, set the options necessary to execute in forward mode.

forwardRule :: Action () -> Rules () #

Given an `Action`, turn it into a `Rules` structure which runs in forward mode.

cache :: (forall r. CmdArguments r => r) -> Action () #

Apply caching to an external command using the same arguments as `cmd`.

    cache $ cmd "gcc -c" ["foo.c"] "-o" ["foo.o"]

This command will be cached, with the inputs/outputs traced. If any of the files used by this command (e.g. `foo.c` or header files it imports) then the command will rerun.

cacheAction :: (Typeable a, Binary a, Show a, Typeable b, Binary b, Show b) => a -> Action b -> Action b #

Cache an action, given a key and an `Action`. Each call in your program should specify a different key, but the key should remain consistent between runs. Ideally, the `Action` will gather all its dependencies with tracked operations, e.g. 'readFile''. However, if information is accessed from the environment (e.g. the action is a closure), you should call `cacheActionWith` being explicit about what is captured.

cacheActionWith :: (Typeable a, Binary a, Show a, Typeable b, Binary b, Show b, Typeable c, Binary c, Show c) => a -> b -> Action c -> Action c #

Like `cacheAction`, but also specify which information is captured by the closure of the `Action`. If that information changes, the `Action` will be rerun.