mirror of
https://github.com/mirror/make.git
synced 2025-01-27 21:00:22 +08:00
Implementation of the .DEFAULT_TARGET special variable.
This commit is contained in:
parent
659fc6b55e
commit
93bd1bd93c
25
ChangeLog
25
ChangeLog
@ -1,3 +1,28 @@
|
|||||||
|
Mon Feb 28 00:18:20 2005 Boris Kolpackov <boris@kolpackov.net>
|
||||||
|
|
||||||
|
Implementation of the .DEFAULT_TARGET special variable.
|
||||||
|
|
||||||
|
* read.c (eval): If necessary, update default_target_name
|
||||||
|
when reading rules.
|
||||||
|
|
||||||
|
* read.c (record_files): Update default_target_file if
|
||||||
|
default_target_name has changed.
|
||||||
|
|
||||||
|
* main.c (default_target_name): Define.
|
||||||
|
|
||||||
|
* main.c (main): Enter .DEFAULT_TARGET as make variable. If
|
||||||
|
default_target_name is set use default_target_file as a root
|
||||||
|
target to make.
|
||||||
|
|
||||||
|
* filedef.h (default_target_name): Declare.
|
||||||
|
|
||||||
|
* dep.h (free_dep_chain):
|
||||||
|
* misc.c (free_dep_chain): Change to operate on struct nameseq
|
||||||
|
and change name to free_ns_chain.
|
||||||
|
|
||||||
|
* file.c (snap_deps): Update to use free_ns_chain.
|
||||||
|
|
||||||
|
|
||||||
Sun Feb 27 22:03:36 2005 Boris Kolpackov <boris@kolpackov.net>
|
Sun Feb 27 22:03:36 2005 Boris Kolpackov <boris@kolpackov.net>
|
||||||
|
|
||||||
Implementation of the second expansion in explicit rules,
|
Implementation of the second expansion in explicit rules,
|
||||||
|
2
dep.h
2
dep.h
@ -72,7 +72,7 @@ extern char *dep_name ();
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern struct dep *copy_dep_chain PARAMS ((struct dep *d));
|
extern struct dep *copy_dep_chain PARAMS ((struct dep *d));
|
||||||
extern void free_dep_chain PARAMS ((struct dep *d));
|
extern void free_ns_chain PARAMS ((struct nameseq *n));
|
||||||
extern struct dep *read_all_makefiles PARAMS ((char **makefiles));
|
extern struct dep *read_all_makefiles PARAMS ((char **makefiles));
|
||||||
extern int eval_buffer PARAMS ((char *buffer));
|
extern int eval_buffer PARAMS ((char *buffer));
|
||||||
extern int update_goal_chain PARAMS ((struct dep *goals));
|
extern int update_goal_chain PARAMS ((struct dep *goals));
|
||||||
|
2
file.c
2
file.c
@ -522,7 +522,7 @@ snap_deps (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free_dep_chain (old);
|
free_ns_chain ((struct nameseq*)old);
|
||||||
}
|
}
|
||||||
free (file_slot_0);
|
free (file_slot_0);
|
||||||
|
|
||||||
|
@ -100,6 +100,7 @@ struct file
|
|||||||
|
|
||||||
|
|
||||||
extern struct file *default_goal_file, *suffix_file, *default_file;
|
extern struct file *default_goal_file, *suffix_file, *default_file;
|
||||||
|
extern char **default_target_name;
|
||||||
|
|
||||||
|
|
||||||
extern struct file *lookup_file PARAMS ((char *name));
|
extern struct file *lookup_file PARAMS ((char *name));
|
||||||
|
58
main.c
58
main.c
@ -461,6 +461,10 @@ unsigned int makelevel;
|
|||||||
|
|
||||||
struct file *default_goal_file;
|
struct file *default_goal_file;
|
||||||
|
|
||||||
|
/* Pointer to the value of the .DEFAULT_TARGET special
|
||||||
|
variable. */
|
||||||
|
char ** default_target_name;
|
||||||
|
|
||||||
/* Pointer to structure for the file .DEFAULT
|
/* Pointer to structure for the file .DEFAULT
|
||||||
whose commands are used for any file that has none of its own.
|
whose commands are used for any file that has none of its own.
|
||||||
This is zero if the makefiles do not define .DEFAULT. */
|
This is zero if the makefiles do not define .DEFAULT. */
|
||||||
@ -1537,10 +1541,17 @@ main (int argc, char **argv, char **envp)
|
|||||||
/* Define the default variables. */
|
/* Define the default variables. */
|
||||||
define_default_variables ();
|
define_default_variables ();
|
||||||
|
|
||||||
/* Read all the makefiles. */
|
|
||||||
|
|
||||||
default_file = enter_file (".DEFAULT");
|
default_file = enter_file (".DEFAULT");
|
||||||
|
|
||||||
|
{
|
||||||
|
struct variable *v = define_variable (
|
||||||
|
".DEFAULT_TARGET", 15, "", o_default, 0);
|
||||||
|
|
||||||
|
default_target_name = &v->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read all the makefiles. */
|
||||||
|
|
||||||
read_makefiles
|
read_makefiles
|
||||||
= read_all_makefiles (makefiles == 0 ? (char **) 0 : makefiles->list);
|
= read_all_makefiles (makefiles == 0 ? (char **) 0 : makefiles->list);
|
||||||
|
|
||||||
@ -2058,18 +2069,47 @@ main (int argc, char **argv, char **envp)
|
|||||||
/* If there were no command-line goals, use the default. */
|
/* If there were no command-line goals, use the default. */
|
||||||
if (goals == 0)
|
if (goals == 0)
|
||||||
{
|
{
|
||||||
if (default_goal_file != 0)
|
if (**default_target_name != '\0')
|
||||||
{
|
{
|
||||||
goals = (struct dep *) xmalloc (sizeof (struct dep));
|
if (default_goal_file == 0 ||
|
||||||
goals->next = 0;
|
strcmp (*default_target_name, default_goal_file->name) != 0)
|
||||||
goals->name = 0;
|
{
|
||||||
|
default_goal_file = lookup_file (*default_target_name);
|
||||||
|
|
||||||
|
/* In case user set .DEFAULT_TARGET to a non-existent target
|
||||||
|
name let's just enter this name into the table and let
|
||||||
|
the standard logic sort it out. */
|
||||||
|
if (default_goal_file == 0)
|
||||||
|
{
|
||||||
|
struct nameseq *ns;
|
||||||
|
char *p = *default_target_name;
|
||||||
|
|
||||||
|
ns = multi_glob (
|
||||||
|
parse_file_seq (&p, '\0', sizeof (struct nameseq), 1),
|
||||||
|
sizeof (struct nameseq));
|
||||||
|
|
||||||
|
/* .DEFAULT_TARGET should contain one target. */
|
||||||
|
if (ns->next != 0)
|
||||||
|
fatal (NILF, _(".DEFAULT_TARGET contains more than one target"));
|
||||||
|
|
||||||
|
default_goal_file = enter_file (ns->name);
|
||||||
|
|
||||||
|
ns->name = 0; /* It was reused by enter_file(). */
|
||||||
|
free_ns_chain (ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goals = (struct dep *) xmalloc (sizeof (struct dep));
|
||||||
|
goals->next = 0;
|
||||||
|
goals->name = 0;
|
||||||
goals->ignore_mtime = 0;
|
goals->ignore_mtime = 0;
|
||||||
goals->file = default_goal_file;
|
goals->file = default_goal_file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
lastgoal->next = 0;
|
lastgoal->next = 0;
|
||||||
|
|
||||||
|
|
||||||
if (!goals)
|
if (!goals)
|
||||||
{
|
{
|
||||||
if (read_makefiles == 0)
|
if (read_makefiles == 0)
|
||||||
|
18
misc.c
18
misc.c
@ -525,22 +525,22 @@ copy_dep_chain (struct dep *d)
|
|||||||
return firstnew;
|
return firstnew;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free a chain of `struct dep'. Each dep->name is freed
|
/* Free a chain of `struct nameseq'. Each nameseq->name is freed
|
||||||
as well. */
|
as well. Can be used on `struct dep' chains.*/
|
||||||
|
|
||||||
void
|
void
|
||||||
free_dep_chain (struct dep *d)
|
free_ns_chain (struct nameseq *n)
|
||||||
{
|
{
|
||||||
register struct dep *tmp;
|
register struct nameseq *tmp;
|
||||||
|
|
||||||
while (d != 0)
|
while (n != 0)
|
||||||
{
|
{
|
||||||
if (d->name != 0)
|
if (n->name != 0)
|
||||||
free (d->name);
|
free (n->name);
|
||||||
|
|
||||||
tmp = d;
|
tmp = n;
|
||||||
|
|
||||||
d = d->next;
|
n = n->next;
|
||||||
|
|
||||||
free (tmp);
|
free (tmp);
|
||||||
}
|
}
|
||||||
|
127
read.c
127
read.c
@ -134,7 +134,7 @@ static int conditional_line PARAMS ((char *line, const struct floc *flocp));
|
|||||||
static void record_files PARAMS ((struct nameseq *filenames, char *pattern, char *pattern_percent,
|
static void record_files PARAMS ((struct nameseq *filenames, char *pattern, char *pattern_percent,
|
||||||
struct dep *deps, unsigned int cmds_started, char *commands,
|
struct dep *deps, unsigned int cmds_started, char *commands,
|
||||||
unsigned int commands_idx, int two_colon,
|
unsigned int commands_idx, int two_colon,
|
||||||
const struct floc *flocp, int set_default));
|
const struct floc *flocp));
|
||||||
static void record_target_var PARAMS ((struct nameseq *filenames, char *defn,
|
static void record_target_var PARAMS ((struct nameseq *filenames, char *defn,
|
||||||
enum variable_origin origin,
|
enum variable_origin origin,
|
||||||
int enabled,
|
int enabled,
|
||||||
@ -472,7 +472,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
fi.lineno = tgts_started; \
|
fi.lineno = tgts_started; \
|
||||||
record_files (filenames, pattern, pattern_percent, deps, \
|
record_files (filenames, pattern, pattern_percent, deps, \
|
||||||
cmds_started, commands, commands_idx, two_colon, \
|
cmds_started, commands, commands_idx, two_colon, \
|
||||||
&fi, set_default); \
|
&fi); \
|
||||||
} \
|
} \
|
||||||
filenames = 0; \
|
filenames = 0; \
|
||||||
commands_idx = 0; \
|
commands_idx = 0; \
|
||||||
@ -1192,6 +1192,83 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
commands[commands_idx++] = '\n';
|
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_TARGET),foo)
|
||||||
|
...
|
||||||
|
endif
|
||||||
|
|
||||||
|
Because the target is not recorded until after ifeq
|
||||||
|
directive is evaluated the .DEFAULT_TARGET does not
|
||||||
|
contain foo yet as one would expect. Because of this
|
||||||
|
we have to move some of the logic here. */
|
||||||
|
|
||||||
|
if (**default_target_name == '\0' && set_default)
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
struct dep *d;
|
||||||
|
struct nameseq *t = filenames;
|
||||||
|
|
||||||
|
for (; t != 0; t = t->next)
|
||||||
|
{
|
||||||
|
int reject = 0;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
register 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)
|
||||||
|
{
|
||||||
|
register unsigned int len = strlen (dep_name (d2));
|
||||||
|
if (!strneq (name, dep_name (d2), len))
|
||||||
|
continue;
|
||||||
|
if (streq (name + len, dep_name (d)))
|
||||||
|
{
|
||||||
|
reject = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reject)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reject)
|
||||||
|
{
|
||||||
|
(void) define_variable (
|
||||||
|
".DEFAULT_TARGET", 15, t->name, o_file, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1737,7 +1814,7 @@ static void
|
|||||||
record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
|
record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
|
||||||
struct dep *deps, unsigned int cmds_started, char *commands,
|
struct dep *deps, unsigned int cmds_started, char *commands,
|
||||||
unsigned int commands_idx, int two_colon,
|
unsigned int commands_idx, int two_colon,
|
||||||
const struct floc *flocp, int set_default)
|
const struct floc *flocp)
|
||||||
{
|
{
|
||||||
struct nameseq *nextf;
|
struct nameseq *nextf;
|
||||||
int implicit = 0;
|
int implicit = 0;
|
||||||
@ -2013,45 +2090,13 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
|
|||||||
name = f->name;
|
name = f->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if this is first target seen whose name does
|
/* See if this target is a default target and update
|
||||||
not start with a `.', unless it contains a slash. */
|
DEFAULT_GOAL_FILE if necessary. */
|
||||||
if (default_goal_file == 0 && set_default
|
if (strcmp (*default_target_name, name) == 0 &&
|
||||||
&& (*name != '.' || strchr (name, '/') != 0
|
(default_goal_file == 0 ||
|
||||||
#ifdef HAVE_DOS_PATHS
|
strcmp (default_goal_file->name, name) != 0))
|
||||||
|| strchr (name, '\\') != 0
|
|
||||||
#endif
|
|
||||||
))
|
|
||||||
{
|
{
|
||||||
int reject = 0;
|
default_goal_file = f;
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
register 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)
|
|
||||||
{
|
|
||||||
register unsigned int len = strlen (dep_name (d2));
|
|
||||||
if (!strneq (name, dep_name (d2), len))
|
|
||||||
continue;
|
|
||||||
if (streq (name + len, dep_name (d)))
|
|
||||||
{
|
|
||||||
reject = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (reject)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!reject)
|
|
||||||
default_goal_file = f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
Mon Feb 28 00:31:14 2005 Boris Kolpackov <boris@kolpackov.net>
|
||||||
|
|
||||||
|
* scripts/variables/DEFAULT_TARGET: Test the .DEFAULT_TARGET
|
||||||
|
special variable.
|
||||||
|
|
||||||
Sun Feb 27 23:33:32 2005 Boris Kolpackov <boris@kolpackov.net>
|
Sun Feb 27 23:33:32 2005 Boris Kolpackov <boris@kolpackov.net>
|
||||||
|
|
||||||
* scripts/features/se_explicit: Test the second expansion in
|
* scripts/features/se_explicit: Test the second expansion in
|
||||||
|
59
tests/scripts/variables/DEFAULT_TARGET
Normal file
59
tests/scripts/variables/DEFAULT_TARGET
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# -*-perl-*-
|
||||||
|
$description = "Test the .DEFAULT_TARGET special variable.";
|
||||||
|
|
||||||
|
$details = "";
|
||||||
|
|
||||||
|
# Test #1: basic logic.
|
||||||
|
#
|
||||||
|
run_make_test('
|
||||||
|
# Basics.
|
||||||
|
#
|
||||||
|
foo: ; @:
|
||||||
|
|
||||||
|
ifneq ($(.DEFAULT_TARGET),foo)
|
||||||
|
$(error )
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Reset to empty.
|
||||||
|
#
|
||||||
|
.DEFAULT_TARGET :=
|
||||||
|
|
||||||
|
bar: ; @:
|
||||||
|
|
||||||
|
ifneq ($(.DEFAULT_TARGET),bar)
|
||||||
|
$(error )
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Change to a different target.
|
||||||
|
#
|
||||||
|
|
||||||
|
.DEFAULT_TARGET := baz
|
||||||
|
|
||||||
|
baz: ; @echo $@
|
||||||
|
',
|
||||||
|
'',
|
||||||
|
'baz');
|
||||||
|
|
||||||
|
|
||||||
|
# Test #2: unknown target.
|
||||||
|
#
|
||||||
|
run_make_test('
|
||||||
|
.DEFAULT_TARGET := foo
|
||||||
|
',
|
||||||
|
'',
|
||||||
|
'make: *** No rule to make target `foo\'. Stop.',
|
||||||
|
512);
|
||||||
|
|
||||||
|
|
||||||
|
# Test #2: more than one target.
|
||||||
|
#
|
||||||
|
run_make_test('
|
||||||
|
.DEFAULT_TARGET := foo bar
|
||||||
|
',
|
||||||
|
'',
|
||||||
|
'make: *** .DEFAULT_TARGET contains more than one target. Stop.',
|
||||||
|
512);
|
||||||
|
|
||||||
|
|
||||||
|
# This tells the test driver that the perl test script executed properly.
|
||||||
|
1;
|
Loading…
Reference in New Issue
Block a user