NAME
ChainMake - Make targets with dependencies
SYNOPSIS
# this example uses the function-oriented interface
use ChainMake::Functions ':all';
# this target is to generate example.dvi from example.tex
target 'example.dvi', (
timestamps => ['$t_name'],
requirements => ['$t_base.tex'],
handler => sub {
my ($t_name,$t_base,$t_ext)=@_;
execute_system(
All => "latex $t_base.tex",
);
}
);
# this target is to generate example.ps from example.dvi
# and another.ps from another.dvi
targets ['example.ps','another.ps'], (
timestamps => ['$t_name'],
requirements => ['$t_base.dvi'],
handler => sub {
my ($t_name,$t_base,$t_ext)=@_;
execute_system(
All => "dvips -q -t a5 $t_base.dvi",
);
}
);
# this target is to generate a *.pdf from a *.ps
target qr/^[^\.]+\.pdf$/, (
timestamps => ['$t_name'],
requirements => ['$t_base.ps'],
handler => sub {
my ($t_name,$t_base,$t_ext)=@_;
execute_system(
All => "ps2pdf $t_base.ps $t_base.pdf",
);
}
);
target 'clean', (
handler => sub {
unlink qw/example.aux example.dvi example.log example.pdf example.ps/;
1;
}
);
target [qw/all All/], requirements => ['example.pdf','clean'];
chainmake(@ARGV);
DESCRIPTION
This module helps with driving data through process chains. It can be a better alternative to make
in some use cases.
TODO: More bla here:
* separation of target name from timestamp file
* 'auto' timestamps, for targets that don't create files
(i.e. xml validation)
* write perl script in perl, not makefile in makefile lingo
* typically for processing files (xml, images etc.)
through several process steps (i.e. latex, xslt, pbmtools)
* not so much for compiling and installing software,
i.e. principally possible,
but no luxury (libpath etc.) provided so far
* in summary it is a better alternative for use cases
that 'make' is not really intended for,
but still widely used
A script that uses this module will typically create one ChainMake object, add some "targets" to it and then call the "chainmake" method, potentially with user supplied parameters.
For a more declarative look-and-feel, script authors may also consider using the function-oriented interface provided by ChainMake::Functions .
METHODS
new
my $cm=new ChainMake(%options);
Creates a new ChainMake object. Options %options
are the same as for configure.
configure
$cm->configure(
timestamps_file => '.timestamps_file',
symbols => [ qr/\$t_name/, qr/\$t_base/, qr/\$t_ext/ ],
verbose => 1,
silent => 0,
);
Configures the ChainMake object. Available options are discussed below. Default values are shown above.
- timestamps_file
-
timestamps_file
is a filename that will be used for automatic timestamps as discussed under "timestamps". - symbols
-
symbols
is a list of three regular expressions that are used for referring to the current target name. See "requirements" below. - verbose
-
Usage of
verbose
is under development and will change. - silent
-
Usage of
silent
is under development and will change.
targets
$cm->targets( ['all', 'document'],
requirements => ['document.html', 'document.pdf']
);
Adds a new target type. A human readable explanation will be given below.
For reference, this is a pseudo formal form of the syntax:
$target_names = targetname | regexp | [targetname | regexp, ...]
%description = (
requirements => [ targetname | filename, ... ] | (),
insistent => 0 | 1,
parallel => 0 | number,
handler => coderef | (),
timestamps => [ filename, ... ] | 'once' | (),
);
$cm->targets( $target_names, %description );
These are examples in perl:
$cm->targets( ['all', 'document'],
requirements => ['document.html', 'document.pdf']
);
$cm->targets( qr/^[^\.]+\.html?$/,
requirements => ['$t_base.xml'],
handler => sub { ... },
timestamps => ['$t_base.$t_ext'],
);
- target names
-
The first argument of the
targets
method is for supplying one or more targets names. Target names can be strings or regular expressions.The
targets
method declares a target type that is used for all targets that match any of the supplied target names. - requirements
-
%description = ( requirements => ['index.txt', '$t_base.dat'], }
The
requirements
field lists things that need to be done before the target can be made. Therequirements
field is optional, but eitherrequirements
or ahandler
must be specified.Requirements may be given as targets or filenames. If a given requirement does not match a target it is regarded a filename. Filenames should include a path if necessary.
The
requirements
strings may contain any of the threesymbols
specified with "configure". The symbols will be replaced with the current target's full name, base name (without extension) and extension respectively. Assuming that you haven't defined differentsymbols
the following will be replaced in therequirements
of a target 'index.html':$t_name -> index.html $t_base -> index $t_ext -> html
- handler
-
%description = ( handler => sub { my ($t_name, $t_base, $t_ext) = @_; execute_system( All => "dvips -q -t a5 $t_base.dvi", ); } }
The
handler
field can be used to supply a subroutine that will be executed to build the target. The return value of this subroutine should indicate whether the build has been successfull.Three parameters will be passed to the subroutine: The full name of the target to make, only the base part of this name (minus the extension), and the extension of the target name. These three variables equal the replacement
symbols
discussed under "requirements" and should convienently be named equally, i.e.$t_name
,$t_base
,$t_ext
.If no
handler
is supplied, the target will always be considered successfull. - timestamps
-
%description = ( timestamps => ['index.html'], } %description2 = ( timestamps => 'once', }
The
timestamps
field defines how to check whether the target is up-to-date. Either one or more filenames or the stringonce
may be supplied.The separation of the timestamps from the target name is an important difference between this module and
make
.If the
timestamps
field is supplied, thehandler
field must be supplied as well.If the
timestamps
is missing, each time thatchainmake()
is performed on the target allrequirements
will be checked and thehandler
will be executed.- filename based timestamps
-
In case one or more filenames are given, the timestamp (age) of the oldest of these files is determined. This timestamp is compared to the timestamps of all of the
requirements
to find out if the target is outdated or not.The filenames may be identical to target names, but, as opposed to
make
, does not need to be. The filename is given with a path relative to the current directory. For a filename that matches the target name usetimestamps => ['$t_name']
.The file should typically be a file that the
handler
produces from at least some of therequirements
. Thehandler
must at leasttouch
the file to make this form of timestamps work. If this is not the case, use'once'
.If the
handler
fails, any remaining files listed undertimestamps
will be removed. - automatic timestamps using 'once'
-
The string
once
may be supplied instead of a list reference. This turns on automatic bookkeeping of the target's status.The data necessary for the
once
automatism is stored in a file with the name that has been defined with the "timestamps_file" option.
- insistent
-
%description = ( insistent => 1, );
The
insistent
field defines if remaining requirements should still still be checked after one requirement failed. Default behaviour is to stop.When a target has several requirements they will be all be checked (and built if necessary) before this target can be built. If one of the requirements fails, i.e. does not exist or fails to built, the remaining requirements may still be checked (
insistent => 1
) or the attempt to build the target may aborted immediately (insistent => 0
).
chainmake
$cm->chainmake($target);
Makes the target $target
.
This is a simplified schematic of the algorithm in use:
Find matching target type
See, if all "timestamps" files are present and how old the oldest one is (
$oldest
)Go through all "requirements":
For the ones that are targets, call
chainmake()
on each of them to learn about their age (recursion here)For the ones that are files, check their age
Compare all these ages with
$oldest
to see if one requirement is younger than the target$target
. If so, we'll have to run the "handler"If any requirement is missing: we cannot make
$target
; Continue with examining the remaining requirements if "insistent" == 1The youngest of all the seen requirements is
$youngest_requirement
, as passed to the handler.Entire loop done in parallel threads by ChainMake::Parallel
Run the handler if necessary
Return the age of the youngest file in "timestamps"
available_targets
print $cm->avaliable_targets();
Returns a formatted string listing the available targets. This will maybe change.
delete_timestamp
$cm1->delete_timestamp('document.validation')
Deletes the automatic ('once'
) timestamp for the given target.
unlink_timestamps
Unlinks the timestamps file.
execute_system
Under development.
execute_perl
Under development, i.e. too lazy to document right now.
CAVEATS/BUGS
None known. In the Rakudo way: It passes almost 300 tests.
SEE ALSO
My search for similar modules has returned the following
- TinyMake
-
Very minimalistic. Syntax tries to mimic makefile syntax.
- File::Maker
-
Uses some sort of database. Difficult-to-read documentation.
AUTHOR/COPYRIGHT
This is $Id: ChainMake.pm 1231 2009-03-15 21:23:32Z schroeer $.
Copyright 2008-2009 Daniel Schröer (schroeer@cpan.org). Any feedback is appreciated.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 862:
Non-ASCII character seen before =encoding in 'Schröer'. Assuming CP1252