A: awk, C: &cat,
chgrp,
&chmod,
chown,
&cp,
cpp,
&cut, D: date,
E: &echo,
&expr, F: false,
fmt, G: &grep,
H: head, I: &install,
L: &ln, M: m4,
&mkdir,
&mv, P: &perl,
&preprocess,
&printf, R: &rm,
rmdir, S: &sed,
&sort, T: tail,
&template,
&touch,
tr, U: &uninstall,
&uniq, Y: &yes
There is a special Shell-like possibility to call built-in
commands in a rule. The only metacharacters recognized are comment signs,
backslashes, single and double quotes. Only one command may be given per
line, and I/O redirection is not available (see
"-i" and
"-o" below instead).
These commands start with
"&", which is the function character
in Perl and not a valid first character in Shell. If no builtin command of
that name can be found, this is also the syntax for calling an external
script within the Perl instance performing the rule. See
"run".
These commands, as well as your self defined ones and Perl scripts
can also be called as a make function, returning the standard output. This
requires perl to be built for PerlIO. The newlines are converted to spaces,
except when evaluated within a "define"
statement.
FIRST-WORDS ;= $(&cut -d' ' -f0 $(FILES))
When these commands are not indented as rule actions, they get
performed while reading the makefile. You can also access these commands
stand-alone, e.g. if you need some features not available in the Unix
counterpart, via the makeppbuiltin command.
These commands are mostly based on the GNU variant. But many
options (like --backup, --interactive or --recursive) don't really make
sense in a makefile. So, even though they'd be easy to implement in Perl,
they have been left out. Also many Unix commands offer a variety of options
that cover fairly complicated cases (e.g. sort field specifications) while
still being inherently limited. Allowing access to Perl, which is present
anyway, gives much more power here.
Lists of filenames may be empty, making it safe to call these
commands with an unchecked list. Options in their short form may be glued
together as in "-ab" instead of
"-a -b". In the long form arguments may be
given either glued on with an "=" sign or
separately. In the short form they may be given either glued on directly or
separately.
A few options are common to several builtins, though the short
form is sometimes hidden by a command's own option (as in
"&cut -f"):
- -A filename
- --args-file=filename
- --arguments-file=filename
- Read the file and parse it as possibly quoted whitespace- and/or
newline-separated options.
- -f
- --force
- Force the creation of the file(s) intended by the parameters, even if a
different kind of file or empty directory of that name already exists.
This must precede the "-o,
--output=filename" option if it is to have any effect on
that.
- -i shellcommand
- --inpipe=shellcommand
- Start the Shell command(s) and pipe the output into the builtin. There may
optionally be a trailing "|" character,
to indicate this is a pipe. With this option no filenames need to be
given. But if you want to perform the builtin on both files and the pipe
output, you must use "-" as a filename
for the pipe output. The pipe is emptied, but, unless you also give
"--infail", the command is not waited
for, so it can terminate in parallel. This option is necessary because
there is no redirection syntax.
- -I
- --infail
- If an "--inpipe" Shell command fails,
that also causes the current builtin to fail. This doesn't currently work
on Strawberry and Win ActiveState, because of the halfhearted way they
emulate Unix fork/exec. Cygwin gets it right though.
- -o filename
- --output=filename
- Write the output to this file, rather than stdout. Filename may have any
of these forms:
- filename
- >filename
- Simply write to file.
- >>filename
- Append to (not necessarily) existing file.
- +<filename
- Also open the file for input, allowing inplace editing. With this option
variant no input filenames need to be given. But if you want to perform
the builtin on more files, you must use
"-" as an input filename for this one.
In fact the output gets written to a temporary file which gets moved to
filename at the end.
- |shellcommand
- Pipe the builtin's output to the Shell command(s).
This option is necessary because there is no redirection
syntax.
- -O
- --outfail
- If an "--output" Shell command fails,
that also causes the current builtin to fail.
- -r number
- --record-size=number
- Locally sets $/ for the current builtin. This
splits input into records of length number rather than line by
line. If number is zero, each input file as a whole is one
record.
- -s string
- --separator=string
- Locally sets $/ for the current builtin. This
splits input on string rather than line by line.
- -S
- --synclines
- Generate "#line
""NO""
"""FILE""""
and "#line
""NO"
lines, understood by many C-like languages.
- -v
- --verbose
- Document the changes to the file system. This must precede other options
if it is to document their effect. If you pass this option to makepp
itself, it is as if you had given it for every single builtin
command.
There are two motivations for having builtin commands in makepp.
The first is to offer a set of utilities, which, unlike Shell commands, are
guaranteed to work the same everywhere, like
"&echo -n" or
"&mkdir -p", and saving you the hassle
of finding the path to &install and figuring out
its wildly varying options. In a compilation environment, it's useful to
have the "--synclines" option, which
normally only "m4" provides, on all
filters.
The other is a question of efficiency. In general costly
fork/execs should be avoided where reasonably possible. On Unix emulations
like Cygwin or BS2000/Posix, this becomes a noticeable win. But, even on
Linux, when the makepp test suite was converted from external commands to
builtins, there was an overall saving of 3% user CPU usage and 15% system
CPU usage. (The tests are of course heavy on primitive actions and hardly
call the compiler.)
Consistency is also an issue, though we're not going to reform
Unix. Normally commands have various nuances of regular expressions. And
many invent sort of languages, each different of course, for doing something
(e.g. "expr",
"sed" ...), or complex options for
specifying fields, delimiters, columns (e.g.
"cut",
"sort" ...).
Here instead, anything fancy simply gets handled by Perl, giving
both consistency across all commands, and far more power than a whole bunch
of options. Better yet, any Perlcode these commands run for you, gets
run in the package of the Makefile. So, rather than stuff Perl code into the
rule action, you can define functions and variables and use them within the
commands:
sub my_filter {
# Return true iff $_ is desirable
}
%.out: %.in Makeppfile
&grep &my_filter $(input) -o $(output)
If you use Perl functions or variables in your commands, makepp
does not recognize this as a dependency. It is generally safer to tell
makepp everything, so rules which use Perl elements should depend on the
makefile or module providing those elements, as shown in the above
example.
On the other hand ignorance may be desirable if you have a program
that mixes programmatic and configuration aspects in one file. An example
would be a WSDL file containing both a web service interface definition and
an IP address. You could preprocess this file with the
&template command to patch in the configuration,
but not let makepp notice.
- &cat [option ...] filename ...
- Concatenates all the files into a single one.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force,
-i, --inpipe=shellcommand, -I, --infail, -o,
--output=filename, -O, --outfail, -S,
--synclines, -v, --verbose"
- &chmod [option ...] mode filename ...
- Sets mode for all given files. Mode must be an octal string.
"Standard options": "-A,
--args-file, --arguments-file=filename, -v, --verbose"
- &cp [option ...] sourcefile destfile
- &cp [option ...] sourcefile
- &cp [option ...] sourcefile ... destdir
- Copy sourcefile to destfile, one sourcefile to
current directory or multiple sourcefiles to destdir with
the same name.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -v,
--verbose"
- -l
- --link
- Try to link the files. If that fails, try symbolic link, if that is also
requested, else copy.
- -s
- --symbolic
- --symbolic-link
- --symlink
- Try to symbolically link the files. If that fails, copy.
- &cut [option ...] filename ...
- Print selected parts of lines from each file or selected lines, counting
across all files. The output is separated by the delimiter which defaults
to TAB for fields and empty string for characters.
"Standard options": "-A,
--args-file, --arguments-file=filename, --force, -i,
--inpipe=shellcommand, -I, --infail, -o,
--output=filename, -O, --outfail, -r,
--record-size=number, --separator=string, -S,
--synclines, -v, --verbose"
- -c list
- --characters=list
- Print all the characters specified by list. List may be any
Perl expression returning a list of integers. The integers can be either
positive, starting at zero to count from the beginning, or negative to
count from the end. Unlike Unix "cut",
the order you request is respected.
Unlike in Perl's slice operator where a ".." range
must be either positive or negative, &cut
allows starting with a positive and ending with a negative. But this is
only available if your expression consists only of numbers, commas and
"..". E.g. "1..-2" means
everything but the first (0) and the last (-1).
The list expression can look at the whole line in
$_. Changes to that will be ignored, however,
because when this expression is evaluated the line has already been
split to Perl's autosplit variable @::F. The
numbers you return are in fact indices to that list.
- -d string
- --delimiter=string
- Set a new delimiter for input fields and output. Unlike Unix
"cut", this may have any length.
- -E
- --noescape
- Treat "\" as normal literals for
"-p, --printf=format".
- -f list
- --fields=list
- Print all the groups specified by list. List is as described
under "-c, --characters=list". Note that
this hides the standard option "-f"
which must be given as "--force".
- -l list
- --lines=list
- Print all the lines specified by list. List is as described
under "-c,
--characters=list" with one major difference:
The first line has number 1, there is no line 0. This is definitely
inefficient for big files, if you have a mixed positive to negative range
in your list, as it reads everything to memory. Otherwise Perl could
optimize this, but I don't know if it does.
- -m
- --matching
- Print only matching lines, i.e. ones which have enough characters or
fields. This implies "--only-delimited",
which is why you will miss single-field lines with
"--fields=0".
- -p format
- --printf=format
- Apply format (with \escapes) to all fields or characters.
- -s
- --only-delimited
- Print only lines containing delimiters.
&cut -c 10-20,-5,25- $(input)
&cut -c 'grep $$_ % 3, 0..99' $(input) # 1st 100 columns not multiple of 3
&cut -d: --fields 0,4 --printf='%10s is %s\n' /etc/passwd
- &echo [option ...] string ...
- &printf [option ...] format argument ...
- &yes [option ...] string ...
- Writes all strings to stdout or the given outfile. Both
&echo and &yes add
a newline at the end. The strings, or for
&printf the format, may contain
"\" escapes, as they are known from C or
modern Unix or Shell "echo". They are
however as in Perl double-quotes, which means some differences, like that
a single trailing "\" is not allowed.
Perl has a few more interesting escapes, but the ones you might expect to
do something different are:
- \cA
- Is a control character ^A.
- \u
- Upcases the following letter.
- \U
- Upcases the rest, or up to the next "\E"
or "\L" if found.
- \xHH,
\x{HHHH}
- Is the character value of the given Hex code. Note that numeric codes are
not portable to EBCDIC platforms!
Unlike Unix "yes",
&yes is exactly like
&echo, except that it repeats the output for as
long as it can, typically until an "--output '|
command'"
terminates. And, if &yes has no arguments, it
defaults to "y".
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -o,
--output=filename, -O, --outfail, -v,
--verbose"
- -E
- --noescape
- Treat "\" as normal literals.
- -n
- --nonewline
- Do not add a newline after the last string. (Not understood by
&printf.)
- &expr [option ...] perlcode ...
- Print the scalar value of perlcode, which may be written as one or several
arguments. Note that builtin commands are not parsed by the Shell, so
"*",
"(" or
">" are not special. But string
quotes are parsed by makepp, so Perl strings must be quoted twice, unless
you want to use barewords. If the value is false, this fails. Note that --
unlike in Unix "expr" -- Perl's index
function starts at 0 (false) and returns -1 (true) for failure.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -o,
--output=filename, -O, --outfail, -v,
--verbose"
&expr ($(VAR) - 3) * 2 < 1 && -1 || 1
&expr "$(VAR) - 3 * 2 < 1 ? 'joy' : 'sorrow'" -o $(output)
-&expr $(VAR) - 3 * 2 -o >>$(output)
- &grep [option ...] perlcode filename ...
- &perl [option ...] perlcode filename ...
- &sed [option ...] perlcode filename ...
- All the files get read line by line (unless you gave a
"--separator" option), and
perlcode gets evaluated for each line, before it gets printed.
&sed is similar to "perl
-pe", while &grep only outputs
those lines for which perlcode returns a true value.
&perl is similar to
"perl -ne", only outputting whatever you
explicitly print in the perlcode. The line content is available in
$_, which may be modified.
Of these three, only &grep will
fail if it outputs nothing. Note that there is no ignore-case option,
since you would do that with
"/regexp/i".
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -i,
--inpipe=shellcommand, -I, --infail, -o,
--output=filename, -O, --outfail, -r,
--record-size=number, -s, --separator=string, -S,
--synclines, --verbose"
The option "--synclines"
only makes sence with &perl if you use
&Mpp::Cmds::print to output
$_. Only &grep has
extra options:
- -c
- --count
- Suppress normal output; instead print a count of matching lines. With the
"-v,
--invert-match" option (see below), count
non-matching lines.
- -l
- --list
- --files-with-matches
- Output only the name of those files with matches. When this is combined
with "-v, --invert-match", output the
name of files with lines that don't match (a bit absurdly but compatible
with Unix -vl). When this is combined with a doubled
"-vv", output the name of files with no
matches.
- -v
- --vice-versa
- --revert-match
- --invert-match
- Invert the sense of matching, to select non-matching lines. Note that this
hides the standard option "-v" which
must be given as "--verbose".
- -w filename
- --waste-file=filename
- An optional waste basket for collecting the rejected lines. This is not
only for debugging your selection code, but also for splitting your input
in two. As with the normal output, you may modify
$_ before returning false.
&sed s/foo/bar/ f1 f2 f3 -o outfile # like sed s/foo/bar/ f1 f2 f3 >outfile
&sed '$$_ = uc' f1 f2 f3 -o outfile # like tr '[:lower:]' '[:upper:]' f1 f2 f3
&grep '$$. % 3' f1 f2 f3 -o outfile # eliminate every 3rd line
&grep -c /match/i f1 f2 f3 # count the lines matching 'match' to STDOUT
Without pushing you to mass generate accessors, here's how you
could do it by simply putting a comment of RO or RW between each type and
desired variable name, all on one line. The generated getter and optionally
setter methods go into the next found public or protected section:
# Create get and maybe set method from "type /* R[OW] */ member;".
sub cxx_accessors {
$acc ||= ''; # Candidate for 5.10.0 state
if( m!^\s*(.+?)\s*/\*\s*R([OW])\s*\*/\s*(.+?)\s*;! ) {
$acc .= "#line $.\n"; # Tell C++ where this came from
$acc .= "void set\u$3( const $1 &__tmp ) { $3 = __tmp; }"
if $2 eq 'W';
$acc .= "const $1 &get\u$3() const { return $3; }\n";
} elsif( /^\s*(?:public|protected)\s*:/ ) {
$_ .= $acc;
$acc = '';
}
}
%.cc: %.cc.in # Use &sed for I/O handling
&sed --sync-lines &cxx_accessors $(input) -o $(output)
- &install [option ...] sourcefile destfile
- &install [option ...] sourcefile ... destdir
- &install --directory [option ...] directory ...
- Move or rename sourcefile to destfile, or multiple
sourcefiles to destdir with the same name. This is the
preferred way of transferring build results to their final installation
locations.
Every file system modification performed by
&install gets logged to the end of the file
pointed to by the environment variable
$INSTALL_LOG, or, if that is not set but we are
under a directory with a RootMakeppfile(.mk), to a file of
.install_log in that directory, or else to that file in the
current directory. You may want to delete the logfile before a series of
&install invocations.
"Standard options": "-A,
--args-file, --arguments-file=filename, -v, --verbose"
- -c
- --copy
- Copy the files rather than moving them. This is preferable, as it doesn't
force makepp to rebuild the file next time. But it is not the default, for
compatibility with other install programs.
- -d
- --directory
- In the third form form of this command create all the given directories
and any necessary parent directories.
- -g group
- --group=group
- Change the group ownership of the destination files. The group may be
given by name or numerically.
- -l
- --link
- Try to link the files. If that fails, copy.
- --log=filename
- --logfile=filename
- Use filename instead of normal logfile.
- -m mode
- --mode=mode
- Sets mode for all destination files or directories. Mode must be an
octal string.
- -o owner
- --owner=owner
- Change the ownership of the destination files. The owner may be given by
name or numerically.
- -r
- --resolve
- --resolve-symbolic
- --resolve-symbolic-link
- --resolve-symlink
- -S
- --symbolic
- --symbolic-link
- --symlink
- Creates symbolic links instead of moving. These options are passed to
&ln and are described there.
- -s
- --strip
- Calls the "strip" utility, which must be
in the $PATH, on the destination files.
- &ln [option ...] sourcefile destfile
- &ln [option ...] sourcefile
- &ln [option ...] sourcefile ... destdir
- Link sourcefile to destfile, one sourcefile to
current directory or multiple sourcefiles to destdir with
the same name.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -v,
--verbose"
- -r
- --resolve
- --resolve-symbolic
- --resolve-symbolic-link
- --resolve-symlink
- This is what you always wanted "ln -s"
to do. Create symbolic rather than hard links, not to the strings
specified, but really to the given files.
- -s
- --symbolic
- --symbolic-link
- --symlink
- Create symbolic rather than hard links.
Note: On various file or operating systems, this operation
is not supported. Or it is, e.g. by Cygwin, but not understood by native
Windows compilers, if you use one. For a makefile you can't change, to get
at least some sort of result, &ln and
"&cp -l -s" can copy the files for you
instead (not directories though). To achieve this, you need to export the
following variable before calling makepp:
- export
MAKEPP_LN_CP=1
- &ln --resolve or --symbolic will copy the
files instead of creating a symbolic link.
- export
MAKEPP_LN_CP=2
- &ln will copy the files instead of creating a
hard link.
- export
MAKEPP_LN_CP=3
- All invocations of &ln will copy the files
instead of creating either kind of link.
- &mkdir [option ...] directory ...
- Create the directories.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -v,
--verbose"
- -m mode
- --mode=mode
- Sets mode for all created directories, irrespective of the umask.
Mode must be an octal string.
- -p
- --parent
- Also create any necessary parent directories. Ignore directory creation
failure due to the directory already existing (even if it was created
concurrently by another process).
- &mv [option ...] sourcefile destfile
- &mv [option ...] sourcefile
- &mv [option ...] sourcefile ... destdir
- Move or rename sourcefile to destfile, one sourcefile
to current directory or multiple sourcefiles to destdir with
the same name.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -v,
--verbose"
- &preprocess [option ...] variable=definition ... filename
...
- This preprocesses the files exactly the same way makepp does for
makefiles. This is more powerful than
&template but syntactically not suited to
files with lots of "$"-signs, like
Makefiles or scripts.
Conditional statements, as well as the statements
"include"/"_include"
(which here neither build the file nor search upwards),
"perl"/"makeperl"/"perl_begin"
or
"sub"/"makesub",
or any statements you define within the file, are processed. Empty and
comment lines are eliminated.
But, instead of learning build rules, it will output all
remaining lines after "$(...)"
expression expansion. To prevent statement from being recognized as
such, you can precede them with an empty expression
"$()". The same applies to lines you
want to stay empty or which shall retain a leading comment sign.
Likewise, if a trailing backslash is not to join a line with the next,
put "$()" after it.
A normal line gets output as is.
A line with $(MAKEEXPRESSIONS) gets expanded and output.
ifdef WANTTHIS # does not get output whether defined or not
might not get output
endif
include some files
_include some files that might not exist # or -include
$()include empty expression prevents keyword from being recognized.
# Comment lines and empty lines get swallowed.
$()# Unless they get masked with an empty expression.
$()
Empty expression prevents \$()
backslash continuation from being recognized.
might give:
A normal line gets output as is.
A line with whatever gets expanded and output.
lots of slurped in content here...
include empty expression prevents keyword from being recognized.
# Unless they get masked with an empty expression.
Empty expression prevents \
backslash continuation from being recognized.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -o,
--output=filename, -O, --outfail, -S, --synclines, -v,
--verbose"
- -a
- --assignment
- Also treat assignments within the files as makepp would. Alas such lines
can't be masked with an empty "$()",
because it is legal to construct variable names with expressions. This
additionally recognizes the statements
"define",
"export"/"unexport"
and "override" (these can be masked with
"$()").
- -h \\%hash
- --hashref=\\%hash
- This allows preallocation of the variable values, including long ones not
easily passed in a command. The passed expression may be any Perl code
that returns a hash reference. This is merged with any other variables
passed to the command, including from another
"--hashref" option.
- &rm [option ...] filename ...
- Delete files if you have directory write permission. This is what Unix
"rm -f" would delete, since it has a
special protection for interactive use not needed in a Makefile.
"Standard options": "-A,
--args-file, --arguments-file=filename, -v, --verbose"
- -f
- --force
- This prevents complaining about inexistent files. That is a side effect
this option has in Unix, and the only one that makes sense here.
- -m
- --metainfo
- In addition to the given files, this also deletes the meta information
makepp stores about them in the .makepp directory. Thus makepp forgets all
it ever knew about the given files. If the .makepp directory becomes empty
after this, it too is deleted.
This will also delete given directories, but only if they are
empty. To facilitate this, it will delete directories last, in the order of
descending depth. So you can use "**"
expressions to delete whole hierarchies. Here's an example to be found in
many top level make files. Note that there is a
"makeppclean" utility that can do this
more efficiently.
$(phony cleanold):
&rm -fm $(only-stale **/*)
$(phony clean): cleanold
&rm -f $(wildcard **/*.[ao])
$(phony distclean): clean
&rm -fm $(only-targets **/*)
- &sort [option ...] filename ...
- Sorts all files together in lexicographic order. This is inefficient for
rather big files, because it happens completely in memory. It will fail if
the combined size of all files exceeds the memory you are entitled to.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -i,
--inpipe=shellcommand, -I, --infail, -o,
--output=filename, -O, --outfail,
--record-size=number, -s, --separator=string, -v,
--verbose"
- -c perlcode
- --compare=perlcode
- perlcode represents a Perl sort block, with the two sorting
candidates in $a and
$b.
- -n
- --numeric
- --numeric-sort
- This sorts sorts numerically on the beginnings of records. Leading
whitespace is skipped. You can use
"--transform" and
"--detransform" if the numbers are not
at the beginning.
- -r
- --reverse
- Output the results in the reverse order. Note that this hides the standard
option "-r" which must be given as
"--record-size".
- -t perlcode
- --transform=perlcode
- -d perlcode
- --detransform=perlcode
- If you have a complex code, sorting gets more and more expensive in
proportion to the number of records n, because the code gets called
O(n log(n)) times. To avoid that, you can allow Perl to
concentrate on sorting, by first modifying the strings, such that
complicated search criteria extraction happens once per record, and
modifying them back, once they are sorted.
If these options are given, the
"--transform" perlcode gets
mapped to the records in $_ one after another,
and can modify them. After sorting, the
"--detransform" perlcode gets
mapped to the modified records in $_ one after
another, and can modify them back. You will usually use neither or both
of these options, unless you want to output modified lines.
Turning the strings into a structure of extracted sort
criteria, which your "--compare"
perlcode can pick up is known as the Schwartzian Transform (ST).
Packing everything into the string itself, so that no
"--compare" perlcode is needed,
allowing the whole sorting to happen without performing expensive Perl
code, is known as the Guttmann-Rosler Transform (GRT). You can find tips
by searching for those names on the web.
# Expensively sort numerical expressions by value ($$ protects $ from makepp expansion)
&sort --compare 'eval( $$a ) <=> eval( $$b )' $(input) -o >>$(output)
# ST for case insensitive sorting
&sort -t '[lc, $$_]' -c '$$a->[0] cmp $$b->[0]' -d '$$_->[1]' $(input) -o >>$(output)
# GRT using modification functions defined elsewhere in the Makeppfile
&sort -t &transform -d &detransform $(input) -o >>$(output)
- -u
- --uniq
- --unique
- After sorting, eliminate duplicates. These are either identical lines, or
if the "--compare" option is given, ones
which that perlcode reports as equivalent.
- &template [option ...] macro=definition ... filename ...
- This is a macro preprocessor, not quite as powerful as the C preprocessor
or "m4". See
&preprocess for a more powerful alternative.
It was inspired by automake's macro replacement in Makefile.am and
Makefile.in. But it goes beyond that. Any normal text goes through
unchanged. Special constructs are by default delimited with
"@". They must fit on one line unless
you pass one of "-r,
--record-size" or
"--separator".
- @# comment @
- Note that despite borrowing from script
"#" line end comment syntax, this one is
an inline comment.
- @MACRO@
- This construct is replaced by the value of the MACRO. Macro names
must start with a letter or underscore, followed by any number of letters,
underscores, minuses or dots. Unlike in makepp names, underscore and minus
are not equivalent.
- @MACRO(arg1,arg2...)@
- Like the first one, but parametrized. The args replace
$1 through $9 or
"${number}"
in the value. Or, if the value is a Perl function, they are passed as
normal parameters. The result then replaces the whole construct. One level
of macro nesting is possible in that the args in parenthesis may contain
plain "@MACRO@" invocations, as in
"@f(@x@)@", where
"@x@" gets expanded before being
replaced into the body of "f".
- @include(filename)@
- This is the only predefined macro. It is replaced by the
&template-processed content of the named file. Like all macros this
can occur in the middle of a line. Alas, because of that,
"-S, --synclines" ignores the file
inclusion, making everything seem to come from the including file.
- @MACRO=definition@
- @MACRO?=definition@
- This defines a macro within the file. This is replaced by nothing. The
second form only takes effect if the macro was not defined, presumably on
the command line.
- @MACRO { Perlcode }@
- This also defines a macro, the body of which is a Perl sub. The arguments,
if there are any, get passed in as @_.
- @{ Perlcode }@
- This runs the Perlcode immediately and gets replaced by the return
value.
So far we have only seen one syntax for embedding special things.
There is another multiline syntax, and both allow a variation to suppress a
newline. These are the builtin syntaxes (which can be configured by options
below). Here SPECIAL stands for any of the constructs shown
above:
- @SPECIAL@
- @SPECIAL@\
- This can appear multiply anywhere on a line. The variant immediately
followed by "\" only works at the end of
the line. It also replaces the following line break.
- @@SPECIAL@@ Normal text @@
- @@SPECIAL@@ Normal text @@\
- This is like the previous one. However the normal text, which also gets
replaced, can span multiple lines. You can put the special parts on
comment lines around source code that is only needed in an uninstalled
script, to be eliminated or replaced during the installation process:
# @@# the next 2 lines will disappear @@
echo You are running the uninstalled version of this script
# @@
# @@REPLAMCENT@@
echo Something else will be here
# @@
A meaningless example showing the various possibilities:
@m1=some definition@\
@m2=foo $1 bar@\
@middle_of_arg=iddl@\
@m1@ @m2(m@middle_of_arg@e)@
@@m2(many lines)@@
...
@@ plain text 1 + 2 = @{ 1 + 2 }@
becomes
some definition foo middle bar
foo many lines bar plain text 1 + 2 = 3
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force,
-i, --inpipe=shellcommand, -I, --infail, -o, --output=filename, -O,
--outfail, -r, --record-size=number, --separator=string,
-S, --synclines, -v, --verbose"
- -d
- --defined
- Replace only instances of macros which are actually defined. Without this
option the undefined ones will all be replaced by nothing.
- -h \\%hash
- --hashref=\\%hash
- This allows preallocation of the macro values, including long ones not
easily passed in a command. The passed expression may be any Perl code
that returns a hash reference. This is merged with any other macros passed
to the command, including from another
"--hashref" option. A hash value may
also be a code reference, in that case the function gets called, as with
"@macro {
Perlcode
}@" definitions.
- -s /prefix/suffix/
- --simple=/prefix/suffix/
- Use prefix and suffix before and after SPECIAL
respectively instead of "@". The first
character is the separator and need not be a slash. These values are Perl
regexps. You must not introduce grouping like
"(...)", but
"(?:...)" is ok.
- -m /prefix/suffix/afterprefix/[aftersuffix/]
- --multiline=/prefix/suffix/afterprefix/[aftersuffix/]
- Use prefix, suffix and afterprefix before and after
SPECIAL and at the end of the block respectively instead of
"@@". If aftersuffix is also
given, the macro name must get repeated before it. The first character is
the separator and need not be a slash. E.g. an XML-ish, to which you must
add "--defined" if you want to preserve
other tags, not defined by you:
--defined --simple=|<|/>| --multiline=|<|>|</|>|
Or, better, use processing instructions
"<?...?>", intended for such a
purpose:
--defined --simple='|<\?|\?>|'
Or, if you want to combine this with
"&entity;" syntax for the simple
macro replacements (preserving numeric entities
"☺" which are not
comments):
--defined --simple='_(?:&(?!#)|<\?)_(?:;|\?>)_'
- &touch [option ...] filename ...
- Updates the modification and access timestamps of each file to now. If the
file doesn't exist, it gets created.
"Standard options": "-A,
--args-file, --arguments-file=filename, -v, --verbose"
- &uninstall [option ...] [filename ...]
- Uninstall files previously installed by
&install. The filenames are logfiles
written by &install. If none are given, nor an
"--inpipe" option, reads the default
logfile of &install.
"Standard options": "-A,
--args-file, --arguments-file=filename, -i,
--inpipe=shellcommand, -I, --infail, -v,
--verbose"
- &uniq [option ...] filename ...
- Discard all but one of successive equal lines.
"Standard options": "-A,
--args-file, --arguments-file=filename, -f, --force, -i,
--inpipe=shellcommand, -I, --infail, -o,
--output=filename, -O, --outfail, -r,
--record-size=number, -s, --separator=string, -S,
--synclines, -v, --verbose"
- -c perlcode
- --compare=perlcode
- This Perlcode gets the previous and current lines in
$a and $b and shall return
true if it considers the two lines equal.
&uniq --compare='lc( $$a ) eq lc $$b' $(inputs) -o $(output)
Various things are not built in, but can be achieved with other
commands:
- awk
- Use &sed.
- chgrp
- chown
- These commands are mostly not portable! They will either quietly do
nothing or fail, depending on the system. Generally only root may perform
these operations, which is why they are only available through the
&install command.
- cpp
- Use &preprocess or
&template.
- date
- Either of these partially does the same thing:
&expr localtime
&expr gmtime
- false
- Use &expr with no argument or
0.
- head
- tail
- You can achieve the same result with &grep or
"&cut
--lines":
&grep 1..10 file # first ten lines
&grep 10..eof file # all lines from tenth onwards
&cut --lines -10..-1 file # last ten lines
Note that 1..10 in &grep is Perl's
line number flip-flop operator, which annoyingly starts at 1. Don't
start at 0, or the flip-flop will never become true.
- fmt
- This is mentioned here since Perl provides a related functionality.
However I had problems using the
"format" declaration in a makefile. What
does work is the underlying "formline"
function. E.g. to transform a csv file consisting of names and prices to a
tabular format:
sub csv2txt {
formline "\@<<<<<<<<<<<<<<< ^###########.##\n", split ',';
$_ = $^A;
$^A = '';
}
%.txt: %.csv
&sed &csv2txt $(input) -o $(output)
- m4
- Use &preprocess or
&template.
- rmdir
- Use &rm.
- tr
- Use &sed.