mirror of
https://git.savannah.gnu.org/git/make.git
synced 2025-02-04 13:55:45 +00:00
[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:
parent
957aa450a0
commit
c01222c018
4 changed files with 108 additions and 98 deletions
3
NEWS
3
NEWS
|
@ -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.
|
||||
|
||||
|
||||
|
|
199
src/read.c
199
src/read.c
|
@ -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. */
|
||||
|
|
|
@ -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\
|
||||
\
|
||||
\
|
||||
|
|
|
@ -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!
|
||||
|
|
Loading…
Reference in a new issue