[SV 35711] Check for special targets earlier

GNU make must recognize some special targets as they are defined.
Because of the way targets are defined, we were not recognizing these
special targets until we were handling the NEXT statement.  However
that's too late for some special targets such as .POSIX etc. which can
change the behavior of make during parsing.

Check for special targets earlier, as soon as we've finished parsing
the target introduction line (before we've even parsed the recipe).

* NEWS: Mention the change.
* src/read.c (check_specials): New function to look for special
targets.  Move checks from eval() and record_files() to this new
function.
(eval): Call check_specials() after we've completed parsing the target
introduction line.  Move default goal detection to check_specials().
(record_files): Move handling of .POSIX, .SECONDEXPANSION, and
.ONESHELL to check_specials().
* tests/scripts/misc/bs-nl: Remove workaround for late .POSIX issue.
* tests/scripts/targets/POSIX: Add a comment.
This commit is contained in:
Paul Smith 2020-11-27 11:37:29 -05:00
parent 957aa450a0
commit c01222c018
4 changed files with 108 additions and 98 deletions

3
NEWS
View file

@ -34,6 +34,9 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
https://www.gnu.org/software/gnulib/manual/html_node/C99-features-assumed.html
The configure script should verify the compiler has these features.
* Special targets like .POSIX are detected upon definition, ensuring that any
change in behavior takes effect immediately, before the next line is parsed.
* GNU Make can now be built for MS-Windows using the Tiny C tcc compiler.

View file

@ -142,6 +142,7 @@ static void do_undefine (char *name, enum variable_origin origin,
static struct variable *do_define (char *name, enum variable_origin origin,
struct ebuffer *ebuf);
static int conditional_line (char *line, size_t len, const floc *flocp);
static void check_specials (const struct nameseq *file, int set_default);
static void record_files (struct nameseq *filenames, int are_also_makes,
const char *pattern,
const char *pattern_percent, char *depstr,
@ -1313,79 +1314,7 @@ eval (struct ebuffer *ebuf, int set_default)
commands[commands_idx++] = '\n';
}
/* Determine if this target should be made default. We used to do
this in record_files() but because of the delayed target recording
and because preprocessor directives are legal in target's commands
it is too late. Consider this fragment for example:
foo:
ifeq ($(.DEFAULT_GOAL),foo)
...
endif
Because the target is not recorded until after ifeq directive is
evaluated the .DEFAULT_GOAL does not contain foo yet as one
would expect. Because of this we have to move the logic here. */
if (set_default && default_goal_var->value[0] == '\0')
{
struct dep *d;
struct nameseq *t = filenames;
for (; t != 0; t = t->next)
{
int reject = 0;
const char *name = t->name;
/* We have nothing to do if this is an implicit rule. */
if (strchr (name, '%') != 0)
break;
/* See if this target's name does not start with a '.',
unless it contains a slash. */
if (*name == '.' && strchr (name, '/') == 0
#ifdef HAVE_DOS_PATHS
&& strchr (name, '\\') == 0
#endif
)
continue;
/* If this file is a suffix, don't let it be
the default goal file. */
for (d = suffix_file->deps; d != 0; d = d->next)
{
struct dep *d2;
if (*dep_name (d) != '.' && streq (name, dep_name (d)))
{
reject = 1;
break;
}
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
{
size_t l = strlen (dep_name (d2));
if (!strneq (name, dep_name (d2), l))
continue;
if (streq (name + l, dep_name (d)))
{
reject = 1;
break;
}
}
if (reject)
break;
}
if (!reject)
{
define_variable_global (".DEFAULT_GOAL", 13, t->name,
o_file, 0, NILF);
break;
}
}
}
check_specials (filenames, set_default);
}
}
@ -1926,6 +1855,107 @@ record_target_var (struct nameseq *filenames, char *defn,
}
}
/* Check for special targets. We used to do this in record_files() but that's
too late: by the time we get there we'll have already parsed the next line
and it have been mis-parsed because these special targets haven't been
considered yet. */
static void check_specials (const struct nameseq* files, int set_default)
{
const struct nameseq *t = files;
/* Unlikely but ... */
if (posix_pedantic && second_expansion && one_shell
&& (!set_default || default_goal_var->value[0] == '\0'))
return;
for (; t != 0; t = t->next)
{
const char* nm = t->name;
if (!posix_pedantic && streq (nm, ".POSIX"))
{
posix_pedantic = 1;
define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0);
/* These default values are based on IEEE Std 1003.1-2008.
It requires '-O 1' for [CF]FLAGS, but GCC doesn't allow
space between -O and the number so omit it here. */
define_variable_cname ("ARFLAGS", "-rv", o_default, 0);
define_variable_cname ("CC", "c99", o_default, 0);
define_variable_cname ("CFLAGS", "-O1", o_default, 0);
define_variable_cname ("FC", "fort77", o_default, 0);
define_variable_cname ("FFLAGS", "-O1", o_default, 0);
define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0);
continue;
}
if (!second_expansion && streq (nm, ".SECONDEXPANSION"))
{
second_expansion = 1;
continue;
}
#if !defined (__MSDOS__) && !defined (__EMX__)
if (!one_shell && streq (nm, ".ONESHELL"))
{
one_shell = 1;
continue;
}
#endif
/* Determine if this target should be made default. */
if (set_default && default_goal_var->value[0] == '\0')
{
struct dep *d;
int reject = 0;
/* We have nothing to do if this is an implicit rule. */
if (strchr (nm, '%') != 0)
break;
/* See if this target's name does not start with a '.',
unless it contains a slash. */
if (*nm == '.' && strchr (nm, '/') == 0
#ifdef HAVE_DOS_PATHS
&& strchr (nm, '\\') == 0
#endif
)
continue;
/* If this file is a suffix, it can't be the default goal file. */
for (d = suffix_file->deps; d != 0; d = d->next)
{
struct dep *d2;
if (*dep_name (d) != '.' && streq (nm, dep_name (d)))
{
reject = 1;
break;
}
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
{
size_t l = strlen (dep_name (d2));
if (!strneq (nm, dep_name (d2), l))
continue;
if (streq (nm + l, dep_name (d)))
{
reject = 1;
break;
}
}
if (reject)
break;
}
if (!reject)
define_variable_global (".DEFAULT_GOAL", 13, t->name,
o_file, 0, NILF);
}
}
}
/* Record a description line for files FILENAMES,
with dependencies DEPS, commands to execute described
by COMMANDS and COMMANDS_IDX, coming from FILENAME:COMMANDS_STARTED.
@ -2067,29 +2097,6 @@ record_files (struct nameseq *filenames, int are_also_makes,
free_ns (filenames);
/* Check for special targets. Do it here instead of, say, snap_deps()
so that we can immediately use the value. */
if (!posix_pedantic && streq (name, ".POSIX"))
{
posix_pedantic = 1;
define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0);
/* These default values are based on IEEE Std 1003.1-2008.
It requires '-O 1' for [CF]FLAGS, but GCC doesn't allow space
between -O and the number so omit it here. */
define_variable_cname ("ARFLAGS", "-rv", o_default, 0);
define_variable_cname ("CC", "c99", o_default, 0);
define_variable_cname ("CFLAGS", "-O1", o_default, 0);
define_variable_cname ("FC", "fort77", o_default, 0);
define_variable_cname ("FFLAGS", "-O1", o_default, 0);
define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0);
}
else if (!second_expansion && streq (name, ".SECONDEXPANSION"))
second_expansion = 1;
#if !defined (__MSDOS__) && !defined (__EMX__)
else if (!one_shell && streq (name, ".ONESHELL"))
one_shell = 1;
#endif
/* If this is a static pattern rule:
'targets: target%pattern: prereq%pattern; recipe',
make sure the pattern matches this target name. */

View file

@ -88,7 +88,6 @@ var:;@echo '|$(var)|'!,
# POSIX: Preserve trailing space
run_make_test(q!
.POSIX:
x = y
var = he \
llo
var:;@echo '|$(var)|'!,
@ -97,7 +96,6 @@ var:;@echo '|$(var)|'!,
# POSIX: One space per bs-nl
run_make_test(q!
.POSIX:
x = y
var = he\
\
\

View file

@ -20,6 +20,8 @@ all: ; \@$script
'', "#MAKE#: *** [#MAKEFILE#:3: all] Error $err\n", 512);
# User settings must override .POSIX
# In the standard .POSIX must be the first thing in the makefile
# but we relax that rule in GNU make.
$flags = '-xc';
$out = `$sh_name $flags '$script' 2>&1`;
run_make_test(qq!