a mini make
Inspired by https://github.com/michaelfm1211/ec
Uses a comment block in the source file to specify how to compile it.
(See the m source file for an example of usage.)
The comment type is determined from the file extension (see the function get_comment for the list of recognised extensions - edit to add more!), or may be determined by command line options.
If no extension is given m attempts to discover it by opening the file with known extensions; the order of opening can be overridden by the M_EXT_ORDER environment variable.
If no rules are found then, for some file extensions, m uses an internal default rule.
usage: m [OPTION...] FILE [RULE[;RULE]...]] [ARGUMENTS]...
OPTION:
-h, --help display help
-v, --version display version
--license display license
--readme display readme
-m FILE read rules from a separate FILE
-r, --rules display available rules
-c, --commands display commands executed by rules
-q, --quiet do not display commands as they are executed
-1, --single when expanding multi-command rules,
only multiply expand the first instance
-t, --type define rule sigils according to argument:
TYPE - one of: .c .asm .html .md .sh
-s, --sigils define rule sigils, has the arguments:
COMMENT - the character sequence of an inline comment
RULE - the character sequence indicating a new rule
CONTINUATION - the character sequence indicating the continuation of rule command
AGGREGATION - the character sequence indicating the start of a new rule command
END - the character sequence at the end of a comment line
-D, --define NAME[=REPLACEMENT]
FILE is either a single filename or, 1 or more file names book-ended with the double-character '--'
e.g:
m m.c
or:
m -- *.c --
arguments before the first '--' and after the second '--' apply to all files
if RULE is the single character '-', the first rule is invoked
Specifically, m first scans for a starting line comment, then parses a block of line comments, and stops parsing at a non-comment. For each comment it looks for the following character sequences (after skipping any space/tab characters):
:: Introduces a new rule; there follows an optional rule condition, and then the rule name.
The rule name - which is a sequence of alphanumeric, as well as the _ and -, characters - follows.
This in turn is followed by an optional dependency list. The remainder of the line is the command to be executed.
:+ Appends the remainder of the line to the current rule command.
:& Adds another command to be executed by the rule.
A dependency list consists of one or more of: a colon (:) and a rule name. Dependency rules are executed first.
A rule condition is either a name, a name followed by = and a textual value, or a shell command, followed by either ? or !:
? indicates that the rule is enabled if there is an existing rule or environment variable of the given name, or its value matches the textual value, or the execution of the shell command is succesful.
! indicates that the rule is enabled if there is no existing rule or environment variable of the given name, or its value does not match the textual value, or the execution of the shell command is unsuccesful.
A shell command is a character sequence enclosed by the ( and ) characters.
When a comment definition starts with the ^ character, then rules are processed when the line does not start with the comment character(s).
In this case the entirety of the file is processed for comments instead of stopping after a single block.
This is in effect for files with the .m extension (where the comment character is a single #).
Variables are indicated by the $ character; unlike make, they are not enclosed in parenthesis.
" causes the expansion to be enclosed in quotes.
+ indicates an alternate form of expansion is to be made.
$: expands to the name of the rule - the alternate form appends .exe on Windows.
$! expands to the full file name as passed on the command line - the alternate form replaces the file suffix with .exe on Windows.
$/ expands to the directory path part of the file.
$^ expands to the name of the file - the alternate form appends .exe on Windows.
$. expands to the extension part of the file - the alternate form changes to .exe on Windows.
$$ results in a single $.
The alternate forms can be configured via the following rule/environment/define variables:
M_ALT_RULE for $:
M_ALT_FILE for $!
M_ALT_PATH for $/
M_ALT_NAME for $^
M_ALT_EXT for $.
Alternate expansion is recursive.
$index the numeric index specifies the position of an argument passed on the command line following the rule name, starting from 0.
$* expands all arguments, separating them with spaces. If the quote modifier is given, the arguments are individually quoted.
$[start-index) as above, except the arguments start at the argument index.
$[start-index] effectively the same as $[start-index).
$[start-index-end-index) outputs arguments in the half-open range.
$[start-index-end-index] outputs arguments in the closed range.
Expansion is recursive.
Starting with _ or an alphabetic character, and continuing with -, _ and alphanumeric characters.
m attempts to obtain the value of the corresponding environment variable; if it fails, it is silently omitted, except in the case of $CC, $DBG, $CP, and $RM where it provides a system related default.
Expansion is recursive.
Rules can also be used as variable; when a rule has multiple commands, each command is expanded separately, resulting in multiple command executions.
Rules take precedence over environment variables with the same name.
The special rule - matches any rule name passed on the command line; it should therefore be placed after all other rules that can specified on the command line.
Expansion is recursive.