mirror of
https://github.com/mirror/make.git
synced 2024-12-30 23:10:52 +08:00
[SV 42249] Propagate correct rule status results.
* remake.c (update_file, update_file_1, check_dep): Return an enum update_status value instead of an int, and keep the highest value we find as we walk the graph so that the ultimate status is correct. * tests/scripts/options/dash-q: Add a test for updating prerequisites.
This commit is contained in:
parent
8411528fdd
commit
0faa98a0bb
75
remake.c
75
remake.c
@ -58,10 +58,10 @@ unsigned int commands_started = 0;
|
|||||||
/* Current value for pruning the scan of the goal chain (toggle 0/1). */
|
/* Current value for pruning the scan of the goal chain (toggle 0/1). */
|
||||||
static unsigned int considered;
|
static unsigned int considered;
|
||||||
|
|
||||||
static int update_file (struct file *file, unsigned int depth);
|
static enum update_status update_file (struct file *file, unsigned int depth);
|
||||||
static int update_file_1 (struct file *file, unsigned int depth);
|
static enum update_status update_file_1 (struct file *file, unsigned int depth);
|
||||||
static int check_dep (struct file *file, unsigned int depth,
|
static enum update_status check_dep (struct file *file, unsigned int depth,
|
||||||
FILE_TIMESTAMP this_mtime, int *must_make_ptr);
|
FILE_TIMESTAMP this_mtime, int *must_make);
|
||||||
static enum update_status touch_file (struct file *file);
|
static enum update_status touch_file (struct file *file);
|
||||||
static void remake_file (struct file *file);
|
static void remake_file (struct file *file);
|
||||||
static FILE_TIMESTAMP name_mtime (const char *name);
|
static FILE_TIMESTAMP name_mtime (const char *name);
|
||||||
@ -130,7 +130,7 @@ update_goal_chain (struct dep *goals)
|
|||||||
file = file->prev)
|
file = file->prev)
|
||||||
{
|
{
|
||||||
unsigned int ocommands_started;
|
unsigned int ocommands_started;
|
||||||
int fail;
|
enum update_status fail;
|
||||||
|
|
||||||
file->dontcare = g->dontcare;
|
file->dontcare = g->dontcare;
|
||||||
|
|
||||||
@ -161,14 +161,12 @@ update_goal_chain (struct dep *goals)
|
|||||||
if (commands_started > ocommands_started)
|
if (commands_started > ocommands_started)
|
||||||
g->changed = 1;
|
g->changed = 1;
|
||||||
|
|
||||||
/* If we updated a file and STATUS was not already 1, set it to
|
|
||||||
1 if updating failed, or to 0 if updating succeeded. Leave
|
|
||||||
STATUS as it is if no updating was done. */
|
|
||||||
|
|
||||||
stop = 0;
|
stop = 0;
|
||||||
if ((fail || file->updated) && status < us_question)
|
if ((fail || file->updated) && status < us_question)
|
||||||
{
|
{
|
||||||
if (file->update_status != us_success)
|
/* We updated this goal. Update STATUS and decide whether
|
||||||
|
to stop. */
|
||||||
|
if (file->update_status)
|
||||||
{
|
{
|
||||||
/* Updating failed, or -q triggered. The STATUS value
|
/* Updating failed, or -q triggered. The STATUS value
|
||||||
tells our caller which. */
|
tells our caller which. */
|
||||||
@ -282,11 +280,11 @@ update_goal_chain (struct dep *goals)
|
|||||||
If there are multiple double-colon entries for FILE,
|
If there are multiple double-colon entries for FILE,
|
||||||
each is considered in turn. */
|
each is considered in turn. */
|
||||||
|
|
||||||
static int
|
static enum update_status
|
||||||
update_file (struct file *file, unsigned int depth)
|
update_file (struct file *file, unsigned int depth)
|
||||||
{
|
{
|
||||||
int status = 0;
|
enum update_status status = us_success;
|
||||||
register struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
f = file->double_colon ? file->double_colon : file;
|
f = file->double_colon ? file->double_colon : file;
|
||||||
|
|
||||||
@ -311,26 +309,31 @@ update_file (struct file *file, unsigned int depth)
|
|||||||
the chain is exhausted. */
|
the chain is exhausted. */
|
||||||
for (; f != 0; f = f->prev)
|
for (; f != 0; f = f->prev)
|
||||||
{
|
{
|
||||||
|
enum update_status new;
|
||||||
|
|
||||||
f->considered = considered;
|
f->considered = considered;
|
||||||
|
|
||||||
status |= update_file_1 (f, depth);
|
new = update_file_1 (f, depth);
|
||||||
check_renamed (f);
|
check_renamed (f);
|
||||||
|
|
||||||
/* Clean up any alloca() used during the update. */
|
/* Clean up any alloca() used during the update. */
|
||||||
alloca (0);
|
alloca (0);
|
||||||
|
|
||||||
/* If we got an error, don't bother with double_colon etc. */
|
/* If we got an error, don't bother with double_colon etc. */
|
||||||
if (status != 0 && !keep_going_flag)
|
if (new && !keep_going_flag)
|
||||||
return status;
|
return new;
|
||||||
|
|
||||||
if (f->command_state == cs_running
|
if (f->command_state == cs_running
|
||||||
|| f->command_state == cs_deps_running)
|
|| f->command_state == cs_deps_running)
|
||||||
{
|
{
|
||||||
/* Don't run the other :: rules for this
|
/* Don't run the other :: rules for this
|
||||||
file until this rule is finished. */
|
file until this rule is finished. */
|
||||||
status = 0;
|
status = us_success;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new > status)
|
||||||
|
status = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process the remaining rules in the double colon chain so they're marked
|
/* Process the remaining rules in the double colon chain so they're marked
|
||||||
@ -343,7 +346,11 @@ update_file (struct file *file, unsigned int depth)
|
|||||||
f->considered = considered;
|
f->considered = considered;
|
||||||
|
|
||||||
for (d = f->deps; d != 0; d = d->next)
|
for (d = f->deps; d != 0; d = d->next)
|
||||||
status |= update_file (d->file, depth + 1);
|
{
|
||||||
|
enum update_status new = update_file (d->file, depth + 1);
|
||||||
|
if (new > status)
|
||||||
|
new = status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -405,12 +412,12 @@ complain (struct file *file)
|
|||||||
/* Consider a single 'struct file' and update it as appropriate.
|
/* Consider a single 'struct file' and update it as appropriate.
|
||||||
Return 0 on success, or non-0 on failure. */
|
Return 0 on success, or non-0 on failure. */
|
||||||
|
|
||||||
static int
|
static enum update_status
|
||||||
update_file_1 (struct file *file, unsigned int depth)
|
update_file_1 (struct file *file, unsigned int depth)
|
||||||
{
|
{
|
||||||
|
enum update_status dep_status = us_success;
|
||||||
FILE_TIMESTAMP this_mtime;
|
FILE_TIMESTAMP this_mtime;
|
||||||
int noexist, must_make, deps_changed;
|
int noexist, must_make, deps_changed;
|
||||||
int dep_status = 0;
|
|
||||||
struct file *ofile;
|
struct file *ofile;
|
||||||
struct dep *d, *ad;
|
struct dep *d, *ad;
|
||||||
struct dep amake;
|
struct dep amake;
|
||||||
@ -528,6 +535,7 @@ update_file_1 (struct file *file, unsigned int depth)
|
|||||||
|
|
||||||
while (d)
|
while (d)
|
||||||
{
|
{
|
||||||
|
enum update_status new;
|
||||||
FILE_TIMESTAMP mtime;
|
FILE_TIMESTAMP mtime;
|
||||||
int maybe_make;
|
int maybe_make;
|
||||||
int dontcare = 0;
|
int dontcare = 0;
|
||||||
@ -562,7 +570,9 @@ update_file_1 (struct file *file, unsigned int depth)
|
|||||||
d->file->dontcare = file->dontcare;
|
d->file->dontcare = file->dontcare;
|
||||||
}
|
}
|
||||||
|
|
||||||
dep_status |= check_dep (d->file, depth, this_mtime, &maybe_make);
|
new = check_dep (d->file, depth, this_mtime, &maybe_make);
|
||||||
|
if (new > dep_status)
|
||||||
|
dep_status = new;
|
||||||
|
|
||||||
/* Restore original dontcare flag. */
|
/* Restore original dontcare flag. */
|
||||||
if (rebuilding_makefiles)
|
if (rebuilding_makefiles)
|
||||||
@ -608,6 +618,7 @@ update_file_1 (struct file *file, unsigned int depth)
|
|||||||
for (d = file->deps; d != 0; d = d->next)
|
for (d = file->deps; d != 0; d = d->next)
|
||||||
if (d->file->intermediate)
|
if (d->file->intermediate)
|
||||||
{
|
{
|
||||||
|
enum update_status new;
|
||||||
int dontcare = 0;
|
int dontcare = 0;
|
||||||
|
|
||||||
FILE_TIMESTAMP mtime = file_mtime (d->file);
|
FILE_TIMESTAMP mtime = file_mtime (d->file);
|
||||||
@ -626,7 +637,9 @@ update_file_1 (struct file *file, unsigned int depth)
|
|||||||
not prune it. */
|
not prune it. */
|
||||||
d->file->considered = !considered;
|
d->file->considered = !considered;
|
||||||
|
|
||||||
dep_status |= update_file (d->file, depth);
|
new = update_file (d->file, depth);
|
||||||
|
if (new > dep_status)
|
||||||
|
dep_status = new;
|
||||||
|
|
||||||
/* Restore original dontcare flag. */
|
/* Restore original dontcare flag. */
|
||||||
if (rebuilding_makefiles)
|
if (rebuilding_makefiles)
|
||||||
@ -671,9 +684,10 @@ update_file_1 (struct file *file, unsigned int depth)
|
|||||||
|
|
||||||
/* If any dependency failed, give up now. */
|
/* If any dependency failed, give up now. */
|
||||||
|
|
||||||
if (dep_status != 0)
|
if (dep_status)
|
||||||
{
|
{
|
||||||
file->update_status = us_failed;
|
/* I'm not sure if we can't just assign dep_status... */
|
||||||
|
file->update_status = dep_status == us_none ? us_failed : dep_status;
|
||||||
notice_finished_file (file);
|
notice_finished_file (file);
|
||||||
|
|
||||||
--depth;
|
--depth;
|
||||||
@ -988,13 +1002,13 @@ notice_finished_file (struct file *file)
|
|||||||
FILE depends on (including FILE itself). Return nonzero if any updating
|
FILE depends on (including FILE itself). Return nonzero if any updating
|
||||||
failed. */
|
failed. */
|
||||||
|
|
||||||
static int
|
static enum update_status
|
||||||
check_dep (struct file *file, unsigned int depth,
|
check_dep (struct file *file, unsigned int depth,
|
||||||
FILE_TIMESTAMP this_mtime, int *must_make_ptr)
|
FILE_TIMESTAMP this_mtime, int *must_make_ptr)
|
||||||
{
|
{
|
||||||
struct file *ofile;
|
struct file *ofile;
|
||||||
struct dep *d;
|
struct dep *d;
|
||||||
int dep_status = 0;
|
enum update_status dep_status = us_success;
|
||||||
|
|
||||||
++depth;
|
++depth;
|
||||||
start_updating (file);
|
start_updating (file);
|
||||||
@ -1067,6 +1081,7 @@ check_dep (struct file *file, unsigned int depth,
|
|||||||
d = file->deps;
|
d = file->deps;
|
||||||
while (d != 0)
|
while (d != 0)
|
||||||
{
|
{
|
||||||
|
enum update_status new;
|
||||||
int maybe_make;
|
int maybe_make;
|
||||||
|
|
||||||
if (is_updating (d->file))
|
if (is_updating (d->file))
|
||||||
@ -1090,12 +1105,14 @@ check_dep (struct file *file, unsigned int depth,
|
|||||||
|
|
||||||
d->file->parent = file;
|
d->file->parent = file;
|
||||||
maybe_make = *must_make_ptr;
|
maybe_make = *must_make_ptr;
|
||||||
dep_status |= check_dep (d->file, depth, this_mtime,
|
new = check_dep (d->file, depth, this_mtime, &maybe_make);
|
||||||
&maybe_make);
|
if (new > dep_status)
|
||||||
|
dep_status = new;
|
||||||
|
|
||||||
if (! d->ignore_mtime)
|
if (! d->ignore_mtime)
|
||||||
*must_make_ptr = maybe_make;
|
*must_make_ptr = maybe_make;
|
||||||
check_renamed (d->file);
|
check_renamed (d->file);
|
||||||
if (dep_status != 0 && !keep_going_flag)
|
if (dep_status && !keep_going_flag)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (d->file->command_state == cs_running
|
if (d->file->command_state == cs_running
|
||||||
|
@ -5,21 +5,21 @@ $details = "Try various uses of -q and ensure they all give the correct results.
|
|||||||
|
|
||||||
# TEST 0
|
# TEST 0
|
||||||
|
|
||||||
run_make_test('
|
run_make_test(qq!
|
||||||
one:
|
one:
|
||||||
two: ;
|
two: ;
|
||||||
three: ; :
|
three: ; :
|
||||||
four: ; $(.XY)
|
four: ; \$(.XY)
|
||||||
five: ; \
|
five: ; \\
|
||||||
$(.XY)
|
\$(.XY)
|
||||||
six: ; \
|
six: ; \\
|
||||||
$(.XY)
|
\$(.XY)
|
||||||
$(.XY)
|
\t\$(.XY)
|
||||||
seven: ; \
|
seven: ; \\
|
||||||
$(.XY)
|
\$(.XY)
|
||||||
: foo
|
\t: foo
|
||||||
$(.XY)
|
\t\$(.XY)
|
||||||
',
|
!,
|
||||||
'-q one', '');
|
'-q one', '');
|
||||||
|
|
||||||
# TEST 1
|
# TEST 1
|
||||||
@ -54,4 +54,24 @@ one:: ; @echo two
|
|||||||
',
|
',
|
||||||
'-q', '', 256);
|
'-q', '', 256);
|
||||||
|
|
||||||
|
# TEST 7 : Savannah bug # 42249
|
||||||
|
# Make sure we exit with 1 even for prerequisite updates
|
||||||
|
run_make_test('
|
||||||
|
build-stamp: ; echo $@
|
||||||
|
build-arch: build-stamp
|
||||||
|
build-x: build-arch
|
||||||
|
build-y: build-x
|
||||||
|
',
|
||||||
|
'-q build-y', '', 256);
|
||||||
|
|
||||||
|
# TEST 8
|
||||||
|
# Make sure we exit with 2 on error even with -q
|
||||||
|
run_make_test('
|
||||||
|
build-stamp: ; echo $@
|
||||||
|
build-arch: build-stamp-2
|
||||||
|
build-x: build-arch
|
||||||
|
build-y: build-x
|
||||||
|
',
|
||||||
|
'-q build-y', "#MAKE#: *** No rule to make target 'build-stamp-2', needed by 'build-arch'. Stop.\n", 512);
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
Loading…
Reference in New Issue
Block a user