diff --git a/NEWS b/NEWS index 95909582..bf6857f2 100644 --- a/NEWS +++ b/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. diff --git a/src/read.c b/src/read.c index c55998c3..57903bc8 100644 --- a/src/read.c +++ b/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. */ diff --git a/tests/scripts/misc/bs-nl b/tests/scripts/misc/bs-nl index fdf4aabc..e8ba0467 100644 --- a/tests/scripts/misc/bs-nl +++ b/tests/scripts/misc/bs-nl @@ -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\ \ \ diff --git a/tests/scripts/targets/POSIX b/tests/scripts/targets/POSIX index d69b8bbd..c40b8dbe 100644 --- a/tests/scripts/targets/POSIX +++ b/tests/scripts/targets/POSIX @@ -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!