and though bugs are the bane of my existence, rest assured the wretched thing will get the best of care here

...
 
Commits (10)
  • Paul Smith's avatar
    74bd8b3a
  • Paul Smith's avatar
    * .dir-locals.el: Update for newer LSP config · 7b0a7418
    Paul Smith authored
    7b0a7418
  • Paul Smith's avatar
  • Jouke Witteveen's avatar
    More correctly describe the scope of variables · e5f6dc54
    Jouke Witteveen authored
    * NEWS: Use "local" instead of the incorrect "lexically-scoped".
    * doc/make.texi: Refer to let/foreach variables as local variables.
    e5f6dc54
  • Paul Smith's avatar
    d9aff6b8
  • Paul Smith's avatar
    [SV 59870] define/undefine prerequisites are not target-specific vars · da6fc6aa
    Paul Smith authored
    * src/read.c (parse_var_assignment): If called in a target-specific
    variable context don't allow define/undefine as variable assignments.
    * test/scripts/variables/define: Add a test.
    * test/scripts/variables/undefine: Add a test.
    da6fc6aa
  • Paul Smith's avatar
    [SV 59881] Handle vertical TAB consistently · c66ec5fa
    Paul Smith authored
    While parsing makefiles get_next_mword() was treating VTAB as a word
    character rather than a word separator.  However, when using
    find_next_token(), for example in patsubst_expand_pat(), we treated
    VTAB as a word separator causing multiple words to appear where we
    didn't expect them.
    
    * src/makeint.h (END_OF_TOKEN): Change from a loop to a boolean check.
    * src/misc.c (end_of_token): Move the loop here.
    * src/read.c (get_next_mword): Skip whitespace, not just blank, to
    find the start of the word and use END_OF_TOKEN() to decide when the
    current word is finished.
    c66ec5fa
  • Paul Smith's avatar
    Ensure variable_buffer is always set. · 52056d7b
    Paul Smith authored
    Initialize the global variable_buffer in main() so that it is never
    a null pointer.  Then invoking variable_expand("") is never needed:
    simply use the variable_buffer pointer when we want to restart the
    variable buffer.  The main point of this simplification is not to
    keep a separate pointer to the beginning of the buffer: this is
    dangerous because the buffer may be re-allocated.  Instead always
    use the variable_buffer pointer itself.
    
    * src/variable.h (initialize_variable_output): Publish.
    * src/expand.c (initialize_variable_output): Remove static.
    * src/main.c (main): Initialize variable_buffer.
    * src/file.c (enter_prereqs): Don't call variable_expand("") and
    don't save a separate buffer pointer than might be outdated.
    (expand_deps): Ditto.
    * src/read.c (record_files): Ditto.
    * src/remake.c (library_search): Ditto.
    52056d7b
  • Paul Smith's avatar
    * tests/scripts/features/exec: Small cleanup · 144f436c
    Paul Smith authored
    144f436c
  • Dmitry Goncharov's avatar
    [SV 60188] Explicit prereqs cannot be intermediate files · 510e5ce8
    Dmitry Goncharov authored
    If a prereq of a pattern is an explicit target, it should not be
    considered an intermediate file.
    
    (Minor tweaks by Paul Smith <psmith@gnu.org>)
    
    * src/dep.h (struct nameseq): Add is_explicit flag.
    * src/implicit.c (struct patdeps): Ditto.
    (pattern_search): Set the is_explicit flag appropriately for each
    prerequisite, based on whether it contained a pattern or not.
    Update the help output to note implicit vs. explicit prereqs.
    * tests/scripts/features/double_colon: Add tests.
    * tests/scripts/features/grouped_targets: Ditto.
    * tests/scripts/features/patternrules: Ditto.
    * tests/scripts/features/se_implicit: Ditto.
    * tests/scripts/features/statipattrules: Ditto.
    510e5ce8
(
(nil . ((bug-reference-bug-regexp . "\\(\\)\\bSV[- ]\\([0-9]+\\)")
(bug-reference-url-format . "https://savannah.gnu.org/bugs/?%s")
(ccls-initialization-options . (:index (:threads 6
:initialBlacklist ("/make-[0-9]" "tests/work/" "/\\.deps" "/\\..*cache" "/\\.git"))))
(lsp-file-watch-ignored . ("/\\.git$"
"/\\..*cache$"
;; autotools content
"/\\.deps$"
"/autom4te\\.cache$"
"/build-aux$"
;; make-specific content
"/doc/manual$"
"/tests/work$"
"/make-[0-9]"))
(ccls-initialization-options
. (:index (:threads 6
:initialBlacklist ["/make-[0-9]" "tests/work/" "/\\.deps"
"/\\..*cache" "/\\.git"])))
(lsp-file-watch-ignored-directories
. ("[/\\\\]\\.git$"
"[/\\\\]\\..*cache$"
;; autotools content
"[/\\\\]\\.deps$"
"[/\\\\]autom4te\\.cache$"
"[/\\\\]build-aux$"
;; make-specific content
"[/\\\\]doc[/\\\\]manual$"
"[/\\\\]tests[/\\\\]work$"
"[/\\\\]make-[0-9]"))
))
(c-mode . ((c-file-style . "gnu")))
)
......@@ -35,8 +35,8 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
The configure script should verify the compiler has these features.
* New feature: The $(let ...) function
This function allows user-defined functions to provide a lexically-scoped
set of variables: values can be assigned to these variables from within the
This function allows user-defined functions to define a set of local
variables: values can be assigned to these variables from within the
user-defined function and they will not impact global variable assignments.
Implementation provided by Jouke Witteveen <j.witteveen@gmail.com>
......
......@@ -276,7 +276,7 @@ Functions for Transforming Text
* Text Functions:: General-purpose text manipulation functions.
* File Name Functions:: Functions for manipulating file names.
* Conditional Functions:: Functions that implement conditions.
* Let Function:: Lexically scoped variables.
* Let Function:: Local variables.
* Foreach Function:: Repeat some text with controlled variation.
* File Function:: Write text to a file.
* Call Function:: Expand a user-defined function.
......@@ -5204,7 +5204,9 @@ variables are called @dfn{macros}.)
Variables and functions in all parts of a makefile are expanded when
read, except for in recipes, the right-hand sides of variable
definitions using @samp{=}, and the bodies of variable definitions
using the @code{define} directive.@refill
using the @code{define} directive. The value a variable expands to is
that of its most recent definition at the time of expansion. In other
words, variables are dynamically scoped.
Variables can represent lists of file names, options to pass to compilers,
programs to run, directories to look in for source files, directories to
......@@ -5792,6 +5794,11 @@ You can specify a value in the makefile, either
with an assignment (@pxref{Setting, ,Setting Variables}) or with a
verbatim definition (@pxref{Multi-Line, ,Defining Multi-Line Variables}).@refill
@item
You can specify a short-lived value with the @code{let} function
(@pxref{Let Function}) or with the @code{foreach} function
(@pxref{Foreach Function}).
@item
Variables in the environment become @code{make} variables.
@xref{Environment, ,Variables from the Environment}.
......@@ -6274,10 +6281,12 @@ the Shell}.@refill
Variable values in @code{make} are usually global; that is, they are the
same regardless of where they are evaluated (unless they're reset, of
course). One exception to that is automatic variables
course). Exceptions to that are variables defined with the @code{let}
function (@pxref{Let Function}) or the @code{foreach} function
(@pxref{Foreach Function}, and automatic variables
(@pxref{Automatic Variables}).
The other exception is @dfn{target-specific variable values}. This
Another exception are @dfn{target-specific variable values}. This
feature allows you to define different values for the same variable,
based on the target that @code{make} is currently building. As with
automatic variables, these values are only available within the context
......@@ -7039,7 +7048,7 @@ be substituted.
* Text Functions:: General-purpose text manipulation functions.
* File Name Functions:: Functions for manipulating file names.
* Conditional Functions:: Functions that implement conditions.
* Let Function:: Lexically scoped variables.
* Let Function:: Local variables.
* Foreach Function:: Repeat some text with controlled variation.
* File Function:: Write text to a file.
* Call Function:: Expand a user-defined function.
......@@ -7144,9 +7153,10 @@ Finds whitespace-separated words in @var{text} that match
@var{pattern} may contain a @samp{%} which acts as a wildcard,
matching any number of any characters within a word. If
@var{replacement} also contains a @samp{%}, the @samp{%} is replaced
by the text that matched the @samp{%} in @var{pattern}. Only the first
@samp{%} in the @var{pattern} and @var{replacement} is treated this
way; any subsequent @samp{%} is unchanged.@refill
by the text that matched the @samp{%} in @var{pattern}. Words that do
not match the pattern are kept without change in the output. Only the
first @samp{%} in the @var{pattern} and @var{replacement} is treated
this way; any subsequent @samp{%} is unchanged.@refill
@cindex @code{%}, quoting in @code{patsubst}
@cindex @code{%}, quoting with @code{\} (backslash)
......@@ -7696,7 +7706,7 @@ the result of the expansion is the expansion of the last argument.
@node Let Function, Foreach Function, Conditional Functions, Functions
@section The @code{let} Function
@findex let
@cindex variables, lexically scoped
@cindex variables, local
The @code{let} function provides a means to limit the scope of a
variable. The assignment of the named variables in a @code{let}
......
......@@ -137,12 +137,13 @@ ChangeLog: .check-git-HEAD
echo "WARNING: $(gl2cl) is not available. No $@ generated."; \
fi
.PHONY: .check-git-HEAD
.check-git-HEAD:
.check-git-HEAD: FORCE
sha="`git rev-parse HEAD`"; \
test -f '$@' && [ "`cat '$@' 2>/dev/null`" = "$$sha" ] \
|| echo "$$sha" > '$@'
.PHONY: FORCE
FORCE:;@:
## ---------------- ##
## Updating files. ##
......
......@@ -38,7 +38,10 @@ struct nameseq
/* Structure representing one dependency of a file.
Each struct file's 'deps' points to a chain of these, through 'next'.
'stem' is the stem for this dep line of static pattern rule or NULL. */
'stem' is the stem for this dep line of static pattern rule or NULL.
explicit is set when implicit rule search is performed and the prerequisite
does not contain %. When explicit is set the file is not intermediate. */
#define DEP(_t) \
NAMESEQ (_t); \
......@@ -49,7 +52,8 @@ struct nameseq
unsigned int ignore_mtime : 1; \
unsigned int staticpattern : 1; \
unsigned int need_2nd_expansion : 1; \
unsigned int ignore_automatic_vars : 1
unsigned int ignore_automatic_vars : 1; \
unsigned int is_explicit : 1;
struct dep
{
......
......@@ -71,10 +71,11 @@ variable_buffer_output (char *ptr, const char *string, size_t length)
return ptr + length;
}
/* Return a pointer to the beginning of the variable buffer. */
/* Return a pointer to the beginning of the variable buffer.
This is called from main() and it should never be null afterward. */
static char *
initialize_variable_output (void)
char *
initialize_variable_output ()
{
/* If we don't have a variable output buffer yet, get one. */
......@@ -207,7 +208,7 @@ variable_expand_string (char *line, const char *string, size_t length)
if (length == 0)
{
variable_buffer_output (o, "", 1);
return (variable_buffer);
return variable_buffer;
}
/* We need a copy of STRING: due to eval, it's possible that it will get
......
......@@ -424,7 +424,11 @@ remove_intermediates (int sig)
}
}
if (status < 0)
perror_with_name ("unlink: ", f->name);
{
perror_with_name ("\nunlink: ", f->name);
/* Start printing over. */
doneany = 0;
}
}
}
}
......@@ -486,7 +490,6 @@ enter_prereqs (struct dep *deps, const char *stem)
if (stem)
{
const char *pattern = "%";
char *buffer = variable_expand ("");
struct dep *dp = deps, *dl = 0;
while (dp != 0)
......@@ -506,14 +509,15 @@ enter_prereqs (struct dep *deps, const char *stem)
if (stem[0] == '\0')
{
memmove (percent, percent+1, strlen (percent));
o = variable_buffer_output (buffer, nm, strlen (nm) + 1);
o = variable_buffer_output (variable_buffer, nm,
strlen (nm) + 1);
}
else
o = patsubst_expand_pat (buffer, stem, pattern, nm,
o = patsubst_expand_pat (variable_buffer, stem, pattern, nm,
pattern+1, percent+1);
/* If the name expanded to the empty string, ignore it. */
if (buffer[0] == '\0')
if (variable_buffer[0] == '\0')
{
struct dep *df = dp;
if (dp == deps)
......@@ -525,7 +529,8 @@ enter_prereqs (struct dep *deps, const char *stem)
}
/* Save the name. */
dp->name = strcache_add_len (buffer, o - buffer);
dp->name = strcache_add_len (variable_buffer,
o - variable_buffer);
}
dp->stem = stem;
dp->staticpattern = 1;
......@@ -583,8 +588,7 @@ expand_deps (struct file *f)
"$*" so they'll expand properly. */
if (d->staticpattern)
{
char *o = variable_expand ("");
o = subst_expand (o, name, "%", "$*", 1, 2, 0);
char *o = subst_expand (variable_buffer, name, "%", "$*", 1, 2, 0);
*o = '\0';
free (name);
d->name = name = xstrdup (variable_buffer);
......
......@@ -153,6 +153,7 @@ struct patdeps
struct file *file;
unsigned int ignore_mtime : 1;
unsigned int ignore_automatic_vars : 1;
unsigned int is_explicit : 1;
};
/* This structure stores information about pattern rules that we need
......@@ -540,6 +541,7 @@ pattern_search (struct file *file, int archive,
/* If we don't need a second expansion, just replace the %. */
if (! dep->need_2nd_expansion)
{
int is_explicit = 1;
p = strchr (nptr, '%');
if (p == 0)
strcpy (depname, nptr);
......@@ -556,6 +558,7 @@ pattern_search (struct file *file, int archive,
memcpy (o, stem, stemlen);
o += stemlen;
strcpy (o, p + 1);
is_explicit = 0;
}
/* Parse the expanded string. It might have wildcards. */
......@@ -566,6 +569,7 @@ pattern_search (struct file *file, int archive,
++deps_found;
d->ignore_mtime = dep->ignore_mtime;
d->ignore_automatic_vars = dep->ignore_automatic_vars;
d->is_explicit = is_explicit;
}
/* We've used up this dep, so next time get a new one. */
......@@ -586,6 +590,7 @@ pattern_search (struct file *file, int archive,
int add_dir = 0;
size_t len;
struct dep **dptr;
int is_explicit;
nptr = get_next_word (nptr, &len);
if (nptr == 0)
......@@ -615,6 +620,7 @@ pattern_search (struct file *file, int archive,
{
memcpy (depname, nptr, len);
depname[len] = '\0';
is_explicit = 1;
}
else
{
......@@ -635,6 +641,7 @@ pattern_search (struct file *file, int archive,
}
memcpy (o, p + 1, len - i - 1);
o[len - i - 1] = '\0';
is_explicit = 0;
}
/* Set up for the next word. */
......@@ -674,6 +681,7 @@ pattern_search (struct file *file, int archive,
++deps_found;
if (order_only)
d->ignore_mtime = 1;
d->is_explicit = is_explicit;
dptr = &d->next;
}
......@@ -726,6 +734,7 @@ pattern_search (struct file *file, int archive,
memset (pat, '\0', sizeof (struct patdeps));
pat->ignore_mtime = d->ignore_mtime;
pat->ignore_automatic_vars = d->ignore_automatic_vars;
pat->is_explicit = d->is_explicit;
DBS (DB_IMPLICIT,
(is_rule
......@@ -777,13 +786,14 @@ pattern_search (struct file *file, int archive,
}
/* We could not find the file in any place we should look.
Try to make this dependency as an intermediate file, but
Look for an implicit rule to make this dependency, but
only on the second pass. */
if (intermed_ok)
{
DBS (DB_IMPLICIT,
(_("Looking for a rule with intermediate file '%s'.\n"),
(_("Looking for a rule with %s file '%s'.\n"),
d->is_explicit ? "explicit" : "intermediate",
d->name));
if (int_file == 0)
......@@ -899,7 +909,7 @@ pattern_search (struct file *file, int archive,
f->pat_searched = imf->pat_searched;
f->also_make = imf->also_make;
f->is_target = 1;
f->intermediate = 1;
f->intermediate = !pat->is_explicit;
f->tried_implicit = 1;
imf = lookup_file (pat->pattern);
......@@ -916,6 +926,7 @@ pattern_search (struct file *file, int archive,
dep = alloc_dep ();
dep->ignore_mtime = pat->ignore_mtime;
dep->is_explicit = pat->is_explicit;
dep->ignore_automatic_vars = pat->ignore_automatic_vars;
s = strcache_add (pat->name);
if (recursions)
......
......@@ -1086,6 +1086,8 @@ main (int argc, char **argv, char **envp)
no_default_sh_exe = 1;
#endif
initialize_variable_output ();
/* Useful for attaching debuggers, etc. */
SPIN ("main-entry");
......
......@@ -463,8 +463,8 @@ extern int unixy_shell;
#define ISBLANK(c) STOP_SET((c),MAP_BLANK)
#define ISSPACE(c) STOP_SET((c),MAP_SPACE)
#define END_OF_TOKEN(c) STOP_SET((c),MAP_SPACE|MAP_NUL)
#define NEXT_TOKEN(s) while (ISSPACE (*(s))) ++(s)
#define END_OF_TOKEN(s) while (! STOP_SET (*(s), MAP_SPACE|MAP_NUL)) ++(s)
/* We can't run setrlimit when using posix_spawn. */
#if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && !defined(USE_POSIX_SPAWN)
......
......@@ -308,7 +308,8 @@ lindex (const char *s, const char *limit, int c)
char *
end_of_token (const char *s)
{
END_OF_TOKEN (s);
while (! END_OF_TOKEN (*s))
++s;
return (char *)s;
}
......
......@@ -494,7 +494,7 @@ eval_buffer (char *buffer, const floc *flocp)
based on the modifiers found if any, plus V_ASSIGN is 1.
*/
static char *
parse_var_assignment (const char *line, struct vmodifiers *vmod)
parse_var_assignment (const char *line, int targvar, struct vmodifiers *vmod)
{
const char *p;
memset (vmod, '\0', sizeof (*vmod));
......@@ -529,14 +529,14 @@ parse_var_assignment (const char *line, struct vmodifiers *vmod)
vmod->override_v = 1;
else if (word1eq ("private"))
vmod->private_v = 1;
else if (word1eq ("define"))
else if (!targvar && word1eq ("define"))
{
/* We can't have modifiers after 'define' */
vmod->define_v = 1;
p = next_token (p2);
break;
}
else if (word1eq ("undefine"))
else if (!targvar && word1eq ("undefine"))
{
/* We can't have modifiers after 'undefine' */
vmod->undefine_v = 1;
......@@ -721,7 +721,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* See if this is a variable assignment. We need to do this early, to
allow variables with names like 'ifdef', 'export', 'private', etc. */
p = parse_var_assignment (p, &vmod);
p = parse_var_assignment (p, 0, &vmod);
if (vmod.assign_v)
{
struct variable *v;
......@@ -1181,7 +1181,7 @@ eval (struct ebuffer *ebuf, int set_default)
p2 = variable_buffer + l;
}
p2 = parse_var_assignment (p2, &vmod);
p2 = parse_var_assignment (p2, 1, &vmod);
if (vmod.assign_v)
{
/* If there was a semicolon found, add it back, plus anything
......@@ -2202,10 +2202,9 @@ record_files (struct nameseq *filenames, int are_also_makes,
if (pattern)
{
static const char *percent = "%";
char *buffer = variable_expand ("");
char *o = patsubst_expand_pat (buffer, name, pattern, percent,
pattern_percent+1, percent+1);
f->stem = strcache_add_len (buffer, o - buffer);
char *o = patsubst_expand_pat (variable_buffer, name, pattern,
percent, pattern_percent+1, percent+1);
f->stem = strcache_add_len (variable_buffer, o - variable_buffer);
if (this)
{
if (! this->need_2nd_expansion)
......@@ -2735,7 +2734,7 @@ get_next_mword (char *buffer, char **startp, size_t *length)
char c;
/* Skip any leading whitespace. */
while (ISBLANK (*p))
while (ISSPACE (*p))
++p;
beg = p;
......@@ -2821,11 +2820,11 @@ get_next_mword (char *buffer, char **startp, size_t *length)
char closeparen;
int count;
if (END_OF_TOKEN (c))
goto done_word;
switch (c)
{
case '\0':
case ' ':
case '\t':
case '=':
goto done_word;
......
......@@ -1646,7 +1646,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
static size_t buflen = 0;
static size_t libdir_maxlen = 0;
static unsigned int std_dirs = 0;
char *libbuf = variable_expand ("");
char *libbuf;
/* Expand the pattern using LIB as a replacement. */
{
......@@ -1663,10 +1663,12 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
p[len] = c;
continue;
}
p4 = variable_buffer_output (libbuf, p, p3-p);
p4 = variable_buffer_output (variable_buffer, p, p3-p);
p4 = variable_buffer_output (p4, lib, liblen);
p4 = variable_buffer_output (p4, p3+1, len - (p3-p));
p[len] = c;
libbuf = variable_buffer;
}
/* Look first for 'libNAME.a' in the current directory. */
......
......@@ -129,6 +129,7 @@ char *allocated_variable_expand_for_file (const char *line, struct file *file);
allocated_variable_expand_for_file (line, (struct file *) 0)
char *expand_argument (const char *str, const char *end);
char *variable_expand_string (char *line, const char *string, size_t length);
char *initialize_variable_output ();
void install_variable_buffer (char **bufp, size_t *lenp);
void restore_variable_buffer (char *buf, size_t len);
......
......@@ -212,6 +212,21 @@ FORCE:
unlink('joe-is-forced');
# sv 60188.
# Even though test.x is explicitly mentioned, terminal pattern rules still
# apply only if the prerequisite exists.
touch('hello.z');
run_make_test(q!
all: hello.z
%.z:: test.x ; touch $@
%.x: ;
!, '', "#MAKE#: Nothing to be done for 'all'.\n");
unlink('hello.z');
# This tells the test driver that the perl test script executed properly.
1;
......
......@@ -3,13 +3,13 @@
use warnings;
my $description = "Test that make can execute binaries as well as scripts with"
." various shabangs and without a shebang";
." various shabangs and without a shbang";
my $details = "The various shells that this test uses are the default"
." /bin/sh, \$SHELL and the perl interpreter that is"
." executing this test program. The shells are used for the value"
." of SHELL inside the test makefile and also as a shebang in the"
." of SHELL inside the test makefile and also as a shbang in the"
." executed script. There is also a test which executes a script"
." that has no shebang.";
." that has no shbang.";
# Only bother with this on UNIX systems
$port_type eq 'UNIX' or return -1;
......@@ -17,26 +17,26 @@ $port_type eq 'UNIX' or return -1;
my $usersh = $origENV{SHELL};
my $answer = 'hello, world';
my @shebangs = ('', '#!/bin/sh', "#!$usersh", "#!$perl_name");
my @shbangs = ('', '#!/bin/sh', "#!$usersh", "#!$perl_name");
my @shells = ('', 'SHELL=/bin/sh', "SHELL=$usersh");
# tests [0-11]
# Have a makefile with various SHELL= exec a shell program with varios
# shebangs or without a shebang at all.
# shbangs or without a shbang at all.
my $stem = './exec.cmd';
my $k = 0;
for my $shebang (@shebangs) {
for my $shbang (@shbangs) {
for my $shell (@shells) {
my $cmd = $k ? "$stem.$k" : $stem;
++$k;
unlink $cmd;
open(CMD,"> $cmd");
print CMD "$shebang\n";
print CMD "$shbang\n";
print CMD "printf \"$answer\\n\";\n";
close(CMD);
chmod 0700, $cmd;
run_make_test(q!
run_make_test("# $shbang\n# $shell" . q!
all:; @$(CMD)
!, "$shell CMD=$cmd", "$answer\n");
......
......@@ -129,5 +129,31 @@ f g h&:: ; @echo Z
'',
"Z");
# sv 60188.
# Test that a file explicitly mentioned by the user and made by an implicit
# rule is not considered intermediate.
touch('hello.z');
touch('hello.q');
# subtest 1
# hello.x is not explicitly mentioned and thus is an intermediate file.
run_make_test(q!
all: hello.z
%.z %.q: %.x ; touch $*.z $*.q
%.x: ;
!, '', "#MAKE#: Nothing to be done for 'all'.\n");
# subtest 2
# test.x is explicitly mentioned and thus is not an intermediate file.
run_make_test(q!
all: hello.z
%.z %.q: %.x test.x ; @echo $*.z $*.q
%.x: ;
!, '', "hello.z hello.q\n");
unlink('hello.z');
unlink('hello.q');
# This tells the test driver that the perl test script executed properly.
1;
......@@ -18,7 +18,7 @@ $dir =~ s,.*/([^/]+)$,../$1,;
run_make_test(q!
.PHONY: all
all: case.1 case.2 case.3
all: case.1 case.2 case.3 case.4
# We can't have this, due to "Implicit Rule Search Algorithm" step 5c
#xxx: void
......@@ -43,6 +43,13 @@ all: case.1 case.2 case.3
@exit 0
3.implicit-phony:
# 4 - explicitly mentioned file made by an implicit rule
%.4: void
@exit 1
%.4: test.x
@exit 0
%.x: ;
!, '', '');
# TEST #1: make sure files that are built via implicit rules are marked
......@@ -244,6 +251,86 @@ run_make_test(q!
unlink('some file.xx', 'some file.yy');
# sv 60188.
# Test that a file explicitly mentioned by the user and made by an implicit
# rule is not considered intermediate.
touch('hello.z');
unlink('hello.x');
unlink('test.x');
# subtest 1
# hello.x is not explicitly mentioned and thus is an intermediate file.
run_make_test(q!
all: hello.z
%.z: %.x
touch $@
%.x: ;
!, '', "#MAKE#: Nothing to be done for 'all'.\n");
# subtest 2
# test.x is explicitly mentioned and thus is not an intermediate file.
run_make_test(q!
all: hello.z
%.z: %.x test.x
touch $@
%.x: ;
!, '', "touch hello.z");
unlink('hello.z');
# sv 60188.
# Test that a file explicitly mentioned by the user and made by an implicit
# rule is not considered intermediate, even when the builtin rules are used.
touch('hello.x');
touch('test.x');
touch('hello.tsk');
# subtest 1
# hello.o is not explicitly mentioned and thus is an intermediate file.
run_make_test(q!
all: hello.tsk
%.tsk: %.z ; @echo $@
%.z : %.x ; @echo $@
!, '', "#MAKE#: Nothing to be done for 'all'.\n");
# subtest 2
# test.z is explicitly mentioned and thus is not an intermediate file.
# test.z is built first because until it's built we don't know if we
# need to rebuild the intermediate hello.z
run_make_test(q!
all: hello.tsk
%.tsk: %.z test.z ; @echo $@
%.z : %.x ; @echo $@
!, '', "test.z\nhello.z\nhello.tsk\n");
# subtest 3
# hello.o is not explicitly mentioned and thus is an intermediate file.
run_make_test(q!
all: hello.tsk
dep:=%.o
%.tsk: $(dep) ; @echo $@
!, '', "#MAKE#: Nothing to be done for 'all'.\n");
# subtest 4
# Even when test.z is constructed from 2 variables it is still explicitly
# mentioned and thus is not an intermediate file.
# test.z is built first because until it's built we don't know if we
# need to rebuild the intermediate hello.z
run_make_test(q!
all: hello.tsk
name:=test
suf:=.z
%.tsk: %.z $(name)$(suf) ; @echo $@
%.z: %.x ; @echo $@
!, '', "test.z\nhello.z\nhello.tsk\n");
unlink('hello.x');
unlink('test.x');
# This tells the test driver that the perl test script executed properly.
1;
......
......@@ -262,5 +262,68 @@ run_make_test(q!
!,
'q/ux', "q/u\nq/u\n");
# sv 60188.
# Test that a file explicitly mentioned by the user and made by an implicit
# rule is not considered intermediate.
touch('hello.z');
# subtest 1.
# hello.x is derived from the stem and thus is an intermediate file.
run_make_test(q!
.SECONDEXPANSION:
dep:=.x
all: hello.z
%.z: %$$(dep) ; @echo $@
%.x: ;
!, '', "#MAKE#: Nothing to be done for 'all'.\n");
# subtest 2.
# test.x is explicitly mentioned and thus is not an intermediate file.
run_make_test(q!
.SECONDEXPANSION:
dep:=test.x
all: hello.z
%.z: %.x $$(dep) ; @echo $@
%.x: ;
!, '', "hello.z\n");
unlink('hello.z');
# sv 60188.
# Test that a file explicitly mentioned by the user and made by an implicit
# rule is not considered intermediate, even when the builtin rules are used.
touch('hello.x');
touch('hello.tsk');
# subtest 1.
# hello.z is explicitly mentioned and thus is not an intermediate file.
run_make_test(q!
.SECONDEXPANSION:
dep:=hello.z
all: hello.tsk
%.tsk: $$(dep) ; @echo $@
%.z : %.x ; @echo $@
!, '', "hello.z\nhello.tsk");
# subtest 2.
# hello.z is derived from the stem and thus is an intermediate file.
run_make_test(q!
.SECONDEXPANSION:
dep:=.z
all: hello.tsk
%.tsk: %$$(dep) ; @echo $@
%.z : %.x ; @echo $@
!, '', "#MAKE#: Nothing to be done for 'all'.\n");
unlink('hello.x');
unlink('hello.tsk');
# This tells the test driver that the perl test script executed properly.
1;
......@@ -108,4 +108,25 @@ all.foo.bar:
'all.foo
all.one all-one all.foo.two all.foo-two');
# Test #8:
# sv 60188.
# Static pattern rules are considered explicit rules: no prerequisite of
# a static pattern rule can ever be considered intermediate.
touch('hello.z');
# subtest 1
run_make_test(q!
hello.z: %.z: %.x ; @echo $@
%.x: ;
!, '', "hello.z\n");
# subtest 2
run_make_test(q!
hello.z: %.z: test.x ; @echo $@
%.x: ;
!, '', "hello.z\n");
unlink('hello.z');
1;
......@@ -279,4 +279,22 @@ hello
world
');
# Ensure that define can be a target when not appearing in a variable
# definition context. See SV 59870
run_make_test(q!
define = define
$(define) : ;@echo $@
%:define
all: define foo
%.x : define
foo:;
!,
'', "define\n");
1;
......@@ -70,4 +70,22 @@ all: ;@echo ouch
',
'', "#MAKEFILE#:3: *** empty variable name. Stop.\n", 512);
# Ensure that define can be a target when not appearing in a variable
# definition context. See SV 59870
run_make_test(q!
undefine = undefine
$(undefine) : ;@echo $@
%:undefine
all: undefine foo
%.x : undefine
foo:;
!,
'', "undefine\n");
1;