1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Another build system overhaul (re: 35672208, 580ff616, 6cc2f6a0)

So far we've been handling AST release build and git commit flags
and ksh SHOPT_* compile time options in the generic package build
script. That was a hack that was necessary before I had sufficient
understanding of the build system. Some of it did not work very
well, e.g. the correct git commit did not show up in ${.sh.version}
when compiling from a git repo.

As of this commit, this is properly included in the mamake
dependency tree by handling it from the libast and ksh93 Mamfiles,
guaranteeing they are properly up to date.

For a release build, the _AST_ksh_release macro is renamed to
_AST_release, because some aspects of libast also use this.

This commit also adds my first attempt at documenting the (very
simple, six-command) mamake language as it is currently implemented
-- which is significantly different from Glenn Fowler's original
paper. This is mostly based on reading the mamake.c source code.

src/cmd/INIT/README-mamake.md:
- Added.

bin/package, src/cmd/INIT/package.sh:
- Delete the hack.

**/Mamfile:
- Remove KSH_RELFLAGS and KSH_SHOPTFLAGS, which supported the hack.
- Delete 'meta' commands. They were no-ops; mamake.c ignores them.
  They also did not add any informative value.

src/lib/libast/Mamfile:
- Add a 'virtual' target that obtains the current git commit,
  examines the git branch, and decides whether to auto-set an
  _AST_git_commit and/or or _AST_release #define to a new
  releaseflags.h header file. This is overwritten on each run.
- Add code to the install target that copies limit.h to
  include/ast, but only if it doesn't exist or the content of the
  original changed. This allows '#include <releaseflags.h>' from
  any program using libast while avoiding needless recompiles.
- When there are uncommitted changes, add /MOD (modified) to the
  commit hash instead of not defining it at all.

src/cmd/ksh93/**:
- Mamfile: Add a shopt.h target that reads SHOPT.sh and converts it
  into a new shopt.h header file in the object code directory. The
  shopt.h header only contains SHOPT_* directives that have a value
  in SHOPT.sh (not the empty/probe ones). They also do not redefine
  the macros if they already exist, so overriding with something
  like CCFLAGS+=' -DSHOPT_FOO=1' remains possible.
- **.c: Every c file now #includes "shopt.h" first. So SHOPT_*
  macros are no longer passed via environment/MAM variables.
* SHOPT.sh: The AUDITFILE and CMDLIB_DIR macros no longer need an
  extra backslash-escape for the double quotes in their values.
  (The old way required this because mamake inserts MAM variables
  directly into shell scripts as literals without quoting.  :-/ )

src/cmd/INIT/mamake.c:
- Import the two minor changes between from 93u+ and 93v-: bind()
  is renamed to bindfile() and there is a tweak to detecting an
  "improper done statement".
- Allow arbitrary whitespace (isspace()) everywhere, instead of
  spaces only. This obsoletes my earlier indentation workaround
  from 6cc2f6a0; turns out mamake always supported indentation, but
  with spaces only.
- Do not skip line numbers at the beginning of each line. This
  undocumented feature is not and (AFAICT) never has been used.
- Throw an error on unknown command or rule attribute. Quite an
  important feature for manual maintenance: catches typos, etc.
This commit is contained in:
Martijn Dekker 2022-06-12 05:35:15 +01:00
parent ed5d561a72
commit 148a8a3f46
84 changed files with 1924 additions and 1896 deletions

View file

@ -1,18 +1,15 @@
info mam static 00000 1994-07-17 make (AT&T Research) 5.7 2012-06-20
note *
note * This build file is in the Make Abstract Machine (MAM) language. It was
note * first generated by nmake, but in the ksh 93u+m distribution we maintain
note * it manually because nmake had too many problems to keep using. The
note * Mamfiles are processed by mamake (src/cmd/INIT/mamake.c); we added
note * support for indentation to improve readability. The language is
note * documented in Glenn Fowler's paper "A Make Abstract Machine":
note * http://web.archive.org/web/20041227143022/http://www2.research.att.com/~gsf/mam/mam.html
note * indentation to improve readability. The language is documented in
note * src/cmd/INIT/README-mamake.md.
note *
setv INSTALLROOT ../../..
setv PACKAGEROOT ../../../../..
setv CC cc
setv mam_cc_FLAGS
setv KSH_RELFLAGS
setv CCFLAGS ${-debug-symbols?1?${mam_cc_DEBUG} -D_BLD_DEBUG?${mam_cc_OPTIMIZE}?}
setv CCLDFLAGS ${-strip-symbols?1?${mam_cc_LD_STRIP}??}
setv COTEMP $$
@ -21,7 +18,6 @@ make install
make iffe
make iffe.sh
done iffe.sh
meta iffe %.sh>% iffe.sh iffe
prev iffe.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -58,7 +54,6 @@ make install
make mktest
make mktest.sh
done mktest.sh
meta mktest %.sh>% mktest.sh mktest
prev mktest.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -95,7 +90,6 @@ make install
make package
make package.sh
done package.sh
meta package %.sh>% package.sh package
prev package.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -132,7 +126,6 @@ make install
make regress
make regress.sh
done regress.sh
meta regress %.sh>% regress.sh regress
prev regress.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -169,7 +162,6 @@ make install
make rt
make rt.sh
done rt.sh
meta rt %.sh>% rt.sh rt
prev rt.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -206,7 +198,6 @@ make install
make crossexec
make crossexec.sh
done crossexec.sh
meta crossexec %.sh>% crossexec.sh crossexec
prev crossexec.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -243,7 +234,6 @@ make install
make execrate
make execrate.sh
done execrate.sh
meta execrate %.sh>% execrate.sh execrate
prev execrate.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -280,7 +270,6 @@ make install
make filter
make filter.sh
done filter.sh
meta filter %.sh>% filter.sh filter
prev filter.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -317,7 +306,6 @@ make install
make ignore
make ignore.sh
done ignore.sh
meta ignore %.sh>% ignore.sh ignore
prev ignore.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -357,7 +345,6 @@ make install
make silent
make silent.sh
done silent.sh
meta silent %.sh>% silent.sh silent
prev silent.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -402,16 +389,14 @@ make install
make ast.h implicit
done ast.h dontcare virtual
done mamake.c
meta mamake.o %.c>%.o mamake.c mamake
prev mamake.c
exec - ${CC} ${mam_cc_FLAGS} ${KSH_RELFLAGS} ${CCFLAGS} -c mamake.c
exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -c mamake.c
done mamake.o generated
exec - ${CC} ${CCLDFLAGS} ${mam_cc_FLAGS} ${KSH_RELFLAGS} ${CCFLAGS} ${LDFLAGS} -o mamake mamake.o
exec - ${CC} ${CCLDFLAGS} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} -o mamake mamake.o
done mamake generated
make mprobe
make mprobe.sh
done mprobe.sh
meta mprobe %.sh>% mprobe.sh mprobe
prev mprobe.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -456,7 +441,6 @@ make install
done make.probe
exec - cat C+probe make.probe > probe.sh
done probe.sh generated
meta probe %.sh>% probe.sh probe
prev probe.sh
exec - case static,port:$OPTIND:$RANDOM in
exec - ?*:*:*|*::*|*:*:$RANDOM)
@ -534,7 +518,6 @@ make install
done ${PACKAGEROOT}/bin/ignore generated
make ${PACKAGEROOT}/bin/mamprobe
make mamprobe
meta mamprobe %.sh>% mamprobe.sh mamprobe
make mamprobe.sh
done mamprobe.sh
exec - case static,port:$OPTIND:$RANDOM in
@ -1110,15 +1093,12 @@ make install
done install virtual
make test
make test.iffe
prev iffe
make iffe.tst
done iffe.tst
exec - regress iffe.tst iffe
done test.iffe virtual
make test.mamake
prev mamake
make mamake.tst
meta mamake.tst %.rt>%.tst mamake.rt mamake
make mamake.rt
done mamake.rt
exec - if [[ "1" || "mamake.rt" -nt "mamake.tst" ]]

View file

@ -0,0 +1,176 @@
## mamake and the MAM language ##
MAM (Make Abstract Machine) is a simple rule-based make language
that is implemented in just six four-letter commands and five attributes,
yet allows unlimited flexibility as it can execute arbitrary shell code.
The program implementing MAM, `mamake`,
is a portable C90 program written in a single file, `mamake.c`.
This allows ksh 93u+m,
or other programs using this build system,
to be built using only a standard C compiler and utilities installation
without any other dependencies or complications.
MAM was designed by Glenn Fowler at AT&T.
The [original documentation](http://web.archive.org/web/20041227143022/http://www2.research.att.com/~gsf/mam/mam.html)
for MAM specified a more extensive language than was actually implemented in `mamake.c`,
while the `ignore` attribute is not documented there.
This file documents the MAM implementation that we are actually using.
`mamake` processes make files called `Mamfile`.
These were originally generated by a complex AT&T make system called `nmake`.
The intention was for `mamake` to process generated Mamfiles only
and not for it to replace `make`.
Yet, we are using it as our `make` in the ksh 93u+m distribution.
`nmake` was slow, brittle, and did not work on some modern systems, e.g. macOS.
It was not worth fixing because it is about as complex as ksh itself --
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 few minor changes to `mamake` that make it easier to maintain Mamfiles by hand:
* 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.
### Comments and unrecognized commands ###
MAM commands have the following basic form:
*command* [ *argument* [ *operand string* ] ]
The *command* name consists of four lower-case letters.
Any other command name is an error.
Unrecognized commands or attributes produce a warning and are then ignored.
The first argument is a single word.
The operand string is any arbitrary text until the end of the line.
### Comments ###
`note` is the comment command and is ignored.
For historical reasons, `info` and `meta` are also ignored.
### Rules ###
`make` *rule* [ *attribute* ... ]
`done` *rule* [ *attribute* ... ]
A `make`...`done` block defines the target rule named *rule* using the other commands described here.
Unless the `virtual` attribute is used, *rule* names the pathname of the file generated or referenced by the rule.
Dependencies may be defined in two ways:
1. By nesting `make`...`done` blocks:
the enclosing *rule* is the parent
and the enclosed *rules* are the prerequisites.
2. By using the `prev` command (see **Referencing previously defined rules** below)
to reference a previous `make`...`done` block.
The dependency is defined as if that block were repeated at the `prev` command's location.
If the block contains one or more `exec` commands (see **Shell actions** below),
the `done` command executes the shell script defined by them.
One or more of the following *attribute*s may be specified
by appending them to the `make` or `done` command:
* `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, but it is customary to specify it regardless.
* `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.
Implicit prerequisites usually correspond to `#include` prerequisites.
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.
* `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.
Unrecognized attributes produce a warning and are then ignored.
### Referencing previously defined rules ###
`prev` *rule* [ *attribute* ... ]
This command references a rule that has previously been defined by `make`...`done`,
regardless of block nesting level.
It can be used to make a rule a prerequisite of multiple `make`...`done` blocks without repeating the rule.
By convention, the *attribute*s of the referenced block are repeated in the `prev` command.
However, `mamake` ignores anything after *rule*.
### MAM variables ###
`setv` *variable* [ *defaultvalue* ]
Defines a new MAM *variable*, optionally assigning the initial *defaultvalue*.
If the *defaultvalue* begins and ends with double quotes (`"`), those are discarded.
If the variable already has a value, the `setv` command is ignored; assigning a new value is not possible.
When `mamake` starts, it imports all environment variables as MAM variables,
so any variable's default value can be overridden by exporting an environment variable by its name.
MAM variables are referenced using the sh-style `${`...`}` syntax, though the braces are *not* optional.
Any reference to an undefined variable is silently left unexpanded (and not replaced by the empty string).
Expansion of MAM variable references is recursive, i.e., the value may itself contain other variable references.
Beware: there is no reference loop detection.
[`TODO`: figure out and document advanced expansion syntax supported by `substitute()` in `mamake.c`]
### Shell actions ###
`exec` `-` *code*
One or more `exec` commands within a `make`...`done` block
define a shell script that is executed for *rule*.
The word following `exec` is ignored; by convention it is `-`.
Each `exec` command appends a line of code to the shell script for the current rule.
It is customary for a rule's `exec` commands to be contiguous, but not necessary.
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!).
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`.
The `exec` command assigns the `generated` attribute to the current rule, even if it was not specified.
### Binding libraries ###
`bind` `-l`*libraryname* [ `dontcare` ]
An argument of `-l`*libraryname* (or `+l`*libraryname*)
causes a MAM variable `mam_lib`*libraryname* to be defined (see **MAM variables** above).
The variable will contain either the compiler argument for linking to the library *libraryname*
(either the `-l`*libraryname* flag, or the full path in case of a static library)
or, if the `dontcare` attribute is specified, possibly the empty string.
This can be used both for AST libraries shipped with the distribution and for system libraries.
If the library file is found in the distribution,
its time stamp is checked and the current target is marked as outdated if it is newer.
There is also a mechanism to communicate library dependency information across Mamfiles and `mamake` invocations.
If a file named *libraryname* in the current directory
or an `${INSTALLROOT}/lib/lib/`*libraryname*`.req` file
exists, `mamake` processes each of the words in the form `-l`*libraryname* in its contents
as if they were arguments to `bind` commands
and the resulting values are appended to the value of `mam_lib`*libraryname*
as dependencies separated by spaces.
`mamake` does not create these dependency files;
they are expected to be generated by Mamfile shell actions (see **Shell actions** above).
If no such dependency file exists, and the `dontcare` attribute is added,
then `mamake` compiles a small test program on the fly to check if the library exists;
if this fails, the `mam_lib`*libraryname* variable will be emptied.
Any `bind` command whose argument does not start with `-l` or `+l` is ignored.
[`TODO`: `bind` is not yet fully understood; more `mamake.c` code analysis is required.
In `require()` in `mamake.c` there is some special handling for dynamic libraries.
Note that the `bind` functionality implemented in `mamake.c`
is completely different from that described in the original documentation.]

View file

@ -1,8 +1,8 @@
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1990-2011 AT&T Intellectual Property *
* Copyright (c) 2020-2021 Contributors to ksh 93u+m *
* Copyright (c) 1990-2013 AT&T Intellectual Property *
* Copyright (c) 2020-2022 Contributors to ksh 93u+m *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
@ -27,7 +27,7 @@
* coded for portability
*/
#define RELEASE_DATE "2021-01-21"
#define RELEASE_DATE "2022-06-12"
static char id[] = "\n@(#)$Id: mamake (ksh 93u+m) " RELEASE_DATE " $\0\n";
#if _PACKAGE_ast
@ -70,11 +70,8 @@ static const char usage[] =
"[n:?Print actions but do not execute. Recursion actions (see \b-r\b) are still"
" executed. Use \b-N\b to disable recursion actions too.]"
"[r:?Recursively make leaf directories matching \apattern\a. Only leaf"
" directories containing a makefile named \bNmakefile\b, \bnmakefile\b,"
" \bMakefile\b or \bmakefile\b are considered. The first makefile"
" found in each leaf directory is scanned for leaf directory"
" prerequisites; the recursion order is determined by a topological sort"
" of these prerequisites.]:[pattern]"
" directories containing a file named \bMamfile\b"
" are considered.]:[pattern]"
"[C:?Do all work in \adirectory\a. All messages will mention"
" \adirectory\a.]:[directory]"
"[D:?Set the debug trace level to \alevel\a. Higher levels produce more"
@ -693,6 +690,7 @@ view(void)
{
p = state.pwd + strlen(state.pwd);
while (p > state.pwd)
{
if (*--p == '/')
{
if (p == state.pwd)
@ -707,6 +705,7 @@ view(void)
break;
}
}
}
if (p <= state.pwd)
report(3, "cannot determine viewpath offset", s, (unsigned long)0);
}
@ -873,8 +872,8 @@ substitute(Buf_t* buf, register char* s)
{
if (a && t[0] == 'm' && t[1] == 'a' && t[2] == 'm' && t[3] == '_' && t[4] == 'l' && t[5] == 'i' && t[6] == 'b')
{
for (t = v; *t == ' '; t++);
for (; *t && *t != ' '; t++);
for (t = v; isspace(*t); t++);
for (; *t && !isspace(*t); t++);
if (*t)
*t = 0;
else
@ -990,6 +989,7 @@ find(Buf_t* buf, char* file, struct stat* st)
else
vp = vp->next;
if (vp)
{
do
{
if (node)
@ -1013,6 +1013,7 @@ find(Buf_t* buf, char* file, struct stat* st)
return s;
}
} while (vp = vp->next);
}
}
return 0;
}
@ -1022,7 +1023,7 @@ find(Buf_t* buf, char* file, struct stat* st)
*/
static unsigned long
bind(Rule_t* r)
bindfile(Rule_t* r)
{
char* s;
Buf_t* buf;
@ -1143,10 +1144,7 @@ input(void)
else if (*state.input && *(e = state.input + strlen(state.input) - 1) == '\n')
*e = 0;
state.sp->line++;
e = state.input;
while (isspace(*e))
e++; /* allow indentation */
return e;
return state.input;
}
/*
@ -1242,9 +1240,9 @@ run(Rule_t* r, register char* s)
i = 2;
else
{
for (i = 3; *(t + i) == ' ' || *(t + i) == '\t'; i++);
for (i = 3; isspace(*(t + i)); i++);
*s = c;
for (s = t + i; *s && *s != ' ' && *s != '\t' && *s != '\n'; s++);
for (s = t + i; *s && !isspace(*s); s++);
c = *s;
*s = 0;
append(buf, t + 2);
@ -1315,7 +1313,7 @@ path(Buf_t* buf, char* s, int must)
int o;
Stat_t st;
for (e = s; *e && *e != ' ' && *e != '\t'; e++);
for (e = s; *e && !isspace(*e); e++);
t = *e;
if ((x = status(buf, 0, s, &st)) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
return x;
@ -1416,30 +1414,46 @@ attributes(register Rule_t* r, register char* s)
for (;;)
{
for (; *s == ' '; s++);
for (t = s; *s && *s != ' '; s++);
int flag = 0;
for (; isspace(*s); s++);
for (t = s; *s && !isspace(*s); s++);
if (!(n = s - t))
break;
switch (*t)
{
case 'd':
if (n == 8 && !strncmp(t, "dontcare", n))
r->flags |= RULE_dontcare;
flag = RULE_dontcare;
break;
case 'g':
if (n == 9 && !strncmp(t, "generated", n))
r->flags |= RULE_generated;
flag = RULE_generated;
break;
case 'i':
if (n == 6 && !strncmp(t, "ignore", n))
r->flags |= RULE_ignore;
flag = RULE_ignore;
else if (n == 8 && !strncmp(t, "implicit", n))
r->flags |= RULE_implicit;
flag = RULE_implicit;
break;
case 'v':
if (n == 7 && !strncmp(t, "virtual", n))
r->flags |= RULE_virtual;
flag = RULE_virtual;
break;
case 'a':
if (n == 7 && !strncmp(t, "archive", n))
flag = -1; /* ignore (not implemented) */
break;
case 'j':
if (n == 5 && !strncmp(t, "joint", n))
flag = -1; /* ignore (not implemented) */
break;
}
if(flag > 0)
r->flags |= flag;
else if(flag == 0)
{
t[n] = '\0';
report(3, "unknown attribute", t, (unsigned long)0);
}
}
}
@ -1521,13 +1535,13 @@ require(char* lib, int dontcare)
{
for (;;)
{
while ((c = fgetc(f)) == ' ' || c == '\t' || c == '\n');
while (isspace(c = fgetc(f)));
if (c == EOF)
break;
do
{
add(tmp, c);
} while ((c = fgetc(f)) != EOF && c != ' ' && c != '\t' && c != '\n');
} while ((c = fgetc(f)) != EOF && !isspace(c));
s = use(tmp);
if (s[0] && (s[0] != '-' || s[1]))
{
@ -1591,7 +1605,7 @@ make(Rule_t* r)
state.active++;
if (*r->name)
{
z = bind(r);
z = bindfile(r);
state.indent++;
report(-1, r->name, "make", r->time);
}
@ -1599,29 +1613,38 @@ make(Rule_t* r)
z = 0;
buf = buffer();
cmd = 0;
/*
* Parse lines
*/
while (s = input())
{
for (; *s == ' '; s++);
for (; isdigit(*s); s++);
for (; *s == ' '; s++);
for (u = s; *s && *s != ' '; s++);
/* skip initial whitespace and empty line */
for (; isspace(*s); s++);
if (!*s)
continue;
/* isolate command name (u), argument word (t), and the operand string (v) */
for (u = s; *s && !isspace(*s); s++);
if (*s)
{
for (*s++ = 0; *s == ' '; s++);
for (t = s; *s && *s != ' '; s++);
for (*s++ = 0; isspace(*s); s++);
for (t = s; *s && !isspace(*s); s++);
if (*s)
for (*s++ = 0; *s == ' '; s++);
for (*s++ = 0; isspace(*s); s++);
v = s;
}
else
t = v = s;
/* enforce 4-letter lowercase command name */
if(u[0]<'a' || u[0]>'z' || u[1]<'a' || u[1]>'z' || u[2]<'a' || u[2]>'z' || u[3]<'a' || u[3]>'z' || u[4] && !isspace(u[4]))
report(3, "not a command name", u, (unsigned long)0);
switch (KEY(u[0], u[1], u[2], u[3]))
{
case KEY('b','i','n','d'):
if ((t[0] == '-' || t[0] == '+') && t[1] == 'l' && (s = require(t, !strcmp(v, "dontcare"))) && strncmp(r->name, "FEATURE/", 8) && strcmp(r->name, "configure.h"))
{
for (;;)
{
for (t = s; *s && *s != ' '; s++);
for (t = s; *s && !isspace(*s); s++);
if (*s)
*s = 0;
else
@ -1630,7 +1653,7 @@ make(Rule_t* r)
{
q = rule(expand(buf, t));
attributes(q, v);
x = bind(q);
x = bindfile(q);
if (z < x)
z = x;
if (q->flags & RULE_error)
@ -1638,12 +1661,13 @@ make(Rule_t* r)
}
if (!s)
break;
for (*s++ = ' '; *s == ' '; s++);
for (*s++ = ' '; isspace(*s); s++);
}
}
continue;
case KEY('d','o','n','e'):
q = rule(expand(buf, t));
if (q != r)
if (q != r && t[0] != '$')
report(2, "improper done statement", t, (unsigned long)0);
attributes(r, v);
if (cmd && state.active && (state.force || r->time < z || !r->time && !z))
@ -1726,8 +1750,13 @@ make(Rule_t* r)
probe();
}
continue;
default:
case KEY('i','n','f','o'):
case KEY('n','o','t','e'):
case KEY('m','e','t','a'):
/* comment command */
continue;
default:
report(3, "unknown command", u, (unsigned long)0);
}
break;
}
@ -1863,8 +1892,8 @@ scan(Dict_item_t* item, void* handle)
j = p = 0;
while (*s)
{
for (k = 1; (i = *s) == ' ' || i == '\t' || i == '"' || i == '\''; s++);
for (t = s; (i = *s) && i != ' ' && i != '\t' && i != '"' && i != '\'' && i != '\\' && i != ':'; s++)
for (k = 1; isspace(i = *s) || i == '"' || i == '\''; s++);
for (t = s; (i = *s) && !isspace(i) && i != '"' && i != '\'' && i != '\\' && i != ':'; s++)
if (i == '/')
t = s + 1;
else if (i == '.' && *(s + 1) != 'c' && *(s + 1) != 'C' && *(s + 1) != 'h' && *(s + 1) != 'H' && t[0] == 'l' && t[1] == 'i' && t[2] == 'b')
@ -1892,7 +1921,7 @@ scan(Dict_item_t* item, void* handle)
t = use(buf);
}
if (i == ':')
while (*s && (*s == ' ' || *s == '\t'))
while (*s && isspace(*s))
s++;
}
}
@ -1906,7 +1935,9 @@ scan(Dict_item_t* item, void* handle)
k = 0;
}
else
{
for (u = t; *u; u++)
{
if (isupper(*u))
*u = tolower(*u);
else if (!isalnum(*u))
@ -1914,16 +1945,22 @@ scan(Dict_item_t* item, void* handle)
k = 0;
break;
}
}
}
}
else if (t[0] != 'l' || t[1] != 'i' || t[2] != 'b')
k = 0;
else
{
for (u = t + 3; *u; u++)
{
if (!isalnum(*u))
{
k = 0;
break;
}
}
}
if (k && ((q = (Rule_t*)search(state.leaf, t, NiL)) && q != r || *t++ == 'l' && *t++ == 'i' && *t++ == 'b' && *t && (q = (Rule_t*)search(state.leaf, t, NiL)) && q != r))
{
for (t = w = r->name; *w; w++)
@ -2319,7 +2356,9 @@ main(int argc, char** argv)
*/
for (e = environ; s = *e; e++)
{
for (t = s; *t; t++)
{
if (*t == '=')
{
*t = 0;
@ -2327,6 +2366,8 @@ main(int argc, char** argv)
*t = '=';
break;
}
}
}
/*
* grab the command line targets and variable definitions
@ -2335,6 +2376,7 @@ main(int argc, char** argv)
while (s = *argv++)
{
for (t = s; *t; t++)
{
if (*t == '=')
{
v = t + 1;
@ -2351,6 +2393,7 @@ main(int argc, char** argv)
*t = c;
break;
}
}
if (!*t)
{
/*

View file

@ -109,7 +109,7 @@ command=${0##*/}
case $(getopts '[-][123:xyz]' opt --xyz 2>/dev/null; echo 0$opt) in
0123) USAGE=$'
[-?
@(#)$Id: '$command$' (ksh 93u+m) 2022-02-24 $
@(#)$Id: '$command$' (ksh 93u+m) 2022-06-12 $
]
[-author?Glenn Fowler <gsf@research.att.com>]
[-author?Contributors to https://github.com/ksh93/ksh]
@ -674,45 +674,6 @@ case $CC in
*) export CC ;;
esac
# Add build type flags via KSH_RELFLAGS, which is used in src/cmd/ksh93/Mamfile.
# (Avoid using CCFLAGS; setting it would overwrite autodetected optimization flags.)
ksh_relflags=
case $(git branch 2>/dev/null) in
'' | *\*\ [0-9]*.[0-9]*)
# If we're not on a git branch (tarball) or on a branch that starts
# with a number (release branch), then compile as a release version
ksh_relflags="${ksh_relflags:+$ksh_relflags }-D_AST_ksh_release" ;;
*) # Otherwise, add 8-character git commit hash if available, and if the working dir is clean
git_commit=$(git status >/dev/null 2>&1 && git diff-index --quiet HEAD && git rev-parse --short=8 HEAD)
case $git_commit in
????????)
ksh_relflags="${ksh_relflags:+$ksh_relflags }-D_AST_git_commit=\\\"$git_commit\\\"" ;;
esac
unset git_commit ;;
esac
case $ksh_relflags in
?*) # add the extra flags as an argument to mamake
assign="${assign:+$assign }KSH_RELFLAGS=\"\$ksh_relflags\"" ;;
esac
# Add ksh compile-options via KSH_SHOPTFLAGS.
SHOPT()
{
case $1 in
*=?*) ksh_shoptflags="${ksh_shoptflags:+$ksh_shoptflags }-DSHOPT_$1" ;;
esac
}
ksh_shoptflags=
shopt_sh='src/cmd/ksh93/SHOPT.sh' # this script calls SHOPT() to set options
if test -f "$shopt_sh"
then . "$shopt_sh"
else echo "WARNING: $shopt_sh is missing" >&2
fi
case $ksh_shoptflags in
?*) # add the extra flags as an argument to mamake
assign="${assign:+$assign }KSH_SHOPTFLAGS=\"\$ksh_shoptflags\"" ;;
esac
# grab action specific args
case $action in
@ -3149,7 +3110,7 @@ cat $j $k
# check against previous compiler and flags
err=
for var in CC CCFLAGS CCLDFLAGS LDFLAGS KSH_RELFLAGS
for var in CC CCFLAGS CCLDFLAGS LDFLAGS
do store=$INSTALLROOT/lib/package/gen/$var
eval "new=\$$var"
if test -f $store