mirror of
https://github.com/mirror/make.git
synced 2025-03-13 19:30:41 +08:00
[SV 63856] Implement .WAIT on the command line
* src/main.c (handle_non_switch_argument): Return 1 if arg is .WAIT. (decode_switches): Set wait_here for a goal that follows .WAIT. * src/remake.c (update_goal_chain): Honor wait_here for a command line goal. Don't allow double-colon targets to continue if .WAIT is given for one of them. * tests/scripts/targets/WAIT: Add .WAIT tests.
This commit is contained in:
parent
54b3202f8d
commit
cd46baab90
37
src/main.c
37
src/main.c
@ -2975,15 +2975,17 @@ init_switches (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Non-option argument. It might be a variable definition. */
|
/* Non-option argument. It might be a variable definition.
|
||||||
static void
|
Returns 1 if the argument we read was .WAIT, else 0.
|
||||||
|
*/
|
||||||
|
static unsigned int
|
||||||
handle_non_switch_argument (const char *arg, enum variable_origin origin)
|
handle_non_switch_argument (const char *arg, enum variable_origin origin)
|
||||||
{
|
{
|
||||||
struct variable *v;
|
struct variable *v;
|
||||||
|
|
||||||
if (arg[0] == '-' && arg[1] == '\0')
|
if (arg[0] == '-' && arg[1] == '\0')
|
||||||
/* Ignore plain '-' for compatibility. */
|
/* Ignore plain '-' for compatibility. */
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
#if MK_OS_VMS
|
#if MK_OS_VMS
|
||||||
{
|
{
|
||||||
@ -3036,7 +3038,12 @@ handle_non_switch_argument (const char *arg, enum variable_origin origin)
|
|||||||
Enter it as a file and add it to the dep chain of goals.
|
Enter it as a file and add it to the dep chain of goals.
|
||||||
Check ARG[0] because if the top makefile resets MAKEOVERRIDES
|
Check ARG[0] because if the top makefile resets MAKEOVERRIDES
|
||||||
then ARG points to an empty string in the submake. */
|
then ARG points to an empty string in the submake. */
|
||||||
struct file *f = enter_file (strcache_add (expand_command_line_file (arg)));
|
struct file *f;
|
||||||
|
|
||||||
|
if (strcmp (arg, ".WAIT") == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
f = enter_file (strcache_add (expand_command_line_file (arg)));
|
||||||
f->cmd_target = 1;
|
f->cmd_target = 1;
|
||||||
|
|
||||||
if (goals == 0)
|
if (goals == 0)
|
||||||
@ -3077,6 +3084,7 @@ handle_non_switch_argument (const char *arg, enum variable_origin origin)
|
|||||||
define_variable_cname ("MAKECMDGOALS", value, o_default, 0);
|
define_variable_cname ("MAKECMDGOALS", value, o_default, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called if the makefile resets the MAKEFLAGS variable. */
|
/* Called if the makefile resets the MAKEFLAGS variable. */
|
||||||
@ -3098,6 +3106,7 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
|
|||||||
struct command_switch *cs;
|
struct command_switch *cs;
|
||||||
struct stringlist *sl;
|
struct stringlist *sl;
|
||||||
int c;
|
int c;
|
||||||
|
unsigned int found_wait = 0;
|
||||||
|
|
||||||
/* getopt does most of the parsing for us.
|
/* getopt does most of the parsing for us.
|
||||||
First, get its vectors set up. */
|
First, get its vectors set up. */
|
||||||
@ -3120,15 +3129,22 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
|
|||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
/* End of arguments, or "--" marker seen. */
|
/* End of arguments, or "--" marker seen. */
|
||||||
break;
|
break;
|
||||||
else if (c == 1)
|
|
||||||
/* An argument not starting with a dash. */
|
|
||||||
handle_non_switch_argument (coptarg, origin);
|
|
||||||
else if (c == '?')
|
else if (c == '?')
|
||||||
/* Bad option. We will print a usage message and die later.
|
/* Bad option. We will print a usage message and die later.
|
||||||
But continue to parse the other options so the user can
|
But continue to parse the other options so the user can
|
||||||
see all he did wrong. */
|
see all he did wrong. */
|
||||||
bad = 1;
|
bad = 1;
|
||||||
|
else if (c == 1)
|
||||||
|
{
|
||||||
|
/* An argument not starting with a dash. */
|
||||||
|
const unsigned int prior_found_wait = found_wait;
|
||||||
|
found_wait = handle_non_switch_argument (coptarg, origin);
|
||||||
|
if (prior_found_wait && lastgoal)
|
||||||
|
/* If the argument before this was .WAIT, wait here. */
|
||||||
|
lastgoal->wait_here = 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
/* An option starting with a dash. */
|
||||||
for (cs = switches; cs->c != '\0'; ++cs)
|
for (cs = switches; cs->c != '\0'; ++cs)
|
||||||
if (cs->c == c)
|
if (cs->c == c)
|
||||||
{
|
{
|
||||||
@ -3320,7 +3336,12 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
|
|||||||
to be returned in order, this only happens when there is a "--"
|
to be returned in order, this only happens when there is a "--"
|
||||||
argument to prevent later arguments from being options. */
|
argument to prevent later arguments from being options. */
|
||||||
while (optind < argc)
|
while (optind < argc)
|
||||||
handle_non_switch_argument (argv[optind++], origin);
|
{
|
||||||
|
const int prior_found_wait = found_wait;
|
||||||
|
found_wait = handle_non_switch_argument (argv[optind++], origin);
|
||||||
|
if (prior_found_wait && lastgoal)
|
||||||
|
lastgoal->wait_here = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (bad && origin == o_command)
|
if (bad && origin == o_command)
|
||||||
print_usage (bad);
|
print_usage (bad);
|
||||||
|
40
src/remake.c
40
src/remake.c
@ -119,6 +119,7 @@ update_goal_chain (struct goaldep *goaldeps)
|
|||||||
unsigned long last_cmd_count = 0;
|
unsigned long last_cmd_count = 0;
|
||||||
int t = touch_flag, q = question_flag, n = just_print_flag;
|
int t = touch_flag, q = question_flag, n = just_print_flag;
|
||||||
enum update_status status = us_none;
|
enum update_status status = us_none;
|
||||||
|
const unsigned int depth = rebuilding_makefiles ? 1 : 0;
|
||||||
|
|
||||||
/* Duplicate the chain so we can remove things from it. */
|
/* Duplicate the chain so we can remove things from it. */
|
||||||
struct dep *goals_orig = copy_dep_chain ((struct dep *)goaldeps);
|
struct dep *goals_orig = copy_dep_chain ((struct dep *)goaldeps);
|
||||||
@ -137,6 +138,7 @@ update_goal_chain (struct goaldep *goaldeps)
|
|||||||
while (goals != 0)
|
while (goals != 0)
|
||||||
{
|
{
|
||||||
struct dep *gu, *g, *lastgoal;
|
struct dep *gu, *g, *lastgoal;
|
||||||
|
int running = 0, wait = 0;
|
||||||
|
|
||||||
/* Start jobs that are waiting for the load to go down. */
|
/* Start jobs that are waiting for the load to go down. */
|
||||||
|
|
||||||
@ -154,16 +156,14 @@ update_goal_chain (struct goaldep *goaldeps)
|
|||||||
while (gu != 0)
|
while (gu != 0)
|
||||||
{
|
{
|
||||||
/* Iterate over all double-colon entries for this file. */
|
/* Iterate over all double-colon entries for this file. */
|
||||||
struct file *file;
|
struct file *file, *dchead;
|
||||||
int stop = 0, any_not_updated = 0;
|
int stop = 0, any_not_updated = 0;
|
||||||
|
|
||||||
g = gu->shuf ? gu->shuf : gu;
|
g = gu->shuf ? gu->shuf : gu;
|
||||||
|
|
||||||
goal_dep = g;
|
goal_dep = g;
|
||||||
|
dchead = g->file->double_colon ? g->file->double_colon : g->file;
|
||||||
for (file = g->file->double_colon ? g->file->double_colon : g->file;
|
for (file = dchead; file != NULL; file = file->prev)
|
||||||
file != NULL;
|
|
||||||
file = file->prev)
|
|
||||||
{
|
{
|
||||||
unsigned int ocommands_started;
|
unsigned int ocommands_started;
|
||||||
enum update_status fail;
|
enum update_status fail;
|
||||||
@ -188,8 +188,24 @@ update_goal_chain (struct goaldep *goaldeps)
|
|||||||
actually run. */
|
actually run. */
|
||||||
ocommands_started = commands_started;
|
ocommands_started = commands_started;
|
||||||
|
|
||||||
fail = update_file (file, rebuilding_makefiles ? 1 : 0);
|
stop = 0;
|
||||||
|
|
||||||
|
/* In the case of double colon rules, only the recipe of the 1st
|
||||||
|
rule should be blocked by .WAIT. The recipes of all subsequent
|
||||||
|
rules for the same file will execute sequentially in order
|
||||||
|
after the 1st. */
|
||||||
|
wait = file == dchead && g->wait_here && running;
|
||||||
|
if (wait)
|
||||||
|
{
|
||||||
|
DBF (DB_VERBOSE, _(".WAIT is blocking '%s'.\n"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail = update_file (file, depth);
|
||||||
check_renamed (file);
|
check_renamed (file);
|
||||||
|
running |= (file->command_state == cs_running
|
||||||
|
|| file->command_state == cs_deps_running);
|
||||||
|
|
||||||
|
|
||||||
/* Set the goal's 'changed' flag if any commands were started
|
/* Set the goal's 'changed' flag if any commands were started
|
||||||
by calling update_file above. We check this flag below to
|
by calling update_file above. We check this flag below to
|
||||||
@ -197,7 +213,6 @@ update_goal_chain (struct goaldep *goaldeps)
|
|||||||
if (commands_started > ocommands_started)
|
if (commands_started > ocommands_started)
|
||||||
g->changed = 1;
|
g->changed = 1;
|
||||||
|
|
||||||
stop = 0;
|
|
||||||
if ((fail || file->updated) && status < us_question)
|
if ((fail || file->updated) && status < us_question)
|
||||||
{
|
{
|
||||||
/* We updated this goal. Update STATUS and decide whether
|
/* We updated this goal. Update STATUS and decide whether
|
||||||
@ -249,6 +264,9 @@ update_goal_chain (struct goaldep *goaldeps)
|
|||||||
/* Reset FILE since it is null at the end of the loop. */
|
/* Reset FILE since it is null at the end of the loop. */
|
||||||
file = g->file;
|
file = g->file;
|
||||||
|
|
||||||
|
if (wait)
|
||||||
|
break;
|
||||||
|
|
||||||
if (stop || !any_not_updated)
|
if (stop || !any_not_updated)
|
||||||
{
|
{
|
||||||
/* If we have found nothing whatever to do for the goal,
|
/* If we have found nothing whatever to do for the goal,
|
||||||
@ -285,8 +303,9 @@ update_goal_chain (struct goaldep *goaldeps)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If we reached the end of the dependency graph update CONSIDERED
|
/* If we reached the end of the dependency graph update CONSIDERED
|
||||||
for the next pass. */
|
for the next pass. In the case of waiting, increment CONSIDERED to
|
||||||
if (gu == 0)
|
prevent the same file from getting pruned over and over again. */
|
||||||
|
if (gu == 0 || wait)
|
||||||
++considered;
|
++considered;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +403,8 @@ update_file (struct file *file, unsigned int depth)
|
|||||||
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 other :: rules for this target until
|
/* Don't run other :: rules for this target until
|
||||||
this rule is finished. */
|
this rule is finished. Multiple recipes running in parallel and
|
||||||
|
updating the same target will corrupt the target. */
|
||||||
return us_success;
|
return us_success;
|
||||||
|
|
||||||
if (new > status)
|
if (new > status)
|
||||||
|
@ -56,6 +56,73 @@ pre2: ; @#HELPER# -q out $@
|
|||||||
|
|
||||||
run_make_test(undef, '-j10 pre2', "pre2\n");
|
run_make_test(undef, '-j10 pre2', "pre2\n");
|
||||||
|
|
||||||
|
# sv 63856.
|
||||||
|
# .WAIT on the command line.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
pre1: ; @#HELPER# -q out start-$@ sleep 1 out end-$@
|
||||||
|
pre2: ; @#HELPER# -q out $@
|
||||||
|
|
||||||
|
# This is just here so we don't fail with older versions of make
|
||||||
|
.WAIT:
|
||||||
|
!,
|
||||||
|
'-j10 pre1 .WAIT pre2', "start-pre1\nend-pre1\npre2\n");
|
||||||
|
|
||||||
|
# Multiple consecutive .WAITs.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
all : pre1 .WAIT .WAIT .WAIT pre2
|
||||||
|
pre1: ; @#HELPER# -q out start-$@ sleep 1 out end-$@
|
||||||
|
pre2: ; @#HELPER# -q out $@
|
||||||
|
|
||||||
|
# This is just here so we don't fail with older versions of make
|
||||||
|
.WAIT:
|
||||||
|
!,
|
||||||
|
'-j10', "start-pre1\nend-pre1\npre2\n");
|
||||||
|
|
||||||
|
# First and last prerequsites are .WAIT.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
all : .WAIT pre1 .WAIT pre2 .WAIT
|
||||||
|
pre1: ; @#HELPER# -q out start-$@ sleep 1 out end-$@
|
||||||
|
pre2: ; @#HELPER# -q out $@
|
||||||
|
|
||||||
|
# This is just here so we don't fail with older versions of make
|
||||||
|
.WAIT:
|
||||||
|
!,
|
||||||
|
'-j10', "start-pre1\nend-pre1\npre2\n");
|
||||||
|
|
||||||
|
# All prerequisites are .WAITs.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
all : .WAIT .WAIT .WAIT
|
||||||
|
|
||||||
|
# This is just here so we don't fail with older versions of make
|
||||||
|
.WAIT:
|
||||||
|
!,
|
||||||
|
'-j10', "#MAKE#: Nothing to be done for 'all'.\n");
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
all:
|
||||||
|
!,
|
||||||
|
'-j10 .WAIT', "#MAKE#: Nothing to be done for 'all'.\n");
|
||||||
|
|
||||||
|
# Wait between the duplicate goals.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
all: hello.tsk .WAIT hello.tsk
|
||||||
|
hello.tsk:; $(info $@)
|
||||||
|
!,
|
||||||
|
'-j10', "hello.tsk\n#MAKE#: Nothing to be done for 'all'.\n");
|
||||||
|
|
||||||
|
# Wait between the duplicate command line goals.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
hello.tsk:; $(info $@)
|
||||||
|
!,
|
||||||
|
'-j10 hello.tsk .WAIT hello.tsk', "hello.tsk\n#MAKE#: 'hello.tsk' is up to date.\n#MAKE#: 'hello.tsk' is up to date.\n");
|
||||||
|
|
||||||
|
|
||||||
# Ensure .WAIT doesn't wait between all targets
|
# Ensure .WAIT doesn't wait between all targets
|
||||||
|
|
||||||
run_make_test(q!
|
run_make_test(q!
|
||||||
@ -71,6 +138,20 @@ pre3: ; @#HELPER# -q wait TWO out $@ file THREE
|
|||||||
|
|
||||||
unlink(qw(TWO THREE));
|
unlink(qw(TWO THREE));
|
||||||
|
|
||||||
|
# Ensure .WAIT on the command line doesn't wait between all targets.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
pre1: ; @#HELPER# -q out start-$@ sleep 1 out end-$@
|
||||||
|
pre2: ; @#HELPER# -q out start-$@ file TWO wait THREE out end-$@
|
||||||
|
pre3: ; @#HELPER# -q wait TWO out $@ file THREE
|
||||||
|
|
||||||
|
# This is just here so we don't fail with older versions of make
|
||||||
|
.WAIT:
|
||||||
|
!,
|
||||||
|
'-j10 pre1 .WAIT pre2 pre3', "start-pre1\nend-pre1\nstart-pre2\npre3\nend-pre2\n");
|
||||||
|
|
||||||
|
unlink(qw(TWO THREE));
|
||||||
|
|
||||||
# Ensure .WAIT waits for ALL targets on the left before ANY targets on the right
|
# Ensure .WAIT waits for ALL targets on the left before ANY targets on the right
|
||||||
|
|
||||||
run_make_test(q!
|
run_make_test(q!
|
||||||
@ -88,6 +169,23 @@ post2: ; @#HELPER# -q file POST2 wait POST1 out $@
|
|||||||
|
|
||||||
unlink(qw(PRE1 PRE2 POST1 POST2));
|
unlink(qw(PRE1 PRE2 POST1 POST2));
|
||||||
|
|
||||||
|
# Ensure .WAIT on the command line waits for ALL targets on the left before ANY
|
||||||
|
# targets on the right.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
pre1: ; @#HELPER# -q out start-$@ file PRE1 wait PRE2 sleep 1 out end-$@
|
||||||
|
pre2: ; @#HELPER# -q wait PRE1 out $@ file PRE2
|
||||||
|
|
||||||
|
post1: ; @#HELPER# -q wait POST2 out $@ file POST1
|
||||||
|
post2: ; @#HELPER# -q file POST2 wait POST1 out $@
|
||||||
|
|
||||||
|
# This is just here so we don't fail with older versions of make
|
||||||
|
.WAIT:
|
||||||
|
!,
|
||||||
|
'-j10 pre1 pre2 .WAIT post1 post2', "start-pre1\npre2\nend-pre1\npost1\npost2\n");
|
||||||
|
|
||||||
|
unlink(qw(PRE1 PRE2 POST1 POST2));
|
||||||
|
|
||||||
# See if .WAIT takes effect between different lists of prereqs
|
# See if .WAIT takes effect between different lists of prereqs
|
||||||
# In the current implementation, .WAIT waits only between two prerequisites
|
# In the current implementation, .WAIT waits only between two prerequisites
|
||||||
# in a given target. These same two targets might be run in a different
|
# in a given target. These same two targets might be run in a different
|
||||||
@ -180,6 +278,17 @@ pre2: ; @#HELPER# -q out $@
|
|||||||
!,
|
!,
|
||||||
'-j10 --shuffle=reverse', "start-pre1\nend-pre1\npre2\n");
|
'-j10 --shuffle=reverse', "start-pre1\nend-pre1\npre2\n");
|
||||||
|
|
||||||
|
# Ensure we don't shuffle if .WAIT is set on the command line.
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
pre1: ; @#HELPER# -q out start-$@ sleep 1 out end-$@
|
||||||
|
pre2: ; @#HELPER# -q out $@
|
||||||
|
|
||||||
|
# This is just here so we don't fail with older versions of make
|
||||||
|
.WAIT:
|
||||||
|
!,
|
||||||
|
'-j10 --shuffle=reverse pre1 .WAIT pre2', "start-pre1\nend-pre1\npre2\n");
|
||||||
|
|
||||||
# Warn about invalid .WAIT definitions
|
# Warn about invalid .WAIT definitions
|
||||||
|
|
||||||
run_make_test(q!
|
run_make_test(q!
|
||||||
|
Loading…
Reference in New Issue
Block a user