diff --git a/src/Mamfile b/src/Mamfile index 231122a23e0c..4cdefcf22898 100644 --- a/src/Mamfile +++ b/src/Mamfile @@ -6,7 +6,7 @@ note * Mamfiles are processed by mamake (src/cmd/INIT/mamake.c); we added note * indentation to improve readability. The language is documented in note * src/cmd/INIT/README-mamake.md. note * -setv MAMAKE_SSTRICT +setv MAMAKE_STRICT make test virtual make test_announce virtual exec - : testing KornShell $KSH_VERSION : diff --git a/src/cmd/INIT/Mamfile b/src/cmd/INIT/Mamfile index dcc0b0758004..83ca64d70a9c 100644 --- a/src/cmd/INIT/Mamfile +++ b/src/cmd/INIT/Mamfile @@ -388,13 +388,8 @@ make test dontcare virtual exec - regress iffe.tst iffe done make test.mamake virtual - make mamake.tst - prev mamake.rt - exec - if test mamake.rt -nt mamake.tst - exec - then "$SHELL" "$INSTALLROOT/bin/mktest" --style=regress mamake.rt > mamake.tst - exec - fi - done - exec - : testing mamake as built by package.sh : + prev mamake.tst + exec - : testing non-libast mamake at $PWD/mamake : exec - regress mamake.tst mamake done done test diff --git a/src/cmd/INIT/README-mamake.md b/src/cmd/INIT/README-mamake.md index d3797d947cc6..500cd23f6417 100644 --- a/src/cmd/INIT/README-mamake.md +++ b/src/cmd/INIT/README-mamake.md @@ -27,18 +27,17 @@ whereas `mamake` is simple and portable, and offers all the same flexibility. Compared to the 2012-08-01 AT&T distribution, ksh 93u+m made a number of changes to `mamake` that make it easier to maintain Mamfiles by hand: -* If the `MAMAKE_STRICT` variable is set before any other mamake command is executed, - some backward incompatible changes are activated to facilitate maintainability. +* Introduced a strict mode that activates some backward incompatible changes and deprecation warnings. * All Mamfiles have been indented for legibility. (See `bin/Mamfile_indent` in the distribution.) * Indentation and word separators may use any whitespace (e.g. tabs), not only spaces. * Unrecognized commands and rule attributes throw an error instead of being silently ignored. * Fixed some crashing bugs and memory leaks. * The `silent` and `ignore` command prefixes for shell actions are processed internally - for backward compatibility, unless the `MAMAKE_STRICT` variable is set. + for backward compatibility, except in the strict mode. * The `prev` command may now be used without a prior `make`...`done` to declare a simple - prerequisite, provided the `MAMAKE_STRICT` variable is set. + prerequisite, provided the strict mode is activated. * The `notrace` attribute was added to disable xtrace for a rule's shell action. -* If `MAMAKE_STRICT` is set, appending attributes to the `done` command +* In the strict mode, appending attributes to the `done` command produces a deprecation warning; please append them to `make` instead. * Repeating the rule name in the `done` commnand is now optional so that a simple `done` also works to terminate the current rule. @@ -47,7 +46,7 @@ In addition, the following two simple shell scripts are now provided to aid in maintaining and modernising Mamfiles: * `src/cmd/INIT/utils/Mamfile_indent`: Automatically indent or re-indent a Mamfile. -* `src/cmd/INIT/utils/Mamfile_rm_unused_vars`: Remove unused `setv` variable +* `src/cmd/INIT/utils/Mamfile_rm_unused_vars`: Remove unreferenced `setv` variable definitions from a Mamfile (except `MAMAKE_STRICT`). ## Commands ## @@ -61,10 +60,17 @@ Unrecognized commands or attributes are an error. The *argument* is a single word. The *operand string* is any arbitrary text until the end of the line. +### Strict and legacy modes ### + +If the `MAMAKE_STRICT` variable is set (`setv MAMAKE_STRICT`), +some backward incompatible changes and deprecation warnings +are activated to facilitate human maintenance of the Mamfiles. +We call this the "strict mode" and its absence the "legacy mode". + ### Comments ### `note` is the comment command and is ignored. -For historical reasons, `info` and `meta` are also ignored. +In the legacy mode, `info` and `meta` are also ignored. ### Rules ### @@ -97,16 +103,12 @@ comes with the distribution or a file generated by a previously run Mamfile. One or more *attribute*s may be specified by appending them to the `make` command. (They may also be appended to the `done` command; the effect is the same either way. -This is deprecated and produces a warning if the `MAMAKE_STRICT` variable is defined.) +This is deprecated and produces a warning in the strict mode.) **Attributes apply to the current rule only and do not propagate down to nested rules.** The following *attribute*s are available: -* `archive`: Ignored. - Historically used to mark the generation of an `ar`(1) archive. * `dontcare`: Marks files that do not need to exist. If the file exists then its last-modified timestamp is checked and propagated, otherwise it is silently ignored. -* `generated`: Marks rules that produce output files generated by a shell action. - The `exec` command implicitly assigns this attribute. * `ignore`: The timestamp associated with *rule* is ignored in dependency resolution. * `implicit`: Marks the current rule as an implicit prerequisite of the enclosing parent rule. An implicit prerequisite can make the parent rule out of date without triggering the parent action. @@ -114,14 +116,24 @@ The following *attribute*s are available: For example, if `foo.o` is generated from `foo.c` and `foo.c` includes `foo.h`, then `foo.h` should be marked as an implicit prerequisite of `foo.c` so that touching `foo.h` does not make `foo.c` out of date while making `foo.o` out of date. -* `joint`: Ignored. - Historically used to mark one of a group of rules that are built by a single shell action. * `notrace`: Disables echoing (xtrace) of shell action commands. * `virtual`: Marks a rule that is not associated with any file. The commands within are executed every time the Mamfile is processed. By convention, a virtual rule named `all` makes everything, and a virtual rule named `install` performs installation. +Specifying the following *attribute*s is deprecated +and will produce a warning in the strict mode: +* `archive`: Ignored. + Historically used to mark the generation of an `ar`(1) archive. +* `generated`: Marks rules that produce output files generated by a shell action. + The explicit assignment of this attribute is ignored in the strict mode. + The `exec` command implicitly assigns this attribute. + If a rule has this attribute, other rules dependent on this rule + will avoid applying viewpathing based on this rule. +* `joint`: Ignored. + Historically used to mark one of a group of rules that are built by a single shell action. + ### Referencing prerequisites or previously defined rules ### `prev` *rule* [ *attribute* ... ] @@ -131,12 +143,12 @@ The `prev` command is used in two ways: 1. If *rule* is a previously defined rule, `prev` adds a dependency on that rule to the current rule. This can be used to make a rule a prerequisite of multiple `make`...`done` blocks without repeating the rule. No attributes should be given for this use of `prev`, because the attributes of the referenced rule are used. - Superfluous attributes are an error if the `MAMAKE_STRICT` variable has been set, otherwise they are ignored. + Superfluous attributes are an error in the strict mode and ignored in the legacy mode. 2. If *rule* is not a previously defined rule, the following applies. - If the `MAMAKE_STRICT` variable is not set, `prev` creates an empty dummy + In the legacy mode, `prev` creates an empty dummy *rule* and ignores the *attribute*s; this is for backward compatibility. - If the `MAMAKE_STRICT` variable is set, + In the strict mode, `prev` creates a rule that declares a dependency on a prerequisite file named by *rule* in a manner equivalent to an empty `make`...`done` block, with any *attribute*s given applied to the new rule, and diff --git a/src/cmd/INIT/mamake.c b/src/cmd/INIT/mamake.c index cbf86194054c..57f30883961c 100644 --- a/src/cmd/INIT/mamake.c +++ b/src/cmd/INIT/mamake.c @@ -27,7 +27,7 @@ * coded for portability */ -#define RELEASE_DATE "2024-02-03" +#define RELEASE_DATE "2024-02-04" static char id[] = "\n@(#)$Id: mamake (ksh 93u+m) " RELEASE_DATE " $\0\n"; #if _PACKAGE_ast @@ -257,6 +257,8 @@ typedef struct View_s /* viewpath level */ static struct /* program state */ { + int strict; /* strict mode activated if set */ + Buf_t* buf; /* work buffer */ Buf_t* old; /* dropped buffers */ Buf_t* opt; /* option buffer */ @@ -610,19 +612,6 @@ search(Dict_t* dict, char* name, void* value) return NULL; } -/* - * return true if in strict mode - */ - -static int -strict(void) -{ - static int found = -1; - if (found < 0) - found = search(state.vars, "MAMAKE_STRICT", NULL) != NULL; - return found; -} - /* * low level for walk() */ @@ -1277,7 +1266,7 @@ run(Rule_t* r, char* s) if (x) { /* stubs for backward compat */ - if (!strict()) + if (!state.strict) append(buf, "alias silent=\n" "ignore() { env \"$@\" || :; }\n" @@ -1504,8 +1493,9 @@ attributes(Rule_t* r, char* s) flag = RULE_dontcare; break; case 'g': + /* 'exec' assigns this attribute; ignore explicit assignment in strict mode */ if (n == 9 && !strncmp(t, "generated", n)) - flag = RULE_generated; + flag = state.strict ? -1 : RULE_generated; break; case 'i': if (n == 6 && !strncmp(t, "ignore", n)) @@ -1537,6 +1527,9 @@ attributes(Rule_t* r, char* s) t[n] = '\0'; report(3, "unknown attribute", t, 0); } + /* deprecate ignored attributes */ + else if (state.strict) + report(1, "deprecated", t, 0); } } @@ -1751,12 +1744,12 @@ make(Rule_t* r) if (*t) { /* target is optional; use it for sanity check if present */ q = rule(expand(buf, t)); - if (q != r && (t[0] != '$' || strict())) + if (q != r && (t[0] != '$' || state.strict)) report(3, "mismatched done statement", t, 0); if (*v) { - if (strict()) - report(1, v, "done: attributes are deprecated here, please move them to 'make'", 0); + if (state.strict) + report(1, v, "done: attributes deprecated; move to 'make'", 0); attributes(r, v); } } @@ -1810,7 +1803,7 @@ make(Rule_t* r) case KEY('p','r','e','v'): { char *name = expand(buf, t); - if (!strict()) + if (!state.strict) q = rule(name); /* for backward compat */ else if (!(q = (Rule_t*)search(state.rules, name, NULL))) { /* @@ -1840,6 +1833,8 @@ make(Rule_t* r) continue; } case KEY('s','e','t','v'): + if (strcmp(t, "MAMAKE_STRICT") == 0) + state.strict = 1; if (!search(state.vars, t, NULL)) { if (*v == '"') @@ -1859,11 +1854,14 @@ make(Rule_t* r) probe(); } continue; - case KEY('i','n','f','o'): case KEY('n','o','t','e'): - case KEY('m','e','t','a'): /* comment command */ continue; + case KEY('i','n','f','o'): + case KEY('m','e','t','a'): + if (!state.strict) + continue; + /* FALLTHROUGH */ default: report(3, "unknown command", u, 0); } diff --git a/src/cmd/INIT/mamake.rt b/src/cmd/INIT/mamake.rt index 5f7603d54d62..bbcd54d49662 100644 --- a/src/cmd/INIT/mamake.rt +++ b/src/cmd/INIT/mamake.rt @@ -1,5 +1,17 @@ NOTE regression tests for the mamake command +# To regenerate mamake.tst from this file: +# +# bin/package use +# cd $INSTALLROOT # needed to stop mamake complaining about not being under VPATH +# mktest $PACKAGEROOT/src/cmd/INIT/mamake.rt > $PACKAGEROOT/src/cmd/INIT/mamake.tst +# +# WARNING: the regeneration assumes mamake's output is correct, so VERIFY THE RESULTS! +# Always do 'git diff mamake.tst' to check that no unexpected changes have been made. + +# ====== +# the one original AT&T test -- uses legacy mode + UNIT mamake TEST macros diff --git a/src/lib/libast/Mamfile b/src/lib/libast/Mamfile index e106fe92e03b..8fd989224e54 100644 --- a/src/lib/libast/Mamfile +++ b/src/lib/libast/Mamfile @@ -4999,11 +4999,8 @@ make install virtual done install make test dontcare virtual make test.mamake virtual - make mamake.tst - prev ${PACKAGEROOT}/src/cmd/INIT/mamake.rt - exec - mktest --style=regress ${PACKAGEROOT}/src/cmd/INIT/mamake.rt > mamake.tst - done - exec - : testing the libast rebuild of mamake : - exec - regress mamake.tst mamake + prev ${PACKAGEROOT}/src/cmd/INIT/mamake.tst + exec - : testing the libast rebuild of mamake at $PWD/mamake : + exec - regress ${PACKAGEROOT}/src/cmd/INIT/mamake.tst mamake done done test