MAKEPP_BUILTINS(1)
β¨ NAME β¨
makepp_builtins β builtin commands in makepp, and bestie they are so good π
π¦ DESCRIPTION π¦
Okay so here's the roster of builtins, alphabetized like a little icon lineup:
- 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's this super special Shell-like thing where you can call built-in commands inside a rule. Not me hyping up the tiny metacharacter list β the only metacharacters it recognizes are comment signs, backslashes, and single and double quotes. You get one command per line, and I/O redirection? Not a thing here (go look at -i and -o below instead, they've got you π«Ά).
These commands all start with &, which is the function character in Perl and not a valid first character in Shell. And here's the plot twist: if no builtin command of that name can be found, that same syntax is also how you call an external script within the Perl instance performing the rule. See run.
These commands β plus your own 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. Newlines get 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. And you can also access these commands stand-alone, e.g. if you need some features that aren't available in the Unix counterpart, via the makeppbuiltin command. obsessed, honestly β¨
These commands are mostly based on the GNU variant. But a lot of 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've been left out. Also, many Unix commands offer a whole variety of options covering 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. the way Perl just ate π
Lists of filenames may be empty, which makes 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.
π Standard options π
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). iykyk
-Afilename,--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=filenameoption if it is to have any effect on that.-ishellcommand,--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--inpipeShell 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. slay cygwin-ofilename,--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--outputShell command fails, that also causes the current builtin to fail.-rnumber,--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.-sstring,--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 $NOlines, 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.
π Builtin commands π
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 to save 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. every filter getting the m4 glow-up, iconic
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. fr fr, don't skip this one
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. sneaky little main character move, we love it π
πΈ &cat πΈ
&cat [option ...] filename ...
Concatenates all the files into a single one. basic but make it flawless
"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 πΈ
&chmod [option ...] mode filename ...
Sets mode for all given files. mode must be an octal string. permissions but make it makepp
"Standard options": -A, --args-file, --arguments-file=filename, -v, --verbose
πΈ &cp πΈ
&cp [option ...] sourcefile destfile
&cp [option ...] sourcefile
&cp [option ...] sourcefile ... destdir
Copy sourcefile to destfile, one sourcefile to the 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.
See the note under &ln. π
πΈ &cut πΈ
&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. tabs vs. nothing, the duality of cut
"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
-clist,--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 Unixcut, the order you request is respected. yes bestie, YOUR order, the way it should be
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β sets a brand new delimiter for your input fields and your output. And here's the tea β: unlike Unixcut, this delimiter can be any length. not just one sad little character. iconic.-E,--noescapeβ treats\as a totally normal literal when you're using-p, --printf=format. no escape interpretation, just vibes.-f list,--fields=listβ prints every group thatlistsays. The list works exactly like the one described under-c, --characters=list. π¨ but bestie, heads up: this option hides the standard-foption, so if you actually want force you have to spell it out as--force. iykyk.-l list,--lines=listβ prints all the lines thatlistasks for. Same list format as-c, --characters=list, with one big plot twist: the first line is number1, and there is no line0. ever. Also π it is definitely inefficient for big files if your list has a mixed positive-to-negative range, because it reads everything into memory. Otherwise Perl could optimize it, but honestly I don't know if it does.-m,--matchingβ prints only the matching lines, i.e. the ones that have enough characters or fields. This implies--only-delimited, which is exactly why you'll miss single-field lines with--fields=0. π-p format,--printf=formatβ appliesformat(with\escapes) to all fields or characters.-s,--only-delimitedβ prints only the lines that actually contain delimiters.
Examples, bestie, so you can see it in the wild:
&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
π the echo / printf / yes trio π
&echo [option ...] string ...
&printf [option ...] format argument ...
&yes [option ...] string ...
These write all their strings to stdout, or to whatever outfile you gave them. Both &echo and &yes tack a newline onto the end. The strings β or, for &printf, the format β may contain \ escapes, the same ones you know from C or modern Unix or Shell echo. BUT π they're actually processed like Perl double-quotes, which means some differences, like the fact that a single trailing \ is not allowed. Perl also has a few extra-fun escapes, and the ones you might expect to behave differently are:
\cAβ is a control character^A.\uβ upcases the following letter.\Uβ upcases the rest, or up to the next\Eor\Lif one shows up.\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 it repeats the output for as long as it possibly can β typically until an --output '| command' terminates it. And if &yes has no arguments, it defaults to y. periodt. π
Standard options: -A, --args-file, --arguments-file=filename, -f, --force, -o, --output=filename, -O, --outfail, -v, --verbose
-E,--noescapeβ treats\as normal literals.-n,--nonewlineβ does not add a newline after the last string. (Not understood by&printf, so don't try it there. π )
β¨ expr β¨
&expr [option ...] perlcode ...
Prints the scalar value of perlcode, which may be written as one argument or several. 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 wanna go with barewords. If the value is false, this fails. And ngl, note that β unlike in Unix expr β Perl's index function starts at 0 (false) and returns -1 (true) for failure. yes, that's real. π
Standard options: -A, --args-file, --arguments-file=filename, -f, --force, -o, --output=filename, -O, --outfail, -v, --verbose
-n,--nonewlineβ do not add a newline after the output.
&expr ($(VAR) - 3) * 2 < 1 && -1 || 1
&expr "$(VAR) - 3 * 2 < 1 ? 'joy' : 'sorrow'" -o $(output)
-&expr $(VAR) - 3 * 2 -o >>$(output)
π¦ grep / perl / sed π¦
&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 basically perl -pe, while &grep only outputs the lines for which perlcode returns a true value. &perl is basically perl -ne, only outputting whatever you explicitly print in the perlcode. The line content lives in $_, which you are absolutely allowed to modify. β¨
Out of these three, only &grep will fail if it outputs nothing. And note: there is no ignore-case option, since you'd just 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--synclinesonly makes sence with&perlif you use&Mpp::Cmds::printto output$_.
Only &grep gets extra options:
-c,--countβ suppresses normal output; instead prints a count of matching lines. With the-v, --invert-matchoption (see below), it counts non-matching lines.-l,--list,--files-with-matchesβ outputs only the name of those files with matches. When this is combined with-v, --invert-match, it outputs the name of files with lines that don't match (a bit absurd, but compatible with Unix-vl). When this is combined with a doubled-vv, it outputs the name of files with no matches at all. π€―-v,--vice-versa,--revert-match,--invert-matchβ inverts the sense of matching, to select non-matching lines. β οΈ Note that this hides the standard-voption, 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 the 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 π
&install [option ...] sourcefile destfile
&install [option ...] sourcefile ... destdir
&install --directory [option ...] directory ...
Moves or renames sourcefile to destfile, or moves multiple sourcefiles to destdir keeping the same name. This is the preferred way of transferring build results to their final installation locations. π
Every single file system modification that &install performs gets logged to the end of the file pointed to by the environment variable $INSTALL_LOG, or β if that isn't set but we're 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 might wanna delete the logfile before a whole series of &install invocations. just saying. π«Ά
Standard options: -A, --args-file, --arguments-file=filename, -v, --verbose
-c,--copyβ copies the files rather than moving them. This is preferable, because 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, creates all the given directories and any necessary parent directories.-g group,--group=groupβ changes the group ownership of the destination files. The group may be given by name or numerically.-l,--linkβ tries to link the files. If that fails, it copies.--log=filename,--logfile=filenameβ usesfilenameinstead of the normal logfile.-m mode,--mode=modeβ sets the mode for all destination files or directories. Mode must be an octal string.-o owner,--owner=ownerβ changes 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 get passed to&lnand are described there.-s,--stripβ calls thestriputility, which must be in the$PATH, on the destination files.
πΈ ln πΈ
&ln [option ...] sourcefile destfile
&ln [option ...] sourcefile
&ln [option ...] sourcefile ... destdir
Links sourcefile to destfile, or one sourcefile into the current directory, or multiple sourcefiles into destdir keeping 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 wantedln -sto do. π₯Ή Creates symbolic rather than hard links, not to the strings specified, but really to the given files.-s,--symbolic,--symbolic-link,--symlinkβ creates symbolic rather than hard links.
okay so real talk about &ln on some file systems or operating systems: the operation just... isn't supported. At all. Or it is supported β hi, Cygwin π β but your native Windows compiler has zero clue what's going on, if that's the compiler you're using. π
So for a makefile you can't change, and you just want some kind of result out of it, &ln and &cp -l -s can copy the files for you instead. Not directories, though β directories are not invited to this party, periodt. To make that work, you need to export the following variable before calling makepp:
export MAKEPP_LN_CP=1
export MAKEPP_LN_CP=1β&lnwith--resolveor--symbolicwill copy the files instead of creating a symbolic link. π¦export MAKEPP_LN_CP=2β&lnwill copy the files instead of creating a hard link. π¦export MAKEPP_LN_CP=3β all invocations of&lnwill copy the files instead of creating either kind of link. π
π &mkdir π
&mkdir [option ...] directory ...
Bestie, it creates the directories. That's the whole vibe. New folders, made fresh, by you, on purpose. β¨
Standard options: -A, --args-file, --arguments-file=filename, -f, --force, -v, --verbose
-m mode--mode=modeβ Sets the mode for all the directories it creates, completely ignoring your umask. And heads up: mode has to be an octal string, no exceptions. π«Ά-p--parentβ Also creates any parent directories that are necessary. And if the directory already exists, it just shrugs it off β no failure, no drama, even if some other process created it at the exact same time. Concurrent queens stay unbothered. π
πΈ &mv πΈ
&mv [option ...] sourcefile destfile
&mv [option ...] sourcefile
&mv [option ...] sourcefile ... destdir
Moves or renames sourcefile to destfile, or moves one sourcefile into the current directory, or moves multiple sourcefiles into destdir keeping the same name. Same energy as Unix mv, but makepp-flavored. π¦
Standard options: -A, --args-file, --arguments-file=filename, -f, --force, -v, --verbose
β &preprocess β
&preprocess [option ...] variable=definition ... filename ...
This one preprocesses your files exactly the same way makepp does for makefiles. Lowkey iconic. It's way more powerful than &template, but ngl it is syntactically not suited to files that are absolutely stuffed with "$"-signs β think Makefiles or scripts. So know what you're feeding it. π
Conditional statements get processed. So do the statements include/_include (which here neither build the file nor search upwards, jsyk), perl/makeperl/perl_begin, sub/makesub, and literally any statement you define inside the file. Empty lines and comment lines? Eliminated. Gone. Poof.
But here's the twist: instead of learning build rules, it outputs all the remaining lines after $(...) expression expansion. And if you don't want a statement to be recognized as a statement, just precede it with an empty expression $(). Same trick applies to lines you want to stay empty, or lines that should keep a leading comment sign. And if a trailing backslash is not supposed to join a line with the next one, put $() after it. Sneaky but effective. π
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 treats assignments within the files the way makepp would. Sadly these lines can't be masked with an empty$(), because it's totally legal to construct variable names with expressions. Sorry bestie, that's just the rules. π This additionally recognizes the statementsdefine,export/unexportandoverride(those ones can be masked with$()). π-h \%hash--hashref=\%hashβ This lets you preallocate the variable values, including long ones that are a pain to pass in a command. The passed expression can be any Perl code that returns a hash reference. It gets merged with any other variables passed to the command β including ones from another--hashrefoption. Merging queens only. π
π &rm π
&rm [option ...] filename ...
Deletes files β but only if you have directory write permission, so mind your permissions, bestie. This is exactly what Unix rm -f would delete, since Unix rm has a special protection for interactive use that honestly just isn't needed inside a Makefile. π¦
Standard options: -A, --args-file, --arguments-file=filename, -v, --verbose
-f--forceβ Stops it from complaining about files that don't exist. That's a side effect this option has in Unix too, and honestly it's the only one that makes sense here. Periodt.-m--metainfoβ On top of the files you named, this also deletes the meta information makepp stores about them inside the.makeppdirectory. So makepp literally forgets everything it ever knew about those files. Memory wiped. And if the.makeppdirectory ends up empty after that, it gets deleted too. π«Ά
This will also delete directories you give it β but only if they're empty. To make that work nicely, it deletes directories last, in order of descending depth. So you can use ** expressions to nuke whole hierarchies. Here's an example you'll find in tons of top level make files. Just note there's a makeppclean utility that can do this way more efficiently. π
$(phony cleanold):
&rm -fm $(only-stale **/*)
$(phony clean): cleanold
&rm -f $(wildcard **/*.[ao])
$(phony distclean): clean
&rm -fm $(only-targets **/*)
π &sort π
&sort [option ...] filename ...
Sorts all the files together in lexicographic order. Fair warning though: this is inefficient for pretty big files, because it happens completely in memory. So if the combined size of all your files exceeds the memory you're entitled to, it will fail. No cap, it will just give up. π
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βperlcodeis a Perl sort block, with the two sorting candidates living in$aand$b. Iconic. β¨-n--numeric--numeric-sortβ This sorts numerically on the beginnings of records. Leading whitespace gets skipped. And if your numbers aren't at the beginning, you can use--transformand--detransformto fix that. π-r--reverseβ Outputs the results in reverse order. But heads up, bestie: this hides the standard option-r, so if you want the standard one you have to write it out as--record-size. Watch out for that trap. π-t perlcode--transform=perlcode-d perlcode--detransform=perlcodeβ If you've got complex code, sorting gets more and more expensive in proportion to the number of recordsn, because the code gets calledO(n log(n))times. To dodge that, you can let Perl concentrate on the actual sorting, by first modifying the strings so the complicated search criteria extraction happens just once per record β and then modifying them back once they're sorted. β¨
If these options are given, the --transform perlcode gets mapped to the records in $_ one after another, and it can modify them. After sorting, the --detransform perlcode gets mapped to the modified records in $_ one after another, and can modify them back. You'll usually use neither or both of these options β unless you actually 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 even needed β letting the whole sorting happen without running 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, it eliminates the duplicates. These are either identical lines, or β if the--compareoption is given β ones that theperlcodereports as equivalent. Two queens, same energy, one gets to stay. π
π¦ &template π¦
&template [option ...] macro=definition ... filename ...
This is a macro preprocessor, not quite as powerful as the C preprocessor or m4. If you want something beefier, go check out &preprocess β that's the more powerful alternative. π«Ά This one was inspired by automake's macro replacement in Makefile.am and Makefile.in β but it goes beyond that, fr fr. Any normal text goes through unchanged. Special constructs are delimited with "@" by default. And they have to fit on one line, unless you pass one of -r, --record-size or --separator. β¨
@# comment @β Note that even though it borrowed the"#"line-end comment syntax from scripts, this one is an inline comment. Sneaky little thing. π@MACRO@β This construct gets replaced by the value of theMACRO. Macro names must start with a letter or underscore, followed by any number of letters, underscores, minuses or dots. And unlike in makepp names, underscore and minus are not equivalent here. So don't get cute with them. π@MACRO(arg1,arg2...)@β Like the first one, but parametrized. The args replace$1through$9or"${number}"in the value. Or, if the value is a Perl function, they get passed as normal parameters. The result then replaces the whole construct. One level of macro nesting is possible, in that the args in the parenthesis may contain plain@MACRO@invocations, like in@f(@x@)@, where@x@gets expanded before being replaced into the body off. π@include(filename)@β okay so this is the only predefined macro, bestie. It gets replaced by the&template-processed content of the named file. And like literally every macro it can sit right in the middle of a line. alas β that's exactly why-S, --synclinesignores the file inclusion, making everything seem to come from the including file instead. π@MACRO=definition@/@MACRO?=definition@β this defines a macro inside the file, and the whole thing gets replaced by nothing. The second form is the shy one: it only takes effect if the macro wasn't already defined, presumably on the command line. β¨@MACRO { Perlcode }@β this also defines a macro, but its body 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. no cap.
So far we've only seen one syntax for embedding special things. There's another multiline syntax, and both allow a variation that suppresses a newline. These are the builtin syntaxes (which can be configured by the 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 β and 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's 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
π the extra &template options
-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 that are not easily passed in a command. The passed expression may be any Perl code that returns a hash reference. It gets merged with any other macros passed to the command, including from another--hashrefoption. 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. Like, an XML-ish one, to which you must add--definedif 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
&touch [option ...] filename ...
Updates the modification and access timestamps of each file to now. If the file doesn't exist, it gets created. main character energy, honestly. β¨
Standard options π«Ά: -A, --args-file, --arguments-file=filename, -v, --verbose
ποΈ &uninstall
&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
&uniq [option ...] filename ...
Discard all but one of successive equal lines. periodt.
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$aand$band shall return true if it considers the two lines equal. π§
&uniq --compare='lc( $$a ) eq lc $$b' $(inputs) -o $(output)
π Emulatable commands
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. π
β¨ AUTHOR β¨
Daniel Pfeiffer (occitan@esperanto.org) β the icon, the moment, the whole vibe. π
and that's a wrap bestie π this page lives in perl v5.32.0, dated 2021-01-06, and it's filed under MAKEPP_BUILTINS(1). go forth and slay those makefiles ππΈ
π¦ where this page comes from
- debian bookworm: makepp 2.0.98.5-2.1
- ubuntu jammy: makepp 2.0.98.5-2.1
- ubuntu noble: makepp 2.0.98.5-2.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms