Skip to content

Commit

Permalink
mamake: drastically simplify prerequisite scanning (re: 6cc2f6a)
Browse files Browse the repository at this point in the history
The scan() function scans Mamfiles (originally, nmake Makefiles)
for library prerequisites. When recursively building directories,
it is used via a walk() call to sort the leaf directories in the
order that they need to be built.

The scan() code is designed to scan nmake Makefiles and is very
complicated. But since we eliminated nmake and the Makefiles and
now maintain Mamfiles by hand, we now scan Mamfiles. The Makefile
scnaning code somehow worked on the Mamfiles, more by luck than by
judgment; back in January 2021 I did not have this figured out yet.

Scanning Mamfiles is very simple; this sort of processing is what
they are designed for. All the prerequisite information is in
commands like "bind -lfoo" to declare a dependency on libast. Such
a command causes the leaf directory named libfoo to be built first.

src/cmd/INIT/mamake.c:
- Restore libast getopts documentation about prerequisites, removed
  in the referenced commit (because I lacked understanding).
- scan(): Only process "bind" commands in mamfiles, parsing their
  very simple form. Eliminate all the Makefile-related cruft.
  • Loading branch information
McDutchie committed Jan 18, 2024
1 parent 5c02cd4 commit 623c698
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 163 deletions.
20 changes: 17 additions & 3 deletions src/cmd/INIT/README-mamake.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,22 @@ The `exec` command assigns the `generated` attribute to the current rule, even i

`bind` `-l`*libraryname* [ `dontcare` ]

These commands are scanned for while sorting leaf directories for recurive
building, and executed as normal commands while building the current directory.

#### …while scanning and sorting leaf directories ####

If there is a leaf directory named `INIT`, it will always be built before
all others. For all other leaf directories, the presence of any `bind`
command of the form `bind -lfoo` (or `bind +lfoo`) anywhere in a leaf
directory's Mamfile causes the leaf directory named `libfoo` (if it exists)
to be a prerequisite of that leaf directory.
The prerequisite leaf directory does not have to be in the same parent
directory, as long as it is processed as part of the same scan.
At this stage, attributes are ignored.

#### …while building the current directory ####

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*
Expand Down Expand Up @@ -191,7 +207,5 @@ 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.]
is completely different from that described in the original documentation.
188 changes: 28 additions & 160 deletions src/cmd/INIT/mamake.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* coded for portability
*/

#define RELEASE_DATE "2023-04-16"
#define RELEASE_DATE "2024-01-17"
static char id[] = "\n@(#)$Id: mamake (ksh 93u+m) " RELEASE_DATE " $\0\n";

#if _PACKAGE_ast
Expand All @@ -39,7 +39,7 @@ static const char usage[] =
"[-?\n@(#)$Id: mamake (ksh 93u+m) " RELEASE_DATE " $\n]"
"[-author?Glenn Fowler <[email protected]>]"
"[-author?Contributors to https://github.com/ksh93/ksh]"
"[-copyright?(c) 1994-2012 AT&T Intellectual Property]"
"[-copyright?(c) 1994-2013 AT&T Intellectual Property]"
"[-copyright?(c) 2020-2024 Contributors to ksh 93u+m]"
"[-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html]"
"[+NAME?mamake - make abstract machine make]"
Expand Down Expand Up @@ -72,7 +72,10 @@ static const char usage[] =
" executed. Use \b-N\b to disable recursion actions too.]"
"[r:?Recursively make leaf directories matching \apattern\a. Only leaf"
" directories containing a file named \bMamfile\b"
" are considered.]:[pattern]"
" are considered. The \abind\a commands in the Mamfile"
" found in each leaf directory are scanned for leaf directory"
" prerequisites; the recursion order is determined by a topological sort"
" of these prerequisites.]:[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"
Expand Down Expand Up @@ -1954,26 +1957,9 @@ scan(Dict_item_t* item, void* handle)
Rule_t* r = (Rule_t*)item->value;
char* s;
char* t;
char* u;
char* w;
Rule_t* q;
int i;
int j;
int k;
int p;
Buf_t* buf;

static char* files[] =
{
"Mamfile"
/* ksh 93u+m no longer uses these:
* "Nmakefile",
* "nmakefile",
* "Makefile",
* "makefile"
*/
};

/*
* drop non-leaf rules
*/
Expand All @@ -1992,149 +1978,31 @@ scan(Dict_item_t* item, void* handle)
return 0;
}
buf = buffer();
for (i = 0; i < elementsof(files); i++)
append(buf, r->name);
add(buf, '/');
append(buf, mamfile);
if (push(use(buf), NULL, 0))
{
append(buf, r->name);
add(buf, '/');
append(buf, files[i]);
if (push(use(buf), NULL, 0))
while (s = input())
{
while (s = input())
{
j = p = 0;
while (*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')
*s = 0;
if (*s)
*s++ = 0;
if (!t[0])
k = 0;
else if ((t[0] == '-' || t[0] == '+') && t[1] == 'l' && t[2])
{
append(buf, "lib");
append(buf, t + 2);
t = use(buf);
}
else if (p)
{
if (t[0] == '+' && !t[1])
p = 2;
else if (p == 1)
{
if (i != ':' || strncmp(s, "command", 7))
{
append(buf, "lib");
append(buf, t);
t = use(buf);
}
if (i == ':')
while (*s && isspace(*s))
s++;
}
}
else if (i == ':')
{
if (j != ':' || !isupper(*t))
k = 0;
else if (!strcmp(t, "PACKAGE"))
{
p = 1;
k = 0;
}
else
{
for (u = t; *u; u++)
{
if (isupper(*u))
*u = tolower(*u);
else if (!isalnum(*u))
{
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, NULL)) && q != r || *t++ == 'l' && *t++ == 'i' && *t++ == 'b' && *t && (q = (Rule_t*)search(state.leaf, t, NULL)) && q != r))
{
for (t = w = r->name; *w; w++)
if (*w == '/')
t = w + 1;
if (t[0] == 'l' && t[1] == 'i' && t[2] == 'b')
t += 3;
for (u = w = q->name; *w; w++)
if (*w == '/')
u = w + 1;
if (strcmp(t, u))
cons(r, q);
}
j = i;
}
}
pop();
for (s = 0, w = r->name; *w; w++)
if (*w == '/')
s = w;
if (s)
{
if ((s - r->name) > 3 && *(s - 1) == 'b' && *(s - 2) == 'i' && *(s - 3) == 'l' && *(s - 4) != '/')
{
/*
* foolib : foo : libfoo
*/

*(s - 3) = 0;
q = (Rule_t*)search(state.leaf, r->name, NULL);
if (q && q != r)
cons(r, q);
for (t = w = r->name; *w; w++)
if (*w == '/')
t = w + 1;
append(buf, "lib");
append(buf, t);
q = (Rule_t*)search(state.leaf, use(buf), NULL);
if (q && q != r)
cons(r, q);
*(s - 3) = 'l';
}
else if (((s - r->name) != 3 || *(s - 1) != 'b' || *(s - 2) != 'i' || *(s - 3) != 'l') && (*(s + 1) != 'l' || *(s + 2) != 'i' || *(s + 3) != 'b'))
{
/*
* huh/foobar : lib/libfoo
*/

s++;
t = s + strlen(s);
while (--t > s)
{
append(buf, "lib/lib");
appendn(buf, s, t - s);
q = (Rule_t*)search(state.leaf, use(buf), NULL);
if (q && q != r)
cons(r, q);
}
}
}
break;
for (; isspace(*s); s++);
/* examine only commands of the form bind [+-]lfoo */
if (s[0] != 'b' || s[1] != 'i' || s[2] != 'n' || s[3] != 'd' || !isspace(s[4]))
continue;
for (s += 5; isspace(*s); s++);
if ((s[0] != '-' && s[0] != '+') || s[1] != 'l' || !s[2])
continue;
/* construct potential leaf directory name */
append(buf, "lib");
append(buf, s + 2);
t = use(buf);
for (s = t; *s && !isspace(*s); s++);
*s = '\0';
/* add a rule and prepend it onto the prerequisites */
if ((q = (Rule_t*)search(state.leaf, t, NULL)) && q != r)
cons(r, q);
}
pop();
}
drop(buf);
return 0;
Expand Down

0 comments on commit 623c698

Please sign in to comment.