Implement SysV-style $$@ support. I looked at E.Parmelan's patch but

decided to implement this a different way, and didn't use it.
This commit is contained in:
Paul Smith 2002-07-10 12:59:07 +00:00
parent 6c9a393f95
commit 4d72c4c11e
9 changed files with 233 additions and 40 deletions

View File

@ -1,3 +1,18 @@
2002-07-10 Paul D. Smith <psmith@gnu.org>
Implement the SysV make syntax $$@, $$(@D), and $$(@F) in the
prerequisite list. A real SysV make will expand the entire
prerequisites list _twice_: we don't do that as it's a big
backward-compatibility problem. We only replace those specific
variables.
* read.c (record_files): Replace any $@, $(@D), and $(@F) variable
references left in the list of prerequisites. Check for .POSIX as
we record targets, so we can disable non-POSIX behavior while
reading makefiles as well as running them.
(eval): Check the prerequisite list to see if we have anything
that looks like a SysV prerequisite variable reference.
2002-07-09 Paul D. Smith <psmith@gnu.org>
* doc/make.texi (Prerequisite Types): Add a new section describing

11
NEWS
View File

@ -1,6 +1,6 @@
GNU make NEWS -*-indented-text-*-
History of user-visible changes.
06 July 2002
10 July 2002
Copyright (C) 2002 Free Software Foundation, Inc.
See the end for copying conditions.
@ -12,7 +12,7 @@ Please send GNU make bug reports to <bug-make@gnu.org>.
See the README file and the GNU make manual for details on sending bug
reports.
Version <next>
Version 3.80
* A new feature exists: order-only prerequisites. These prerequisites
affect the order in which targets are built, but they do not impact
@ -21,6 +21,13 @@ Version <next>
requiring that target A will always be rebuilt if target B is updated.
Patch for this feature provided by Greg McGary <greg@mcgary.org>.
* For compatibility with SysV make, GNU make now supports the peculiar
syntax $$@, $$(@D), and $$(@F) in the prerequisites list of a rule.
This syntax is only valid within explicit and static pattern rules: it
cannot be used in implicit (suffix or pattern) rules. Edouard G. Parmelan
<egp@free.fr> provided a patch implementing this feature; however, I
decided to implemented it myself in a different way.
* A new function is defined: $(quote ...). The argument to this
function is the _name_ of a variable. The result of the function is
the value of the variable, without having been expanded.

View File

@ -8410,6 +8410,16 @@ part of the first prerequisite.
Lists of the directory parts and the file-within-directory
parts of all prerequisites.
@vindex $(+D)
@vindex +D @r{(automatic variable)}
@item $(+D)
@vindex $(+F)
@vindex +F @r{(automatic variable)}
@itemx $(+F)
Lists of the directory parts and the file-within-directory
parts of all prerequisites, including multiple instances of duplicated
prerequisites.
@vindex $(?D)
@vindex ?D @r{(automatic variable)}
@item $(?D)
@ -8429,6 +8439,32 @@ deep significance; @samp{$<} refers to the variable named @code{<} just
as @samp{$(CFLAGS)} refers to the variable named @code{CFLAGS}.
You could just as well use @samp{$(<)} in place of @samp{$<}.
@vindex $$@@
@vindex $$(@@D)
@vindex $$(@@F)
@cindex $$@@, support for
GNU @code{make} provides support for the SysV @code{make} feature that
allows special variable references @code{$$@@}, @code{$$(@@D)}, and
@code{$$(@@F)} (note the required double-''$''!) to appear with the
@emph{prerequisites list} (normal automatic variables are available
only within a command script). When appearing in a prerequisites
list, these variables are expanded to the name of the target, the
directory component of the target, and the file component of the
target, respectively.
Note that these variables are available only within explicit and
static pattern (@pxref{Static Pattern, ,Static Pattern Rules}) rules;
they have no special significance within implicit (suffix or pattern)
rules. Also note that while SysV @code{make} actually expands its
entire prerequisite list @emph{twice}, GNU @code{make} does not behave
this way: instead it simply expands these special variables without
re-expanding any other part of the prerequisites list.
This somewhat bizarre feature is included only to provide some
compatibility with SysV makefiles. In a native GNU @code{make} file
there are other ways to accomplish the same results. This feature is
disabled if the special pseudo target @code{.POSIX} is defined.
@node Pattern Match, Match-Anything Rules, Automatic, Pattern Rules
@subsection How Patterns Match
@ -9322,29 +9358,6 @@ pattern rules for extraction from SCCS, in combination with the
general feature of rule chaining.
@xref{Chained Rules, ,Chains of Implicit Rules}.
@item
In System V @code{make}, the string @samp{$$@@} has the strange meaning
that, in the prerequisites of a rule with multiple targets, it stands
for the particular target that is being processed.
This is not defined in GNU @code{make} because @samp{$$} should always
stand for an ordinary @samp{$}.
It is possible to get portions of this functionality through the use of
static pattern rules (@pxref{Static Pattern, ,Static Pattern Rules}).
The System V @code{make} rule:
@example
$(targets): $$@@.o lib.a
@end example
@noindent
can be replaced with the GNU @code{make} static pattern rule:
@example
$(targets): %: %.o lib.a
@end example
@item
In System V and 4.3 BSD @code{make}, files found by @code{VPATH} search
(@pxref{Directory Search, ,Searching Directories for Prerequisites}) have their names changed inside command

4
main.c
View File

@ -2169,9 +2169,9 @@ print_usage (bad)
}
if (!remote_description || *remote_description == '\0')
fprintf (usageto, _("\nBuilt for %s"), make_host);
fprintf (usageto, _("\nThis program built for %s"), make_host);
else
fprintf (usageto, "\nBuilt for %s (%s)", make_host, remote_description);
fprintf (usageto, "\nThis program built for %s (%s)", make_host, remote_description);
fprintf (usageto, _("\nReport bugs to <bug-make@gnu.org>\n"));
}

View File

@ -1,3 +1,4 @@
*.gmo *.mo *.pot
*.gmo *.mo *.pot *.po
Makefile.in Makefile
POTFILES

129
read.c
View File

@ -132,7 +132,8 @@ static int conditional_line PARAMS ((char *line, const struct floc *flocp));
static void record_files PARAMS ((struct nameseq *filenames, char *pattern, char *pattern_percent,
struct dep *deps, unsigned int cmds_started, char *commands,
unsigned int commands_idx, int two_colon,
const struct floc *flocp, int set_default));
int have_sysv_atvar,
const struct floc *flocp, int set_default));
static void record_target_var PARAMS ((struct nameseq *filenames, char *defn,
int two_colon,
enum variable_origin origin,
@ -430,6 +431,7 @@ eval (ebuf, set_default)
unsigned int cmds_started, tgts_started;
int ignoring = 0, in_ignored_define = 0;
int no_targets = 0; /* Set when reading a rule without targets. */
int have_sysv_atvar = 0;
struct nameseq *filenames = 0;
struct dep *deps = 0;
long nlines = 0;
@ -450,7 +452,7 @@ eval (ebuf, set_default)
fi.lineno = tgts_started; \
record_files (filenames, pattern, pattern_percent, deps, \
cmds_started, commands, commands_idx, two_colon, \
&fi, set_default); \
have_sysv_atvar, &fi, set_default); \
} \
filenames = 0; \
commands_idx = 0; \
@ -1057,6 +1059,16 @@ eval (ebuf, set_default)
}
}
/* Do any of the prerequisites appear to have $@ etc.? */
have_sysv_atvar = 0;
if (!posix_pedantic)
for (p = strchr (p2, '$'); p != 0; p = strchr (p+1, '$'))
if (p[1] == '@' || (p[1] == '(' && p[2] == '@'))
{
have_sysv_atvar = 1;
break;
}
/* Is this a static pattern rule: `target: %targ: %dep; ...'? */
p = strchr (p2, ':');
while (p != 0 && p[-1] == '\\')
@ -1654,7 +1666,8 @@ record_target_var (filenames, defn, two_colon, origin, flocp)
static void
record_files (filenames, pattern, pattern_percent, deps, cmds_started,
commands, commands_idx, two_colon, flocp, set_default)
commands, commands_idx, two_colon, have_sysv_atvar,
flocp, set_default)
struct nameseq *filenames;
char *pattern, *pattern_percent;
struct dep *deps;
@ -1662,6 +1675,7 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started,
char *commands;
unsigned int commands_idx;
int two_colon;
int have_sysv_atvar;
const struct floc *flocp;
int set_default;
{
@ -1684,16 +1698,22 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started,
for (; filenames != 0; filenames = nextf)
{
register char *name = filenames->name;
register struct file *f;
register struct dep *d;
char *name = filenames->name;
struct file *f;
struct dep *d;
struct dep *this;
char *implicit_percent;
nextf = filenames->next;
free (filenames);
/* Check for .POSIX. We used to do this in snap_deps() but that's not
good enough: it doesn't happen until after the makefile is read,
which means we cannot use its value during parsing. */
if (streq (name, ".POSIX"))
posix_pedantic = 1;
implicit_percent = find_percent (name);
implicit |= implicit_percent != 0;
@ -1772,6 +1792,101 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started,
}
}
/* If at least one of the dependencies uses $$@ etc. deal with that.
It would be very nice and very simple to just expand everything, but
it would break a lot of backward compatibility. Maybe that's OK
since we're just emulating a SysV function, and if we do that then
why not emulate it completely (that's what SysV make does: it
re-expands the entire prerequisite list, all the time, with $@
etc. in scope. But, it would be a pain indeed to document this
("iff you use $$@, your prerequisite lists is expanded twice...")
Ouch. Maybe better to make the code more complex. */
if (have_sysv_atvar)
{
char *p;
int tlen = strlen (name);
char *fnp = strrchr (name, '/');
int dlen;
int flen;
if (fnp)
{
dlen = fnp - name;
++fnp;
flen = strlen (fnp);
}
else
{
dlen = 0;
fnp = name;
flen = tlen;
}
for (d = this; d != 0; d = d->next)
for (p = strchr (d->name, '$'); p != 0; p = strchr (p+1, '$'))
{
char *s = p;
char *at;
int atlen;
/* If it's a '$@' or '$(@', it's escaped */
if ((++p)[0] == '$'
&& (p[1] == '@' || (p[1] == '(' && p[2] == '@')))
{
bcopy (p, s, strlen (p)+1);
continue;
}
/* Maybe found one. Check. p will point to '@' [for $@] or
')' [for $(@)] or 'D' [for $(@D)] or 'F' [for $(@F)]. */
if (p[0] != '@'
&& (p[0] != '(' || (++p)[0] != '@'
|| ((++p)[0] != ')'
&& (p[1] != ')' || (p[0] != 'D' && p[0] != 'F')))))
continue;
/* Found one. Compute the length and string ptr. Move p
past the variable reference. */
switch (p[0])
{
case 'D':
atlen = dlen;
at = name;
p += 2;
break;
case 'F':
atlen = flen;
at = fnp;
p += 2;
break;
default:
atlen = tlen;
at = name;
++p;
break;
}
/* Get more space. */
{
int soff = s - d->name;
int poff = p - d->name;
d->name = (char *) xrealloc (d->name,
strlen (d->name) + atlen + 1);
s = d->name + soff;
p = d->name + poff;
}
/* Copy the string over. */
bcopy(p, s+atlen, strlen (p)+1);
bcopy(at, s, atlen);
p = s + atlen - 1;
}
}
if (!two_colon)
{
/* Single-colon. Combine these dependencies

View File

@ -1,3 +1,8 @@
2002-07-10 Paul D. Smith <psmith@gnu.org>
* scripts/variables/automatic: Add some tests for $$@, $$(@D), and
$$(@F).
2002-07-09 Paul D. Smith <psmith@gnu.org>
* scripts/variables/automatic: Create a test for automatic variables.

View File

@ -30,9 +30,8 @@ close(MAKEFILE);
# TEST #1 -- simple test
# -------
&touch(qw(foo.x baz.z));
sleep(1);
# Touch these into the past
&utouch(-10, qw(foo.x baz.z));
&run_make_with_options($makefile, "", &get_logfile);
$answer = "touch $dir/bar.y
@ -47,4 +46,28 @@ touch $dir/foo.x\n";
unlink(qw(foo.x bar.y baz.z));
# TEST #2 -- test the SysV emulation of $$@ etc.
# -------
$makefile2 = &get_tmpfile;
open(MAKEFILE, "> $makefile2");
print MAKEFILE "dir = $dir\n";
print MAKEFILE <<'EOF';
.SUFFIXES:
.DEFAULT: ; @echo '$@'
$(dir)/foo $(dir)/bar: $@.x $$@.x $$$@.x $$$$@.x $$(@D).x $$(@F).x
$(dir)/x.z $(dir)/y.z: $(dir)/%.z : $@.% $$@.% $$$@.% $$$$@.% $$(@D).% $$(@F).%
EOF
&run_make_with_options($makefile2, "$dir/foo $dir/bar", &get_logfile);
$answer = ".x\n$dir/foo.x\n\$.x\n\$@.x\n$dir.x\nfoo.x\n$dir/bar.x\nbar.x\n";
&compare_output($answer, &get_logfile(1));
&run_make_with_options($makefile2, "$dir/x.z $dir/y.z", &get_logfile);
$answer = ".x\n$dir/x.z.x\n\$.x\n\$@.x\n$dir.x\nx.z.x\n.y\n$dir/y.z.y\n\$.y\n\$@.y\n$dir.y\ny.z.y\n";
&compare_output($answer, &get_logfile(1));
1;

View File

@ -825,15 +825,29 @@ sub remove_directory_tree_inner
sub touch
{
local (@filenames) = @_;
local ($file);
foreach $file (@filenames) {
foreach $file (@_) {
(open(T, ">> $file") && print(T "\n") && close(T))
|| &error("Couldn't touch $file: $!\n", 1);
}
}
# Touch with a time offset. To DTRT, call touch() then use stat() to get the
# access/mod time for each file and apply the offset.
sub utouch
{
local ($off) = shift;
local ($file);
&touch(@_);
local (@s) = stat($_[0]);
utime($s[8]+$off, $s[9]+$off, @_);
}
# open a file, write some stuff to it, and close it.
sub create_file