Skip to content

Commit

Permalink
mamake: add 4 "automatic variables" to reduce Mamfile redundancy
Browse files Browse the repository at this point in the history
This is another step towards making the build system easier to
maintain. The following special MAM variables are now set and
updated automatically. They are inspired by similar automatic
variables in make implementations, but since mamake is different,
so are these variables.

${@} is the name of the rule currently being made.

${<} is the name of the prerequisite rule (make...done or prev)
that was *last* processed within the current rule.

${^} is a space-separated list of names of all the current rule's
previously processed prerequisites.

${?} is a space-separate list of the current rule's previously
processed prerequisites that have been updated by a shell action
during the current mamake run. Prequisites that were already up to
date, or prerequisites that do not contain a shell action, are not
included.

*/*/Mamfile:
- Use the automatic variables to eliminate repetitive values (the
  single-source-of-truth principle). Many rules are now identical
  except for their rule name and prerequisites, showing the need
  for another new mamake feature that would make it possible to
  further reduce redundancy -- to come soon.

src/cmd/INIT/mamake.c:
- For ${?} we need to keep track of whether a rule was updated by a
  shell action during this run. Add a RULE_updated flag for this.

- Declare global pointers to the automatic variable nodes.

- Amend duplicate() to make it easy to reallocate a string using
  realloc(), with an optimisation that avoids allocating memory for
  the empty string; this works by declaring a global constant
  'empty' pointer to an empty string and comparing value pointers
  to that before freeing them. The realloc version is called
  reduplicate().

- Amend search() to return the pointer to the node (root), not the
  node name (root->name), if a value was given. Only one call in
  rule() used the root->name return value, so that's easy to fix.

- main():  Create the global automatic variable nodes while
  initialising the global pointers to them, which is made possible
  by the previous change. Set their initial values to the
  unallocated empty string. Their ->value pointers are never NULL.

- Add a tweak to substitute() to allow '?' as the first character
  of a variable name without interpreting it as an operator; ${?}
  is not possible without it.

- In make(), when processing 'exec', expand variables immediately
  upon collecting each line of script and don't wait with expanding
  them until 'done' when executing the script. This avoids getting
  confusing values of ${<}, ${^} and ${?}.

- make(): For 'make' and 'prev', save, set and restore the
  automatic variables as required by their expected function.
  - Saving and restoring pointers on the C stack is needed to make
    nested rules do the right thing; nesting corresponds with
    make() call recursion, so that's easy.
  - The initialisation of the nodes in main() makes it possible to
    address the global node pointers directly without any repeated
    search() calls.
  - The new reduplicate() function makes it convenient to
    free/reallocate values.
  • Loading branch information
McDutchie committed Feb 12, 2024
1 parent 5a53e00 commit fea5419
Show file tree
Hide file tree
Showing 9 changed files with 1,357 additions and 1,250 deletions.
72 changes: 36 additions & 36 deletions src/cmd/INIT/Mamfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,73 +20,73 @@ note *
make install virtual
make iffe
prev iffe.sh
exec - ${STDCP} iffe.sh iffe && ${STDCHMOD} u+w,+x iffe
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
make mktest
prev mktest.sh
exec - ${STDCP} mktest.sh mktest && ${STDCHMOD} u+w,+x mktest
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
make regress
prev regress.sh
exec - ${STDCP} regress.sh regress && ${STDCHMOD} u+w,+x regress
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
make crossexec
prev crossexec.sh
exec - ${STDCP} crossexec.sh crossexec && ${STDCHMOD} u+w,+x crossexec
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
make mkreq
prev mkreq.sh
exec - ${STDCP} mkreq.sh mkreq && ${STDCHMOD} u+w,+x mkreq
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
make mkreq-maplib
prev mkreq-maplib.sh
exec - ${STDCP} mkreq-maplib.sh mkreq-maplib && ${STDCHMOD} u+w,+x mkreq-maplib
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
make mprobe
prev mprobe.sh
exec - ${STDCP} mprobe.sh mprobe && ${STDCHMOD} u+w,+x mprobe
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
make probe
make probe.sh
prev C+probe
prev make.probe
exec - ${STDCAT} C+probe make.probe > probe.sh
exec - ${STDCAT} ${^} > ${@}
done
exec - ${STDCP} probe.sh probe && ${STDCHMOD} u+w,+x probe
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
make ${INSTALLROOT}/bin
exec - mkdir -p ${INSTALLROOT}/bin
exec - mkdir -p ${@}
done
make ${INSTALLROOT}/bin/iffe
prev iffe
exec - ${STDCP} -f iffe ${INSTALLROOT}/bin/iffe
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/bin/mkreq
prev mkreq
exec - ${STDCP} -f mkreq ${INSTALLROOT}/bin/mkreq
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/bin/mktest
prev mktest
exec - ${STDCP} -f mktest ${INSTALLROOT}/bin/mktest
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/bin/regress
prev regress
exec - ${STDCP} -f regress ${INSTALLROOT}/bin/regress
exec - ${STDCP} -f ${<} ${@}
done
make ${PACKAGEROOT}/bin
exec - mkdir -p ${PACKAGEROOT}/bin
done
make ${INSTALLROOT}/bin/crossexec
prev crossexec
exec - ${STDCP} -f crossexec ${INSTALLROOT}/bin/crossexec
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/bin/proto
note *
note * proto(1) has been removed, but install a backward compatibility stub
note * that allows old Mamfiles containing proto commands to keep working.
note *
prev proto.sh
exec - ${STDCP} proto.sh ${INSTALLROOT}/bin/proto && ${STDCHMOD} u+w,+x ${INSTALLROOT}/bin/proto
exec - ${STDCP} ${<} ${@} && ${STDCHMOD} u+w,+x ${@}
done
note *
note * ksh93 function search on PATH
Expand Down Expand Up @@ -229,38 +229,38 @@ make install virtual
note * probe initialization
note *
make ${INSTALLROOT}/lib/probe/C
exec - mkdir -p ${INSTALLROOT}/lib/probe/C
exec - mkdir -p ${@}
done
make ${INSTALLROOT}/lib/probe/C/probe
prev C+probe
exec - ${STDCP} -f C+probe ${INSTALLROOT}/lib/probe/C/probe
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/lib/probe/C/make
exec - mkdir -p ${INSTALLROOT}/lib/probe/C/make
exec - mkdir -p ${@}
done
make ${INSTALLROOT}/lib/probe/C/pp
exec - mkdir -p ${INSTALLROOT}/lib/probe/C/pp
exec - mkdir -p ${@}
done
make ${INSTALLROOT}/lib/probe/C/mam
exec - mkdir -p ${INSTALLROOT}/lib/probe/C/mam
exec - mkdir -p ${@}
done
make ${INSTALLROOT}/lib/probe/C/mam/probe
prev mprobe
exec - ${STDCP} -f mprobe ${INSTALLROOT}/lib/probe/C/mam/probe
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/lib/probe/C/mam/mprobe
prev mprobe
exec - ${STDCP} -f mprobe ${INSTALLROOT}/lib/probe/C/mam/mprobe
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/lib/probe/C/make/probe
prev probe
exec - ${STDCP} -f probe ${INSTALLROOT}/lib/probe/C/make/probe
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/include/ast
exec - mkdir -p ${INSTALLROOT}/include/ast
exec - mkdir -p ${@}
done
make ${INSTALLROOT}/lib/lib
exec - mkdir -p ${INSTALLROOT}/lib/lib
exec - mkdir -p ${@}
done
note *
note * check if -ldl is required
Expand All @@ -277,7 +277,7 @@ make install virtual
prev mkreq-maplib
exec - mkreq-maplib ${CC} : dl : dl.c : dl
done
exec - ${STDCP} -f dl.req ${INSTALLROOT}/lib/lib/dl
exec - ${STDCP} -f ${<} ${@}
done
note *
note * requiring these is a botch
Expand All @@ -288,7 +288,7 @@ make install virtual
prev mkreq-maplib
exec - mkreq-maplib ${CC} : iconv : iconv.c : iconv
done
exec - ${STDCP} -f iconv.req ${INSTALLROOT}/lib/lib/iconv
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/lib/lib/w
make w.req
Expand All @@ -297,7 +297,7 @@ make install virtual
prev mkreq-maplib
exec - mkreq-maplib ${CC} : w : w.c w2.c : w
done
exec - ${STDCP} -f w.req ${INSTALLROOT}/lib/lib/w
exec - ${STDCP} -f ${<} ${@}
done
note *
note * miscellaneous -l* checks
Expand All @@ -308,7 +308,7 @@ make install virtual
prev mkreq-maplib
exec - mkreq-maplib ${CC} : intl : intl.c : intl
done
exec - ${STDCP} -f intl.req ${INSTALLROOT}/lib/lib/intl
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/lib/lib/m
make m.req
Expand All @@ -321,15 +321,15 @@ make install virtual
prev mkreq-maplib
exec - mkreq-maplib ${CC} : m : m.c m2.c m3.c m4.c m5.c m6.c : m
done
exec - ${STDCP} -f m.req ${INSTALLROOT}/lib/lib/m
exec - ${STDCP} -f ${<} ${@}
done
make ${INSTALLROOT}/lib/lib/nsl
make nsl.req
prev nsl.c
prev mkreq-maplib
exec - mkreq-maplib ${CC} : nsl : nsl.c : nsl
done
exec - ${STDCP} -f nsl.req ${INSTALLROOT}/lib/lib/nsl
exec - ${STDCP} -f ${<} ${@}
done
note *
note * what was sco smoking
Expand All @@ -344,7 +344,7 @@ make install virtual
prev mkreq-maplib
exec - mkreq-maplib ${CC} : socket : socket.c nsl.c : socket
done
exec - ${STDCP} -f socket.req ${INSTALLROOT}/lib/lib/socket
exec - ${STDCP} -f ${<} ${@}
done
note *
note * more substance abuse
Expand All @@ -367,17 +367,17 @@ make install virtual
prev mkreq-maplib
exec - mkreq-maplib ${CC} : dbm : db.c gdbm.c gdbm1.c gdbm2.c : db gdbm_compat gdbm ndbm dbm
done
exec - ${STDCP} -f dbm.req ${INSTALLROOT}/lib/lib/dbm
exec - ${STDCP} -f ${<} ${@}
done
done install
make test dontcare virtual
make test.iffe virtual
prev iffe.tst
exec - regress iffe.tst iffe
exec - regress ${<} iffe
done
make test.mamake virtual
prev mamake.tst
exec - : testing non-libast mamake at $PWD/mamake :
exec - regress mamake.tst mamake
exec - regress ${<} mamake
done
done test
29 changes: 26 additions & 3 deletions src/cmd/INIT/README-mamake.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ ksh 93u+m made a number of changes to `mamake` that make it easier to maintain M
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.
* The automatic variables `${@}`, `${<}`, `${^}` and `${?}` have been added.

In addition, the following two simple shell scripts are now provided to aid
in maintaining and modernising Mamfiles:
Expand Down Expand Up @@ -175,6 +176,25 @@ Beware: there is no reference loop detection.

[`TODO`: figure out and document advanced expansion syntax supported by `substitute()` in `mamake.c`]

#### Automatic variables ####

The following variables are set and updated automatically.
They are inspired by similar variables in `make` implementations,
but since `mamake` is different, so are these variables.

`${@}` is the name of the rule currently being made.

`${<}` is the name of the prerequisite rule (`make``done` or `prev`)
that was *last* processed within the current rule.

`${^}` is a space-separated list of names of all the current rule's
previously processed prerequisites.

`${?}` is a space-separate list of the current rule's previously processed
prerequisites that have been updated by a shell action (see `exec` below)
during the current `mamake` run. Prequisites that were already up to date,
or prerequisites that do not contain a shell action, are not included.

### Shell actions ###

`exec` `-` *code*
Expand All @@ -189,6 +209,9 @@ Before adding each line of code to the script,
MAM variable references (see **MAM variables** above)
are expanded; their literal values are inserted into the *code* line
(beware: no quoting is applied!).
Because variables are expanded when the line is encountered, the value
of the automatic variables for any `exec` line depends on the position
of the line in the rule.

After MAM variable expansion, viewpathing is applied: each word
(separated by space, tab, newline, `;`, `(`, `)`, `` ` ``, `|`, `&` or `=`)
Expand All @@ -200,9 +223,9 @@ When `mamake` encounters the `done` command,
the script is executed by the shell whose path is in the `SHELL` environment variable
or, absent that, by `/bin/sh`.
Before executing the script, a trace header in the following format is added to the log:
```
# path/to/Mamfile: startline-endline: rule
```

# path/to/Mamfile: startline-endline: rule

During script execution, shell action comands are traced using the
shell's xtrace option, unless the rule has the `notrace` attribute.

Expand Down
Loading

0 comments on commit fea5419

Please sign in to comment.