Coadjute is a generic build tool, intended as an easier to use and more portable (in the sense that implementations don't differ) replacement for make. It's not tailored toward any particular language, and is not meant to replace tools which target a specific environment.
An example of simple usage:
import Coadjute import System.Directory main = coadjute $ do rule' "Copy foo from src to obj" (\[s] t -> copyFile s t) (sourceDatum' (("obj"++) . drop 3) ["src/foo"])
By convention, this file should be called Adjutant.hs.
Compiled and run, it would copy src/foo
to obj/foo
whenever src/foo
is older than obj/foo
. With -d
or --use-db
passed, it would hash
(currently MD5) src/foo
, using that instead of modification time data to
decide whether to run the copyFile
or not.
- data Coadjute a
- coadjute :: Coadjute a -> IO a
- rule :: String -> [String] -> ([Source] -> Target -> IO ()) -> [([Source], Target)] -> Coadjute ()
- ruleM :: String -> [String] -> ([Source] -> [Target] -> IO ()) -> [([Source], [Target])] -> Coadjute ()
- rule' :: String -> ([Source] -> Target -> IO ()) -> [([Source], Target)] -> Coadjute ()
- ruleM' :: String -> ([Source] -> [Target] -> IO ()) -> [([Source], [Target])] -> Coadjute ()
- getUserArgs :: Coadjute [String]
- type Source = FilePath
- type Target = FilePath
Coadjute blocks
When using Coadjute, you give it all the information it needs within
a monad inspiringly called Coadjute
. Use coadjute
to escape into
the IO monad, letting Coadjute do all your hard work for you.
Coadjute is the main monad you'll be working in. You can use the rule
family of functions to add rules whilst within this monad, and you can have
a look at what arguments were given to you with getUserArgs
.
For your convenience, a MonadIO
instance is provided.
Defining rules
These are the primary functions available to you inside a Coadjute
block:
each one adds a single build rule, on the basis of which many build tasks
may be constructed.
Each function takes:
- A name for the rule. (Currently only used in error messages.)
- A build action: this function will be run if the dependencies are deemed out of date compared to the target.
- A list of dependencies pared with one or more targets.
For instance, you might have a rule "C files" which handles building of C code, thus:
rule' "C files" (\_ c -> system ("gcc -c " ++ c)) [(["foo.c"],"foo.o"), (["bar.c"],"bar.o")]
This example also demonstrates poor practices: you should really specify complete dependency data, such as header files.
The above example did not use command line arguments, so let's have a look at those. Let's say you want to build either a debug or a release version of your program, depending on a flag you pass in. Since this flag will affect all your object files, you want to tell Coadjute that you're interested in it:
rule "C files" ["--debug"] ...
Now, if you've built your C files in release mode and want to switch to
debug mode, Coadjute will know to rebuild even those files which you haven't
changed, based simply on the fact that last time you did not pass --debug
and this time you did.
You must still handle the flag's presence yourself using getUserArgs
and
acting on it: the [String]
parameter is simply to tell Coadjute which
flags that particular rule is affected by.
For now, only boolean flags are supported: either they're present or not.
Note that you must build with -d
to store the argument data. You need
specify this only the first time: as long as the database exists it will be
used.
rule :: String -> [String] -> ([Source] -> Target -> IO ()) -> [([Source], Target)] -> Coadjute ()Source
A rule for building targets individually.
ruleM :: String -> [String] -> ([Source] -> [Target] -> IO ()) -> [([Source], [Target])] -> Coadjute ()Source
A rule for building multiple targets at once.
rule'
and ruleM'
are a pair of convenience functions for when you don't
care about command line arguments.
rule' :: String -> ([Source] -> Target -> IO ()) -> [([Source], Target)] -> Coadjute ()Source
rule' = flip rule []
ruleM' :: String -> ([Source] -> [Target] -> IO ()) -> [([Source], [Target])] -> Coadjute ()Source
ruleM' = flip ruleM []
Other functions within Coadjute
getUserArgs :: Coadjute [String]Source
You should use this instead of System.Environment.getArgs
, to let
Coadjute handle its own command line arguments first.
Sources and Targets
Sources and targets are both paths to files or directories.