mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2024-12-26 14:00:56 +00:00
Implementation of the second expansion in explicit
rules, static pattern rules and implicit rules.
This commit is contained in:
parent
9d153cc1b1
commit
659fc6b55e
18 changed files with 1113 additions and 340 deletions
46
ChangeLog
46
ChangeLog
|
@ -1,3 +1,49 @@
|
|||
Sun Feb 27 22:03:36 2005 Boris Kolpackov <boris@kolpackov.net>
|
||||
|
||||
Implementation of the second expansion in explicit rules,
|
||||
static pattern rules and implicit rules.
|
||||
|
||||
* read.c (eval): Refrain from chopping up rule's dependencies.
|
||||
Store them in a struct dep as a single dependency line. Remove
|
||||
the code that implements SySV-style automatic variables.
|
||||
|
||||
* read.c (record_files): Adjust the code that handles static
|
||||
pattern rules to expand all percents instead of only the first
|
||||
one. Reverse the order in which dependencies are stored so that
|
||||
when the second expansion reverses them again they appear in
|
||||
the makefile order (with some exceptions, see comments in
|
||||
the code). Remove the code that implements SySV-style automatic
|
||||
variables.
|
||||
|
||||
* file.c (snap_deps): Implement the second expansion and chopping
|
||||
of dependency lines for explicit rules.
|
||||
|
||||
* implicit.c (struct idep): Define an auxiliary data type to hold
|
||||
implicit rule's dependencies after stem substitution and
|
||||
expansion.
|
||||
|
||||
* implicit.c (free_idep_chain): Implement.
|
||||
|
||||
* implicit.c (get_next_word): Implement helper function for
|
||||
parsing implicit rule's dependency lines into words taking
|
||||
into account variable expansion requests. Used in the stem
|
||||
splitting code.
|
||||
|
||||
* implicit.c (pattern_search): Implement the second expansion
|
||||
for implicit rules. Also fixes bug #12091.
|
||||
|
||||
* commands.h (set_file_variables): Declare.
|
||||
* commands.c (set_file_variables): Remove static specifier.
|
||||
|
||||
* dep.h (free_dep_chain): Declare.
|
||||
* misc.c (free_dep_chain): Implement.
|
||||
|
||||
* variable.h (variable_expand_for_file): Declare.
|
||||
* expand.c (variable_expand_for_file): Remove static specifier.
|
||||
|
||||
* make.h (strip_whitespace): Declare.
|
||||
* function.c (strip_whitespace): Remove static specifier.
|
||||
|
||||
2005-02-24 Jonathan Grant <jg@jguk.org>
|
||||
|
||||
* configure.in: Add MinGW configuration options, and extra w32 code
|
||||
|
|
|
@ -38,7 +38,7 @@ extern int getpid ();
|
|||
|
||||
/* Set FILE's automatic variables up. */
|
||||
|
||||
static void
|
||||
void
|
||||
set_file_variables (struct file *file)
|
||||
{
|
||||
struct dep *d;
|
||||
|
|
|
@ -40,3 +40,4 @@ extern void execute_file_commands PARAMS ((struct file *file));
|
|||
extern void print_commands PARAMS ((struct commands *cmds));
|
||||
extern void delete_child_targets PARAMS ((struct child *child));
|
||||
extern void chop_commands PARAMS ((struct commands *cmds));
|
||||
extern void set_file_variables PARAMS ((struct file *file));
|
||||
|
|
1
dep.h
1
dep.h
|
@ -72,6 +72,7 @@ extern char *dep_name ();
|
|||
#endif
|
||||
|
||||
extern struct dep *copy_dep_chain PARAMS ((struct dep *d));
|
||||
extern void free_dep_chain PARAMS ((struct dep *d));
|
||||
extern struct dep *read_all_makefiles PARAMS ((char **makefiles));
|
||||
extern int eval_buffer PARAMS ((char *buffer));
|
||||
extern int update_goal_chain PARAMS ((struct dep *goals));
|
||||
|
|
2
expand.c
2
expand.c
|
@ -440,7 +440,7 @@ expand_argument (const char *str, const char *end)
|
|||
/* Expand LINE for FILE. Error messages refer to the file and line where
|
||||
FILE's commands were found. Expansion uses FILE's variable set list. */
|
||||
|
||||
static char *
|
||||
char *
|
||||
variable_expand_for_file (char *line, struct file *file)
|
||||
{
|
||||
char *result;
|
||||
|
|
109
file.c
109
file.c
|
@ -416,12 +416,14 @@ snap_deps (void)
|
|||
{
|
||||
register struct file *f;
|
||||
register struct file *f2;
|
||||
register struct dep *d;
|
||||
register struct dep *d, *d1;
|
||||
register struct file **file_slot_0;
|
||||
register struct file **file_slot;
|
||||
register struct file **file_end;
|
||||
|
||||
/* Enter each dependency name as a file. */
|
||||
/* Perform second expansion and enter each dependency
|
||||
name as a file. */
|
||||
|
||||
/* We must use hash_dump (), because within this loop
|
||||
we might add new files to the table, possibly causing
|
||||
an in-situ table expansion. */
|
||||
|
@ -429,16 +431,99 @@ snap_deps (void)
|
|||
file_end = file_slot_0 + files.ht_fill;
|
||||
for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
|
||||
for (f2 = *file_slot; f2 != 0; f2 = f2->prev)
|
||||
for (d = f2->deps; d != 0; d = d->next)
|
||||
if (d->name != 0)
|
||||
{
|
||||
d->file = lookup_file (d->name);
|
||||
if (d->file == 0)
|
||||
d->file = enter_file (d->name);
|
||||
else
|
||||
free (d->name);
|
||||
d->name = 0;
|
||||
}
|
||||
{
|
||||
struct dep *new = 0;
|
||||
struct dep *old = f2->deps;
|
||||
unsigned int last_dep_has_cmds = f2->updating;
|
||||
|
||||
f2->updating = 0;
|
||||
f2->deps = 0;
|
||||
|
||||
/* We are going to do second expansion so initialize file
|
||||
variables for the file. */
|
||||
initialize_file_variables (f2, 0);
|
||||
|
||||
for (d = old; d != 0; d = d->next)
|
||||
{
|
||||
if (d->name != 0)
|
||||
{
|
||||
char *p;
|
||||
struct dep **d_ptr;
|
||||
|
||||
set_file_variables (f2);
|
||||
|
||||
p = variable_expand_for_file (d->name, f2);
|
||||
|
||||
/* Parse the dependencies. */
|
||||
new = (struct dep *)
|
||||
multi_glob (
|
||||
parse_file_seq (&p, '|', sizeof (struct dep), 1),
|
||||
sizeof (struct dep));
|
||||
|
||||
if (*p)
|
||||
{
|
||||
/* Files that follow '|' are special prerequisites that
|
||||
need only exist in order to satisfy the dependency.
|
||||
Their modification times are irrelevant. */
|
||||
|
||||
struct dep *d;
|
||||
for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
|
||||
;
|
||||
++p;
|
||||
|
||||
*d_ptr = (struct dep *)
|
||||
multi_glob (
|
||||
parse_file_seq (&p, '\0', sizeof (struct dep), 1),
|
||||
sizeof (struct dep));
|
||||
|
||||
for (d = *d_ptr; d != 0; d = d->next)
|
||||
d->ignore_mtime = 1;
|
||||
}
|
||||
|
||||
/* Enter them as files. */
|
||||
for (d1 = new; d1 != 0; d1 = d1->next)
|
||||
{
|
||||
d1->file = lookup_file (d1->name);
|
||||
if (d1->file == 0)
|
||||
d1->file = enter_file (d1->name);
|
||||
else
|
||||
free (d1->name);
|
||||
d1->name = 0;
|
||||
}
|
||||
|
||||
/* Add newly parsed deps to f2->deps. If this is the last
|
||||
dependency line and this target has commands then put
|
||||
it in front so the last dependency line (the one with
|
||||
commands) ends up being the first. This is important
|
||||
because people expect $< to hold first prerequisite
|
||||
from the rule with commands. If it is not the last
|
||||
dependency line or the rule does not have commands
|
||||
then link it at the end so it appears in makefile
|
||||
order. */
|
||||
|
||||
if (new != 0)
|
||||
{
|
||||
if (d->next == 0 && last_dep_has_cmds)
|
||||
{
|
||||
for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
|
||||
;
|
||||
|
||||
*d_ptr = f2->deps;
|
||||
f2->deps = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (d_ptr = &(f2->deps); *d_ptr; d_ptr = &(*d_ptr)->next)
|
||||
;
|
||||
|
||||
*d_ptr = new;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_dep_chain (old);
|
||||
}
|
||||
free (file_slot_0);
|
||||
|
||||
for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)
|
||||
|
|
|
@ -706,7 +706,7 @@ func_words (char *o, char **argv, const char *funcname UNUSED)
|
|||
* If the string is empty or contains nothing but whitespace, endpp will be
|
||||
* begpp-1.
|
||||
*/
|
||||
static char *
|
||||
char *
|
||||
strip_whitespace (const char **begpp, const char **endpp)
|
||||
{
|
||||
while (*begpp <= *endpp && isspace ((unsigned char)**begpp))
|
||||
|
|
557
implicit.c
557
implicit.c
|
@ -22,9 +22,13 @@ Boston, MA 02111-1307, USA. */
|
|||
#include "rule.h"
|
||||
#include "dep.h"
|
||||
#include "debug.h"
|
||||
#include "variable.h"
|
||||
#include "job.h" /* struct child, used inside commands.h */
|
||||
#include "commands.h" /* set_file_variables */
|
||||
|
||||
static int pattern_search PARAMS ((struct file *file, int archive, unsigned int depth,
|
||||
unsigned int recursions));
|
||||
static int
|
||||
pattern_search PARAMS ((struct file *file, int archive,
|
||||
unsigned int depth, unsigned int recursions));
|
||||
|
||||
/* For a FILE which has no commands specified, try to figure out some
|
||||
from the implicit pattern rules.
|
||||
|
@ -61,6 +65,126 @@ try_implicit_rule (struct file *file, unsigned int depth)
|
|||
}
|
||||
|
||||
|
||||
/* Struct idep captures information about implicit prerequisites
|
||||
that come from implicit rules. */
|
||||
struct idep
|
||||
{
|
||||
struct idep *next; /* struct dep -compatible interface */
|
||||
char *name; /* name of the prerequisite */
|
||||
struct file *intermediate_file; /* intermediate file, 0 otherwise */
|
||||
char *intermediate_pattern; /* pattern for intermediate file */
|
||||
unsigned char had_stem; /* had % substituted with stem */
|
||||
unsigned char ignore_mtime; /* ignore_mtime flag */
|
||||
};
|
||||
|
||||
static void
|
||||
free_idep_chain (struct idep* p)
|
||||
{
|
||||
register struct idep* n;
|
||||
register struct file *f;
|
||||
|
||||
for (; p != 0; p = n)
|
||||
{
|
||||
n = p->next;
|
||||
|
||||
if (p->name)
|
||||
{
|
||||
free (p->name);
|
||||
|
||||
f = p->intermediate_file;
|
||||
|
||||
if (f != 0
|
||||
&& (f->stem < f->name
|
||||
|| f->stem > f->name + strlen (f->name)))
|
||||
free (f->stem);
|
||||
}
|
||||
|
||||
free (p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Scans the BUFFER for the next word with whitespace as a separator.
|
||||
Returns the pointer to the beginning of the word. LENGTH hold the
|
||||
length of the word. */
|
||||
|
||||
static char *
|
||||
get_next_word (char *buffer, unsigned int *length)
|
||||
{
|
||||
char *p = buffer, *beg;
|
||||
char c;
|
||||
|
||||
/* Skip any leading whitespace. */
|
||||
while (isblank ((unsigned char)*p))
|
||||
++p;
|
||||
|
||||
beg = p;
|
||||
c = *(p++);
|
||||
|
||||
if (c == '\0')
|
||||
return 0;
|
||||
|
||||
|
||||
/* We already found the first value of "c", above. */
|
||||
while (1)
|
||||
{
|
||||
char closeparen;
|
||||
int count;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
case ' ':
|
||||
case '\t':
|
||||
goto done_word;
|
||||
|
||||
case '$':
|
||||
c = *(p++);
|
||||
if (c == '$')
|
||||
break;
|
||||
|
||||
/* This is a variable reference, so read it to the matching
|
||||
close paren. */
|
||||
|
||||
if (c == '(')
|
||||
closeparen = ')';
|
||||
else if (c == '{')
|
||||
closeparen = '}';
|
||||
else
|
||||
/* This is a single-letter variable reference. */
|
||||
break;
|
||||
|
||||
for (count = 0; *p != '\0'; ++p)
|
||||
{
|
||||
if (*p == c)
|
||||
++count;
|
||||
else if (*p == closeparen && --count < 0)
|
||||
{
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '|':
|
||||
goto done;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
c = *(p++);
|
||||
}
|
||||
done_word:
|
||||
--p;
|
||||
|
||||
done:
|
||||
if (length)
|
||||
*length = p - beg;
|
||||
|
||||
return beg;
|
||||
}
|
||||
|
||||
/* Search the pattern rules for a rule with an existing dependency to make
|
||||
FILE. If a rule is found, the appropriate commands and deps are put in FILE
|
||||
and 1 is returned. If not, 0 is returned.
|
||||
|
@ -93,20 +217,13 @@ pattern_search (struct file *file, int archive,
|
|||
except during a recursive call. */
|
||||
struct file *intermediate_file = 0;
|
||||
|
||||
/* List of dependencies found recursively. */
|
||||
struct file **intermediate_files
|
||||
= (struct file **) xmalloc (max_pattern_deps * sizeof (struct file *));
|
||||
/* This linked list records all the prerequisites actually
|
||||
found for a rule along with some other useful information
|
||||
(see struct idep for details). */
|
||||
struct idep* deps = 0;
|
||||
|
||||
/* List of the patterns used to find intermediate files. */
|
||||
char **intermediate_patterns
|
||||
= (char **) alloca (max_pattern_deps * sizeof (char *));
|
||||
|
||||
/* This buffer records all the dependencies actually found for a rule. */
|
||||
char **found_files = (char **) alloca (max_pattern_deps * sizeof (char *));
|
||||
/* Remember whether the associated dep has an "ignore_mtime" flag set. */
|
||||
unsigned char *found_files_im = (unsigned char *) alloca (max_pattern_deps * sizeof (unsigned char));
|
||||
/* Number of dep names now in FOUND_FILES. */
|
||||
unsigned int deps_found = 0;
|
||||
/* 1 if we need to remove explicit prerequisites, 0 otherwise. */
|
||||
unsigned int remove_explicit_deps = 0;
|
||||
|
||||
/* Names of possible dependencies are constructed in this buffer. */
|
||||
register char *depname = (char *) alloca (namelen + max_pattern_dep_length);
|
||||
|
@ -146,9 +263,13 @@ pattern_search (struct file *file, int archive,
|
|||
|
||||
register unsigned int i = 0; /* uninit checks OK */
|
||||
register struct rule *rule;
|
||||
register struct dep *dep;
|
||||
register struct dep *dep, *expl_d;
|
||||
|
||||
char *p, *vp;
|
||||
char *p, *vname;
|
||||
|
||||
struct idep *d;
|
||||
struct idep **id_ptr;
|
||||
struct dep **d_ptr;
|
||||
|
||||
#ifndef NO_ARCHIVES
|
||||
if (archive || ar_name (filename))
|
||||
|
@ -295,19 +416,27 @@ pattern_search (struct file *file, int archive,
|
|||
tryrules[i] = 0;
|
||||
}
|
||||
|
||||
/* We are going to do second expansion so initialize file variables
|
||||
for the rule. */
|
||||
initialize_file_variables (file, 0);
|
||||
|
||||
/* Try each rule once without intermediate files, then once with them. */
|
||||
for (intermed_ok = 0; intermed_ok == !!intermed_ok; ++intermed_ok)
|
||||
{
|
||||
/* Try each pattern rule till we find one that applies.
|
||||
If it does, copy the names of its dependencies (as substituted)
|
||||
and store them in FOUND_FILES. DEPS_FOUND is the number of them. */
|
||||
If it does, expand its dependencies (as substituted)
|
||||
and chain them in DEPS. */
|
||||
|
||||
for (i = 0; i < nrules; i++)
|
||||
{
|
||||
struct file *f;
|
||||
unsigned int failed = 0;
|
||||
int check_lastslash;
|
||||
|
||||
rule = tryrules[i];
|
||||
|
||||
remove_explicit_deps = 0;
|
||||
|
||||
/* RULE is nil when we discover that a rule,
|
||||
already placed in TRYRULES, should not be applied. */
|
||||
if (rule == 0)
|
||||
|
@ -337,149 +466,258 @@ pattern_search (struct file *file, int archive,
|
|||
DBS (DB_IMPLICIT, (_("Trying pattern rule with stem `%.*s'.\n"),
|
||||
(int) stemlen, stem));
|
||||
|
||||
/* Temporary assign STEM to file->stem and set file variables. */
|
||||
file->stem = stem;
|
||||
set_file_variables (file);
|
||||
|
||||
/* Try each dependency; see if it "exists". */
|
||||
|
||||
deps_found = 0;
|
||||
/* @@ There is always only one dep line for any given implicit
|
||||
rule. So the loop is not necessary. Can rule->deps be 0?
|
||||
|
||||
Watch out for conversion of suffix rules to implicit rules.
|
||||
*/
|
||||
|
||||
for (dep = rule->deps; dep != 0; dep = dep->next)
|
||||
{
|
||||
struct file *f;
|
||||
unsigned int len;
|
||||
char *p2;
|
||||
unsigned int order_only = 0; /* Set if '|' was seen. */
|
||||
|
||||
/* If the dependency name has a %, substitute the stem. */
|
||||
p = strchr (dep_name (dep), '%');
|
||||
if (p != 0)
|
||||
{
|
||||
register unsigned int i;
|
||||
if (check_lastslash)
|
||||
{
|
||||
/* Copy directory name from the original FILENAME. */
|
||||
i = lastslash - filename + 1;
|
||||
bcopy (filename, depname, i);
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
bcopy (dep_name (dep), depname + i, p - dep_name (dep));
|
||||
i += p - dep_name (dep);
|
||||
bcopy (stem, depname + i, stemlen);
|
||||
i += stemlen;
|
||||
strcpy (depname + i, p + 1);
|
||||
p = depname;
|
||||
}
|
||||
else
|
||||
p = dep_name (dep);
|
||||
/* In an ideal world we would take the dependency line,
|
||||
substitute the stem, re-expand the whole line and
|
||||
chop it into individual prerequisites. Unfortunately
|
||||
this won't work because of the "check_lastslash" twist.
|
||||
Instead, we will have to go word by word, taking $()'s
|
||||
into account, for each word we will substitute the stem,
|
||||
re-expand, chop it up, and, if check_lastslash != 0,
|
||||
add the directory part to each resulting prerequisite. */
|
||||
|
||||
/* P is now the actual dependency name as substituted. */
|
||||
p = get_next_word (dep->name, &len);
|
||||
|
||||
if (file_impossible_p (p))
|
||||
{
|
||||
/* If this dependency has already been ruled
|
||||
"impossible", then the rule fails and don't
|
||||
bother trying it on the second pass either
|
||||
since we know that will fail too. */
|
||||
DBS (DB_IMPLICIT,
|
||||
(p == depname
|
||||
while (1)
|
||||
{
|
||||
int add_dir = 0;
|
||||
int had_stem = 0;
|
||||
|
||||
if (p == 0)
|
||||
break; /* No more words */
|
||||
|
||||
/* If the dependency name has %, substitute the stem. */
|
||||
|
||||
for (p2 = p; p2 < p + len && *p2 != '%'; ++p2);
|
||||
|
||||
if (p2 < p + len)
|
||||
{
|
||||
register unsigned int i = p2 - p;
|
||||
bcopy (p, depname, i);
|
||||
bcopy (stem, depname + i, stemlen);
|
||||
bcopy (p2 + 1, depname + i + stemlen, len - i - 1);
|
||||
depname[len + stemlen - 1] = '\0';
|
||||
|
||||
if (check_lastslash)
|
||||
add_dir = 1;
|
||||
|
||||
had_stem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bcopy (p, depname, len);
|
||||
depname[len] = '\0';
|
||||
}
|
||||
|
||||
p2 = variable_expand_for_file (depname, file);
|
||||
|
||||
/* Parse the dependencies. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
id_ptr = &deps;
|
||||
|
||||
for (; *id_ptr; id_ptr = &(*id_ptr)->next)
|
||||
;
|
||||
|
||||
*id_ptr = (struct idep *)
|
||||
multi_glob (
|
||||
parse_file_seq (&p2,
|
||||
order_only ? '\0' : '|',
|
||||
sizeof (struct idep),
|
||||
1), sizeof (struct idep));
|
||||
|
||||
/* @@ It would be nice to teach parse_file_seq or
|
||||
multi_glob to add prefix. This would save us
|
||||
some reallocations. */
|
||||
|
||||
if (order_only || add_dir || had_stem)
|
||||
{
|
||||
unsigned long l = lastslash - filename + 1;
|
||||
|
||||
for (d = *id_ptr; d != 0; d = d->next)
|
||||
{
|
||||
if (order_only)
|
||||
d->ignore_mtime = 1;
|
||||
|
||||
if (add_dir)
|
||||
{
|
||||
char *p = d->name;
|
||||
|
||||
d->name = xmalloc (strlen (p) + l + 1);
|
||||
|
||||
bcopy (filename, d->name, l);
|
||||
bcopy (p, d->name + l, strlen (p) + 1);
|
||||
|
||||
free (p);
|
||||
}
|
||||
|
||||
if (had_stem)
|
||||
d->had_stem = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!order_only && *p2)
|
||||
{
|
||||
++p2;
|
||||
order_only = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
p += len;
|
||||
p = get_next_word (p, &len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the stem in FILE. */
|
||||
|
||||
file->stem = 0;
|
||||
|
||||
/* @@ This loop can be combined with the previous one. I do
|
||||
it separately for now for transparency.*/
|
||||
|
||||
for (d = deps; d != 0; d = d->next)
|
||||
{
|
||||
char *name = d->name;
|
||||
|
||||
if (file_impossible_p (name))
|
||||
{
|
||||
/* If this dependency has already been ruled
|
||||
"impossible", then the rule fails and don't
|
||||
bother trying it on the second pass either
|
||||
since we know that will fail too. */
|
||||
DBS (DB_IMPLICIT,
|
||||
(d->had_stem
|
||||
? _("Rejecting impossible implicit prerequisite `%s'.\n")
|
||||
: _("Rejecting impossible rule prerequisite `%s'.\n"),
|
||||
p));
|
||||
tryrules[i] = 0;
|
||||
break;
|
||||
}
|
||||
name));
|
||||
tryrules[i] = 0;
|
||||
|
||||
intermediate_files[deps_found] = 0;
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
DBS (DB_IMPLICIT,
|
||||
(p == depname
|
||||
DBS (DB_IMPLICIT,
|
||||
(d->had_stem
|
||||
? _("Trying implicit prerequisite `%s'.\n")
|
||||
: _("Trying rule prerequisite `%s'.\n"), p));
|
||||
: _("Trying rule prerequisite `%s'.\n"), name));
|
||||
|
||||
/* The DEP->changed flag says that this dependency resides in a
|
||||
nonexistent directory. So we normally can skip looking for
|
||||
the file. However, if CHECK_LASTSLASH is set, then the
|
||||
dependency file we are actually looking for is in a different
|
||||
directory (the one gotten by prepending FILENAME's directory),
|
||||
so it might actually exist. */
|
||||
/* If this prerequisite also happened to be explicitly
|
||||
mentioned for FILE skip all the test below since it
|
||||
it has to be built anyway, no matter which implicit
|
||||
rule we choose. */
|
||||
|
||||
if (((f = lookup_file (p)) != 0 && f->is_target)
|
||||
|| ((!dep->changed || check_lastslash) && file_exists_p (p)))
|
||||
{
|
||||
found_files_im[deps_found] = dep->ignore_mtime;
|
||||
found_files[deps_found++] = xstrdup (p);
|
||||
continue;
|
||||
}
|
||||
/* This code, given FILENAME = "lib/foo.o", dependency name
|
||||
"lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */
|
||||
vp = p;
|
||||
if (vpath_search (&vp, (FILE_TIMESTAMP *) 0))
|
||||
{
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Found prerequisite `%s' as VPATH `%s'\n"), p, vp));
|
||||
strcpy (vp, p);
|
||||
found_files_im[deps_found] = dep->ignore_mtime;
|
||||
found_files[deps_found++] = vp;
|
||||
continue;
|
||||
}
|
||||
for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next)
|
||||
if (strcmp (dep_name (expl_d), name) == 0) break;
|
||||
|
||||
/* We could not find the file in any place we should look.
|
||||
Try to make this dependency as an intermediate file,
|
||||
but only on the second pass. */
|
||||
if (expl_d != 0)
|
||||
continue;
|
||||
|
||||
if (intermed_ok)
|
||||
{
|
||||
if (intermediate_file == 0)
|
||||
intermediate_file
|
||||
= (struct file *) alloca (sizeof (struct file));
|
||||
|
||||
DBS (DB_IMPLICIT,
|
||||
|
||||
/* The DEP->changed flag says that this dependency resides in a
|
||||
nonexistent directory. So we normally can skip looking for
|
||||
the file. However, if CHECK_LASTSLASH is set, then the
|
||||
dependency file we are actually looking for is in a different
|
||||
directory (the one gotten by prepending FILENAME's directory),
|
||||
so it might actually exist. */
|
||||
|
||||
/* @@ dep->changed check is disabled. */
|
||||
if (((f = lookup_file (name)) != 0 && f->is_target)
|
||||
/*|| ((!dep->changed || check_lastslash) && */
|
||||
|| file_exists_p (name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This code, given FILENAME = "lib/foo.o", dependency name
|
||||
"lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */
|
||||
vname = name;
|
||||
if (vpath_search (&vname, (FILE_TIMESTAMP *) 0))
|
||||
{
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Found prerequisite `%s' as VPATH `%s'\n"),
|
||||
name,
|
||||
vname));
|
||||
|
||||
free (vname);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* We could not find the file in any place we should look.
|
||||
Try to make this dependency as an intermediate file,
|
||||
but only on the second pass. */
|
||||
|
||||
if (intermed_ok)
|
||||
{
|
||||
if (intermediate_file == 0)
|
||||
intermediate_file
|
||||
= (struct file *) alloca (sizeof (struct file));
|
||||
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Looking for a rule with intermediate file `%s'.\n"),
|
||||
p));
|
||||
name));
|
||||
|
||||
bzero ((char *) intermediate_file, sizeof (struct file));
|
||||
intermediate_file->name = p;
|
||||
if (pattern_search (intermediate_file, 0, depth + 1,
|
||||
recursions + 1))
|
||||
{
|
||||
p = xstrdup (p);
|
||||
intermediate_patterns[deps_found]
|
||||
= intermediate_file->name;
|
||||
intermediate_file->name = p;
|
||||
intermediate_files[deps_found] = intermediate_file;
|
||||
intermediate_file = 0;
|
||||
found_files_im[deps_found] = dep->ignore_mtime;
|
||||
/* Allocate an extra copy to go in FOUND_FILES,
|
||||
because every elt of FOUND_FILES is consumed
|
||||
or freed later. */
|
||||
found_files[deps_found++] = xstrdup (p);
|
||||
continue;
|
||||
}
|
||||
bzero ((char *) intermediate_file, sizeof (struct file));
|
||||
intermediate_file->name = name;
|
||||
if (pattern_search (intermediate_file,
|
||||
0,
|
||||
depth + 1,
|
||||
recursions + 1))
|
||||
{
|
||||
d->intermediate_file = intermediate_file;
|
||||
d->intermediate_pattern = intermediate_file->name;
|
||||
|
||||
/* If we have tried to find P as an intermediate
|
||||
file and failed, mark that name as impossible
|
||||
so we won't go through the search again later. */
|
||||
file_impossible (p);
|
||||
}
|
||||
intermediate_file->name = xstrdup (name);
|
||||
intermediate_file = 0;
|
||||
|
||||
/* A dependency of this rule does not exist.
|
||||
Therefore, this rule fails. */
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This rule is no longer `in use' for recursive searches. */
|
||||
/* If we have tried to find P as an intermediate
|
||||
file and failed, mark that name as impossible
|
||||
so we won't go through the search again later. */
|
||||
file_impossible (name);
|
||||
}
|
||||
|
||||
/* A dependency of this rule does not exist. Therefore,
|
||||
this rule fails. */
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* This rule is no longer `in use' for recursive searches. */
|
||||
rule->in_use = 0;
|
||||
|
||||
if (dep != 0)
|
||||
{
|
||||
/* This pattern rule does not apply.
|
||||
If some of its dependencies succeeded,
|
||||
free the data structure describing them. */
|
||||
while (deps_found-- > 0)
|
||||
{
|
||||
register struct file *f = intermediate_files[deps_found];
|
||||
free (found_files[deps_found]);
|
||||
if (f != 0
|
||||
&& (f->stem < f->name
|
||||
|| f->stem > f->name + strlen (f->name)))
|
||||
free (f->stem);
|
||||
}
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
/* This pattern rule does not apply. If some of its
|
||||
dependencies succeeded, free the data structure
|
||||
describing them. */
|
||||
free_idep_chain (deps);
|
||||
deps = 0;
|
||||
}
|
||||
else
|
||||
/* This pattern rule does apply. Stop looking for one. */
|
||||
break;
|
||||
|
@ -511,11 +749,30 @@ pattern_search (struct file *file, int archive,
|
|||
This includes the intermediate files, if any.
|
||||
Convert them into entries on the deps-chain of FILE. */
|
||||
|
||||
while (deps_found-- > 0)
|
||||
if (remove_explicit_deps)
|
||||
{
|
||||
/* Remove all the dependencies that didn't come from
|
||||
this implicit rule. */
|
||||
|
||||
dep = file->deps;
|
||||
while (dep != 0)
|
||||
{
|
||||
struct dep *next = dep->next;
|
||||
free (dep->name);
|
||||
free ((char *)dep);
|
||||
dep = next;
|
||||
}
|
||||
file->deps = 0;
|
||||
}
|
||||
|
||||
expl_d = file->deps; /* We will add them at the end. */
|
||||
d_ptr = &file->deps;
|
||||
|
||||
for (d = deps; d != 0; d = d->next)
|
||||
{
|
||||
register char *s;
|
||||
|
||||
if (intermediate_files[deps_found] != 0)
|
||||
if (d->intermediate_file != 0)
|
||||
{
|
||||
/* If we need to use an intermediate file,
|
||||
make sure it is entered as a target, with the info that was
|
||||
|
@ -524,13 +781,13 @@ pattern_search (struct file *file, int archive,
|
|||
a target; therefore we can assume that the deps and cmds
|
||||
of F below are null before we change them. */
|
||||
|
||||
struct file *imf = intermediate_files[deps_found];
|
||||
struct file *imf = d->intermediate_file;
|
||||
register struct file *f = enter_file (imf->name);
|
||||
f->deps = imf->deps;
|
||||
f->cmds = imf->cmds;
|
||||
f->stem = imf->stem;
|
||||
f->also_make = imf->also_make;
|
||||
imf = lookup_file (intermediate_patterns[deps_found]);
|
||||
imf = lookup_file (d->intermediate_pattern);
|
||||
if (imf != 0 && imf->precious)
|
||||
f->precious = 1;
|
||||
f->intermediate = 1;
|
||||
|
@ -547,8 +804,9 @@ pattern_search (struct file *file, int archive,
|
|||
}
|
||||
|
||||
dep = (struct dep *) xmalloc (sizeof (struct dep));
|
||||
dep->ignore_mtime = found_files_im[deps_found];
|
||||
s = found_files[deps_found];
|
||||
dep->ignore_mtime = d->ignore_mtime;
|
||||
s = d->name; /* Hijacking the name. */
|
||||
d->name = 0;
|
||||
if (recursions == 0)
|
||||
{
|
||||
dep->name = 0;
|
||||
|
@ -567,7 +825,7 @@ pattern_search (struct file *file, int archive,
|
|||
dep->file = 0;
|
||||
dep->changed = 0;
|
||||
}
|
||||
if (intermediate_files[deps_found] == 0 && tryrules[foundrule]->terminal)
|
||||
if (d->intermediate_file == 0 && tryrules[foundrule]->terminal)
|
||||
{
|
||||
/* If the file actually existed (was not an intermediate file),
|
||||
and the rule that found it was a terminal one, then we want
|
||||
|
@ -579,10 +837,13 @@ pattern_search (struct file *file, int archive,
|
|||
else
|
||||
dep->file->tried_implicit = 1;
|
||||
}
|
||||
dep->next = file->deps;
|
||||
file->deps = dep;
|
||||
|
||||
*d_ptr = dep;
|
||||
d_ptr = &dep->next;
|
||||
}
|
||||
|
||||
*d_ptr = expl_d;
|
||||
|
||||
if (!checked_lastslash[foundrule])
|
||||
{
|
||||
/* Always allocate new storage, since STEM might be
|
||||
|
@ -629,7 +890,7 @@ pattern_search (struct file *file, int archive,
|
|||
}
|
||||
|
||||
done:
|
||||
free (intermediate_files);
|
||||
free_idep_chain (deps);
|
||||
free (tryrules);
|
||||
|
||||
return rule != 0;
|
||||
|
|
4
make.h
4
make.h
|
@ -460,6 +460,10 @@ extern void user_access PARAMS ((void));
|
|||
extern void make_access PARAMS ((void));
|
||||
extern void child_access PARAMS ((void));
|
||||
|
||||
extern char *
|
||||
strip_whitespace PARAMS ((const char **begpp, const char **endpp));
|
||||
|
||||
|
||||
#ifdef HAVE_VFORK_H
|
||||
# include <vfork.h>
|
||||
#endif
|
||||
|
|
21
misc.c
21
misc.c
|
@ -525,6 +525,27 @@ copy_dep_chain (struct dep *d)
|
|||
return firstnew;
|
||||
}
|
||||
|
||||
/* Free a chain of `struct dep'. Each dep->name is freed
|
||||
as well. */
|
||||
|
||||
void
|
||||
free_dep_chain (struct dep *d)
|
||||
{
|
||||
register struct dep *tmp;
|
||||
|
||||
while (d != 0)
|
||||
{
|
||||
if (d->name != 0)
|
||||
free (d->name);
|
||||
|
||||
tmp = d;
|
||||
|
||||
d = d->next;
|
||||
|
||||
free (tmp);
|
||||
}
|
||||
|
||||
}
|
||||
#ifdef iAPX286
|
||||
/* The losing compiler on this machine can't handle this macro. */
|
||||
|
||||
|
|
258
read.c
258
read.c
|
@ -134,7 +134,6 @@ 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,
|
||||
int have_sysv_atvar,
|
||||
const struct floc *flocp, int set_default));
|
||||
static void record_target_var PARAMS ((struct nameseq *filenames, char *defn,
|
||||
enum variable_origin origin,
|
||||
|
@ -457,7 +456,6 @@ eval (struct ebuffer *ebuf, int 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;
|
||||
|
@ -474,7 +472,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
fi.lineno = tgts_started; \
|
||||
record_files (filenames, pattern, pattern_percent, deps, \
|
||||
cmds_started, commands, commands_idx, two_colon, \
|
||||
have_sysv_atvar, &fi, set_default); \
|
||||
&fi, set_default); \
|
||||
} \
|
||||
filenames = 0; \
|
||||
commands_idx = 0; \
|
||||
|
@ -869,6 +867,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
char *cmdleft, *semip, *lb_next;
|
||||
unsigned int len, plen = 0;
|
||||
char *colonp;
|
||||
const char *end, *beg; /* Helpers for whitespace stripping. */
|
||||
|
||||
/* Record the previous rule. */
|
||||
|
||||
|
@ -917,6 +916,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
}
|
||||
|
||||
p2 = variable_expand_string(NULL, lb_next, len);
|
||||
|
||||
while (1)
|
||||
{
|
||||
lb_next += len;
|
||||
|
@ -1094,16 +1094,6 @@ eval (struct ebuffer *ebuf, int 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[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] == '\\')
|
||||
|
@ -1168,26 +1158,20 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
else
|
||||
pattern = 0;
|
||||
|
||||
/* Parse the dependencies. */
|
||||
deps = (struct dep *)
|
||||
multi_glob (parse_file_seq (&p2, '|', sizeof (struct dep), 1),
|
||||
sizeof (struct dep));
|
||||
if (*p2)
|
||||
/* Strip leading and trailing whitespaces. */
|
||||
beg = p2;
|
||||
end = beg + strlen (beg) - 1;
|
||||
strip_whitespace (&beg, &end);
|
||||
|
||||
if (beg <= end && *beg != '\0')
|
||||
{
|
||||
/* Files that follow '|' are special prerequisites that
|
||||
need only exist in order to satisfy the dependency.
|
||||
Their modification times are irrelevant. */
|
||||
struct dep **deps_ptr = &deps;
|
||||
struct dep *d;
|
||||
for (deps_ptr = &deps; *deps_ptr; deps_ptr = &(*deps_ptr)->next)
|
||||
;
|
||||
++p2;
|
||||
*deps_ptr = (struct dep *)
|
||||
multi_glob (parse_file_seq (&p2, '\0', sizeof (struct dep), 1),
|
||||
sizeof (struct dep));
|
||||
for (d = *deps_ptr; d != 0; d = d->next)
|
||||
d->ignore_mtime = 1;
|
||||
deps = (struct dep*) xmalloc (sizeof (struct dep));
|
||||
deps->next = 0;
|
||||
deps->name = savestring (beg, end - beg + 1);
|
||||
deps->file = 0;
|
||||
}
|
||||
else
|
||||
deps = 0;
|
||||
|
||||
commands_idx = 0;
|
||||
if (cmdleft != 0)
|
||||
|
@ -1753,7 +1737,7 @@ static void
|
|||
record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
|
||||
struct dep *deps, unsigned int cmds_started, char *commands,
|
||||
unsigned int commands_idx, int two_colon,
|
||||
int have_sysv_atvar, const struct floc *flocp, int set_default)
|
||||
const struct floc *flocp, int set_default)
|
||||
{
|
||||
struct nameseq *nextf;
|
||||
int implicit = 0;
|
||||
|
@ -1846,126 +1830,35 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
|
|||
/* We use patsubst_expand to do the work of translating
|
||||
the target pattern, the target's name and the dependencies'
|
||||
patterns into plain dependency names. */
|
||||
char *buffer = variable_expand ("");
|
||||
|
||||
for (d = this; d != 0; d = d->next)
|
||||
{
|
||||
char *o;
|
||||
char *percent = find_percent (d->name);
|
||||
if (percent == 0)
|
||||
continue;
|
||||
o = patsubst_expand (buffer, name, pattern, d->name,
|
||||
pattern_percent+1, percent+1);
|
||||
if (find_percent (this->name) != 0)
|
||||
{
|
||||
char stem[PATH_MAX];
|
||||
char *o;
|
||||
char *buffer = variable_expand ("");
|
||||
|
||||
o = patsubst_expand (buffer, name, pattern, "%",
|
||||
pattern_percent + 1, 0);
|
||||
|
||||
|
||||
strncpy (stem, buffer, o - buffer);
|
||||
stem[o - buffer] = '\0';
|
||||
|
||||
o = subst_expand (buffer, this->name, "%", stem,
|
||||
1, strlen (stem), 0);
|
||||
|
||||
/* If the name expanded to the empty string, that's
|
||||
illegal. */
|
||||
if (o == buffer)
|
||||
fatal (flocp,
|
||||
_("target `%s' leaves prerequisite pattern empty"),
|
||||
name);
|
||||
free (d->name);
|
||||
d->name = savestring (buffer, o - buffer);
|
||||
free (this->name);
|
||||
this->name = savestring (buffer, o - buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 '$@', '$(@', or '${@', it's escaped */
|
||||
if ((++p)[0] == '$'
|
||||
&& (p[1] == '@'
|
||||
|| ((p[1] == '(' || p[1] == '{') && p[2] == '@')))
|
||||
{
|
||||
bcopy (p, s, strlen (p)+1);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Maybe found one. We like anything of any form matching @,
|
||||
[({]@[}):], or [({]@[DF][}):]. */
|
||||
|
||||
if (! (p[0] == '@'
|
||||
|| ((p[0] == '(' || p[0] == '{') && (++p)[0] == '@'
|
||||
&& (((++p)[0] == ')' || p[0] == '}' || p[0] == ':')
|
||||
|| ((p[1] == ')' || p[1] == '}' || 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
|
||||
|
@ -2003,6 +1896,7 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
|
|||
f->cmds = 0;
|
||||
if (cmds != 0)
|
||||
f->cmds = cmds;
|
||||
|
||||
/* Defining .SUFFIXES with no dependencies
|
||||
clears out the list of suffixes. */
|
||||
if (f == suffix_file && this == 0)
|
||||
|
@ -2017,41 +1911,63 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
|
|||
}
|
||||
f->deps = 0;
|
||||
}
|
||||
else if (f->deps != 0)
|
||||
else if (this != 0)
|
||||
{
|
||||
/* Add the file's old deps and the new ones in THIS together. */
|
||||
|
||||
struct dep *firstdeps, *moredeps;
|
||||
if (cmds != 0)
|
||||
{
|
||||
/* This is the rule with commands, so put its deps first.
|
||||
The rationale behind this is that $< expands to the
|
||||
first dep in the chain, and commands use $< expecting
|
||||
to get the dep that rule specifies. */
|
||||
firstdeps = this;
|
||||
moredeps = f->deps;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Append the new deps to the old ones. */
|
||||
firstdeps = f->deps;
|
||||
moredeps = this;
|
||||
}
|
||||
if (f->deps != 0)
|
||||
{
|
||||
struct dep **d_ptr = &f->deps;
|
||||
|
||||
if (firstdeps == 0)
|
||||
firstdeps = moredeps;
|
||||
else
|
||||
{
|
||||
d = firstdeps;
|
||||
while (d->next != 0)
|
||||
d = d->next;
|
||||
d->next = moredeps;
|
||||
}
|
||||
while ((*d_ptr)->next != 0)
|
||||
d_ptr = &(*d_ptr)->next;
|
||||
|
||||
f->deps = firstdeps;
|
||||
if (cmds != 0)
|
||||
{
|
||||
/* This is the rule with commands, so put its deps
|
||||
last. The rationale behind this is that $< expands
|
||||
to the first dep in the chain, and commands use $<
|
||||
expecting to get the dep that rule specifies.
|
||||
However the second expansion algorithm reverses
|
||||
the order thus we need to make it last here. */
|
||||
|
||||
(*d_ptr)->next = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is the rule without commands. Put its
|
||||
dependencies at the end but before dependencies
|
||||
from the rule with commands (if any). This way
|
||||
everyhting appears in makefile order. */
|
||||
|
||||
if (f->cmds != 0)
|
||||
{
|
||||
this->next = *d_ptr;
|
||||
*d_ptr = this;
|
||||
}
|
||||
else
|
||||
(*d_ptr)->next = this;
|
||||
}
|
||||
}
|
||||
else
|
||||
f->deps = this;
|
||||
|
||||
/* This is a hack. I need a way to communicate to snap_deps()
|
||||
that the last dependency line in this file came with commands
|
||||
(so that logic in snap_deps() can put it in front and all
|
||||
this $< -logic works). I cannot's simply rely oon file->cmds
|
||||
being not 0 because of the cases like the following:
|
||||
|
||||
foo: bar
|
||||
foo:
|
||||
...
|
||||
|
||||
I am going to temporarily "borrow" UPDATING member in
|
||||
`struct file' for this. */
|
||||
|
||||
if (cmds != 0)
|
||||
f->updating = 1;
|
||||
}
|
||||
else
|
||||
f->deps = this;
|
||||
|
||||
/* If this is a static pattern rule, set the file's stem to
|
||||
the part of its name that matched the `%' in the pattern,
|
||||
|
@ -2135,7 +2051,7 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
|
|||
}
|
||||
|
||||
if (!reject)
|
||||
default_goal_file = f;
|
||||
default_goal_file = f;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
Sun Feb 27 23:33:32 2005 Boris Kolpackov <boris@kolpackov.net>
|
||||
|
||||
* scripts/features/se_explicit: Test the second expansion in
|
||||
explicit rules.
|
||||
|
||||
* scripts/features/se_implicit: Test the second expansion in
|
||||
implicit rules.
|
||||
|
||||
* scripts/features/se_statpat: Test the second expansion in
|
||||
static pattern rules.
|
||||
|
||||
* tests/scripts/variables/automatic: Fix to work with the second
|
||||
expansion.
|
||||
|
||||
* scripts/misc/general4: Add a test for bug #12091.
|
||||
|
||||
2005-02-09 Paul D. Smith <psmith@gnu.org>
|
||||
|
||||
* scripts/features/recursion: Test command line variable settings:
|
||||
|
|
105
tests/scripts/features/se_explicit
Normal file
105
tests/scripts/features/se_explicit
Normal file
|
@ -0,0 +1,105 @@
|
|||
# -*-perl-*-
|
||||
$description = "Test second expansion in ordinary rules.";
|
||||
|
||||
$details = "";
|
||||
|
||||
# Test #1: automatic variables.
|
||||
#
|
||||
run_make_test('
|
||||
.DEFAULT: ; @echo $@
|
||||
|
||||
foo: bar baz
|
||||
|
||||
foo: biz | buz
|
||||
|
||||
foo: $$@.1 \
|
||||
$$<.2 \
|
||||
$$(addsuffix .3,$$^) \
|
||||
$$(addsuffix .4,$$+) \
|
||||
$$|.5 \
|
||||
$$*.6
|
||||
|
||||
',
|
||||
'',
|
||||
'bar
|
||||
baz
|
||||
biz
|
||||
buz
|
||||
foo.1
|
||||
bar.2
|
||||
bar.3
|
||||
baz.3
|
||||
biz.3
|
||||
bar.4
|
||||
baz.4
|
||||
biz.4
|
||||
buz.5
|
||||
.6
|
||||
');
|
||||
|
||||
|
||||
# Test #2: target/pattern -specific variables.
|
||||
#
|
||||
run_make_test('
|
||||
.DEFAULT: ; @echo $@
|
||||
|
||||
foo.x: $$a $$b
|
||||
|
||||
foo.x: a := bar
|
||||
|
||||
%.x: b := baz
|
||||
|
||||
',
|
||||
'',
|
||||
'bar
|
||||
baz
|
||||
');
|
||||
|
||||
|
||||
# Test #3: order of prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
.DEFAULT: ; @echo $@
|
||||
|
||||
all: foo bar baz
|
||||
|
||||
# Subtest #1
|
||||
#
|
||||
foo: foo.1; @:
|
||||
|
||||
foo: foo.2
|
||||
|
||||
foo: foo.3
|
||||
|
||||
|
||||
# Subtest #2
|
||||
#
|
||||
bar: bar.2
|
||||
|
||||
bar: bar.1; @:
|
||||
|
||||
bar: bar.3
|
||||
|
||||
|
||||
# Subtest #3
|
||||
#
|
||||
baz: baz.1
|
||||
|
||||
baz: baz.2
|
||||
|
||||
baz: ; @:
|
||||
|
||||
',
|
||||
'',
|
||||
'foo.1
|
||||
foo.2
|
||||
foo.3
|
||||
bar.1
|
||||
bar.2
|
||||
bar.3
|
||||
baz.1
|
||||
baz.2
|
||||
');
|
||||
|
||||
# This tells the test driver that the perl test script executed properly.
|
||||
1;
|
188
tests/scripts/features/se_implicit
Normal file
188
tests/scripts/features/se_implicit
Normal file
|
@ -0,0 +1,188 @@
|
|||
# -*-perl-*-
|
||||
$description = "Test second expansion in ordinary rules.";
|
||||
|
||||
$details = "";
|
||||
|
||||
use Cwd;
|
||||
|
||||
$dir = cwd;
|
||||
$dir =~ s,.*/([^/]+)$,../$1,;
|
||||
|
||||
|
||||
# Test #1: automatic variables.
|
||||
#
|
||||
run_make_test('
|
||||
.DEFAULT: ; @echo $@
|
||||
|
||||
foo.a: bar baz
|
||||
|
||||
foo.a: biz | buz
|
||||
|
||||
foo.%: 1.$$@ \
|
||||
2.$$< \
|
||||
$$(addprefix 3.,$$^) \
|
||||
$$(addprefix 4.,$$+) \
|
||||
5.$$| \
|
||||
6.$$*
|
||||
@:
|
||||
|
||||
1.foo.a \
|
||||
2.bar \
|
||||
3.bar \
|
||||
3.baz \
|
||||
3.biz \
|
||||
4.bar \
|
||||
4.baz \
|
||||
4.biz \
|
||||
5.buz \
|
||||
6.a:
|
||||
@echo $@
|
||||
|
||||
',
|
||||
'',
|
||||
'1.foo.a
|
||||
2.bar
|
||||
3.bar
|
||||
3.baz
|
||||
3.biz
|
||||
4.bar
|
||||
4.baz
|
||||
4.biz
|
||||
5.buz
|
||||
6.a
|
||||
bar
|
||||
baz
|
||||
biz
|
||||
buz
|
||||
');
|
||||
|
||||
|
||||
# Test #2: target/pattern -specific variables.
|
||||
#
|
||||
run_make_test('
|
||||
foo.x:
|
||||
|
||||
foo.%: $$(%_a) $$(%_b) bar
|
||||
@:
|
||||
|
||||
foo.x: x_a := bar
|
||||
|
||||
%.x: x_b := baz
|
||||
|
||||
bar baz: ; @echo $@
|
||||
|
||||
',
|
||||
'',
|
||||
'bar
|
||||
baz
|
||||
');
|
||||
|
||||
|
||||
# Test #3: order of prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
.DEFAULT: ; @echo $@
|
||||
|
||||
all: foo bar baz
|
||||
|
||||
|
||||
# Subtest #1
|
||||
#
|
||||
%oo: %oo.1; @:
|
||||
|
||||
foo: foo.2
|
||||
|
||||
foo: foo.3
|
||||
|
||||
foo.1: ; @echo $@
|
||||
|
||||
|
||||
# Subtest #2
|
||||
#
|
||||
bar: bar.2
|
||||
|
||||
%ar: %ar.1; @:
|
||||
|
||||
bar: bar.3
|
||||
|
||||
bar.1: ; @echo $@
|
||||
|
||||
|
||||
# Subtest #3
|
||||
#
|
||||
baz: baz.1
|
||||
|
||||
baz: baz.2
|
||||
|
||||
%az: ; @:
|
||||
|
||||
',
|
||||
'',
|
||||
'foo.1
|
||||
foo.2
|
||||
foo.3
|
||||
bar.1
|
||||
bar.2
|
||||
bar.3
|
||||
baz.1
|
||||
baz.2
|
||||
');
|
||||
|
||||
|
||||
# Test #4: stem splitting logic.
|
||||
#
|
||||
run_make_test('
|
||||
$(dir)/tmp/bar.o:
|
||||
|
||||
$(dir)/tmp/foo/bar.c: ; @echo $@
|
||||
$(dir)/tmp/bar/bar.c: ; @echo $@
|
||||
foo.h: ; @echo $@
|
||||
|
||||
%.o: $$(addsuffix /%.c,foo bar) foo.h
|
||||
@echo $@: {$<} $^
|
||||
|
||||
',
|
||||
"dir=$dir",
|
||||
"$dir/tmp/foo/bar.c
|
||||
$dir/tmp/bar/bar.c
|
||||
foo.h
|
||||
$dir/tmp/bar.o: {$dir/tmp/foo/bar.c} $dir/tmp/foo/bar.c $dir/tmp/bar/bar.c foo.h
|
||||
");
|
||||
|
||||
|
||||
# Test #5: stem splitting logic and order-only prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
$(dir)/tmp/foo.o: $(dir)/tmp/foo.c
|
||||
$(dir)/tmp/foo.c: ; @echo $@
|
||||
bar.h: ; @echo $@
|
||||
|
||||
%.o: %.c|bar.h
|
||||
@echo $@: {$<} {$|} $^
|
||||
|
||||
',
|
||||
"dir=$dir",
|
||||
"$dir/tmp/foo.c
|
||||
bar.h
|
||||
$dir/tmp/foo.o: {$dir/tmp/foo.c} {bar.h} $dir/tmp/foo.c
|
||||
");
|
||||
|
||||
|
||||
# Test #6: lack of implicit prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
foo.o: foo.c
|
||||
foo.c: ; @echo $@
|
||||
|
||||
%.o:
|
||||
@echo $@: {$<} $^
|
||||
|
||||
',
|
||||
'',
|
||||
'foo.c
|
||||
foo.o: {foo.c} foo.c
|
||||
');
|
||||
|
||||
|
||||
# This tells the test driver that the perl test script executed properly.
|
||||
1;
|
106
tests/scripts/features/se_statpat
Normal file
106
tests/scripts/features/se_statpat
Normal file
|
@ -0,0 +1,106 @@
|
|||
# -*-perl-*-
|
||||
$description = "Test second expansion in static pattern rules.";
|
||||
|
||||
$details = "";
|
||||
|
||||
# Test #1: automatic variables.
|
||||
#
|
||||
run_make_test('
|
||||
.DEFAULT: ; @echo $@
|
||||
|
||||
foo.a foo.b: foo.%: bar.% baz.%
|
||||
|
||||
foo.a foo.b: foo.%: biz.% | buz.%
|
||||
|
||||
foo.a foo.b: foo.%: $$@.1 \
|
||||
$$<.2 \
|
||||
$$(addsuffix .3,$$^) \
|
||||
$$(addsuffix .4,$$+) \
|
||||
$$|.5 \
|
||||
$$*.6
|
||||
|
||||
',
|
||||
'',
|
||||
'bar.a
|
||||
baz.a
|
||||
biz.a
|
||||
buz.a
|
||||
foo.a.1
|
||||
bar.a.2
|
||||
bar.a.3
|
||||
baz.a.3
|
||||
biz.a.3
|
||||
bar.a.4
|
||||
baz.a.4
|
||||
biz.a.4
|
||||
buz.a.5
|
||||
a.6
|
||||
');
|
||||
|
||||
|
||||
# Test #2: target/pattern -specific variables.
|
||||
#
|
||||
run_make_test('
|
||||
.DEFAULT: ; @echo $@
|
||||
|
||||
foo.x foo.y: foo.%: $$(%_a) $$($$*_b)
|
||||
|
||||
foo.x: x_a := bar
|
||||
|
||||
%.x: x_b := baz
|
||||
|
||||
|
||||
',
|
||||
'',
|
||||
'bar
|
||||
baz
|
||||
');
|
||||
|
||||
|
||||
# Test #3: order of prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
.DEFAULT: ; @echo $@
|
||||
|
||||
all: foo.a bar.a baz.a
|
||||
|
||||
# Subtest #1
|
||||
#
|
||||
foo.a foo.b: foo.%: foo.%.1; @:
|
||||
|
||||
foo.a foo.b: foo.%: foo.%.2
|
||||
|
||||
foo.a foo.b: foo.%: foo.%.3
|
||||
|
||||
|
||||
# Subtest #2
|
||||
#
|
||||
bar.a bar.b: bar.%: bar.%.2
|
||||
|
||||
bar.a bar.b: bar.%: bar.%.1; @:
|
||||
|
||||
bar.a bar.b: bar.%: bar.%.3
|
||||
|
||||
|
||||
# Subtest #3
|
||||
#
|
||||
baz.a baz.b: baz.%: baz.%.1
|
||||
|
||||
baz.a baz.b: baz.%: baz.%.2
|
||||
|
||||
baz.a baz.b: ; @:
|
||||
|
||||
',
|
||||
'',
|
||||
'foo.a.1
|
||||
foo.a.2
|
||||
foo.a.3
|
||||
bar.a.1
|
||||
bar.a.2
|
||||
bar.a.3
|
||||
baz.a.1
|
||||
baz.a.2
|
||||
');
|
||||
|
||||
# This tells the test driver that the perl test script executed properly.
|
||||
1;
|
|
@ -6,9 +6,6 @@ which have either broken at some point in the past or seem likely to
|
|||
break.";
|
||||
|
||||
open(MAKEFILE,"> $makefile");
|
||||
|
||||
# The contents of the Makefile ...
|
||||
|
||||
print MAKEFILE <<'EOF';
|
||||
# Make sure that subdirectories built as prerequisites are actually handled
|
||||
# properly.
|
||||
|
@ -21,11 +18,36 @@ dir/subdir/file.b: dir/subdir ; @echo touch dir/subdir/file.b
|
|||
|
||||
dir/subdir/%.a: dir/subdir/%.b ; @echo cp $< $@
|
||||
EOF
|
||||
|
||||
close(MAKEFILE);
|
||||
|
||||
&run_make_with_options($makefile,"",&get_logfile);
|
||||
$answer = "mkdir -p dir/subdir\ntouch dir/subdir/file.b\ncp dir/subdir/file.b dir/subdir/file.a\n";
|
||||
&compare_output($answer,&get_logfile(1));
|
||||
|
||||
|
||||
# Test implicit rules
|
||||
|
||||
&touch('foo.c');
|
||||
run_make_test('
|
||||
foo: foo.o
|
||||
',
|
||||
'CC="@echo cc" OUTPUT_OPTION=',
|
||||
'cc -c foo.c
|
||||
cc foo.o -o foo');
|
||||
unlink('foo.c');
|
||||
|
||||
|
||||
# Test other implicit rule searching
|
||||
|
||||
&touch('bar');
|
||||
run_make_test('
|
||||
test.foo:
|
||||
%.foo : baz ; @echo done $<
|
||||
%.foo : bar ; @echo done $<
|
||||
fox: baz
|
||||
',
|
||||
'',
|
||||
'done bar');
|
||||
unlink('bar');
|
||||
|
||||
1;
|
||||
|
|
|
@ -67,11 +67,11 @@ EOF
|
|||
close(MAKEFILE);
|
||||
|
||||
&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";
|
||||
$answer = ".x\n$dir/foo.x\nx\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";
|
||||
$answer = ".x\n$dir/x.z.x\nx\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));
|
||||
|
||||
&run_make_with_options($makefile2, "$dir/biz", &get_logfile);
|
||||
|
|
|
@ -112,6 +112,7 @@ extern struct variable_set_list *current_variable_set_list;
|
|||
/* expand.c */
|
||||
extern char *variable_buffer_output PARAMS ((char *ptr, char *string, unsigned int length));
|
||||
extern char *variable_expand PARAMS ((char *line));
|
||||
extern char *variable_expand_for_file PARAMS ((char *line, struct file *file));
|
||||
extern char *allocated_variable_expand_for_file PARAMS ((char *line, struct file *file));
|
||||
#define allocated_variable_expand(line) \
|
||||
allocated_variable_expand_for_file (line, (struct file *) 0)
|
||||
|
|
Loading…
Reference in a new issue