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. */
|
||||
static void
|
||||
/* Non-option argument. It might be a variable definition.
|
||||
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)
|
||||
{
|
||||
struct variable *v;
|
||||
|
||||
if (arg[0] == '-' && arg[1] == '\0')
|
||||
/* Ignore plain '-' for compatibility. */
|
||||
return;
|
||||
return 0;
|
||||
|
||||
#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.
|
||||
Check ARG[0] because if the top makefile resets MAKEOVERRIDES
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 stringlist *sl;
|
||||
int c;
|
||||
unsigned int found_wait = 0;
|
||||
|
||||
/* getopt does most of the parsing for us.
|
||||
First, get its vectors set up. */
|
||||
@ -3120,15 +3129,22 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
|
||||
if (c == EOF)
|
||||
/* End of arguments, or "--" marker seen. */
|
||||
break;
|
||||
else if (c == 1)
|
||||
/* An argument not starting with a dash. */
|
||||
handle_non_switch_argument (coptarg, origin);
|
||||
else if (c == '?')
|
||||
/* Bad option. We will print a usage message and die later.
|
||||
But continue to parse the other options so the user can
|
||||
see all he did wrong. */
|
||||
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
|
||||
/* An option starting with a dash. */
|
||||
for (cs = switches; cs->c != '\0'; ++cs)
|
||||
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 "--"
|
||||
argument to prevent later arguments from being options. */
|
||||
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)
|
||||
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;
|
||||
int t = touch_flag, q = question_flag, n = just_print_flag;
|
||||
enum update_status status = us_none;
|
||||
const unsigned int depth = rebuilding_makefiles ? 1 : 0;
|
||||
|
||||
/* Duplicate the chain so we can remove things from it. */
|
||||
struct dep *goals_orig = copy_dep_chain ((struct dep *)goaldeps);
|
||||
@ -137,6 +138,7 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
while (goals != 0)
|
||||
{
|
||||
struct dep *gu, *g, *lastgoal;
|
||||
int running = 0, wait = 0;
|
||||
|
||||
/* Start jobs that are waiting for the load to go down. */
|
||||
|
||||
@ -154,16 +156,14 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
while (gu != 0)
|
||||
{
|
||||
/* Iterate over all double-colon entries for this file. */
|
||||
struct file *file;
|
||||
struct file *file, *dchead;
|
||||
int stop = 0, any_not_updated = 0;
|
||||
|
||||
g = gu->shuf ? gu->shuf : gu;
|
||||
|
||||
goal_dep = g;
|
||||
|
||||
for (file = g->file->double_colon ? g->file->double_colon : g->file;
|
||||
file != NULL;
|
||||
file = file->prev)
|
||||
dchead = g->file->double_colon ? g->file->double_colon : g->file;
|
||||
for (file = dchead; file != NULL; file = file->prev)
|
||||
{
|
||||
unsigned int ocommands_started;
|
||||
enum update_status fail;
|
||||
@ -188,8 +188,24 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
actually run. */
|
||||
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);
|
||||
running |= (file->command_state == cs_running
|
||||
|| file->command_state == cs_deps_running);
|
||||
|
||||
|
||||
/* Set the goal's 'changed' flag if any commands were started
|
||||
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)
|
||||
g->changed = 1;
|
||||
|
||||
stop = 0;
|
||||
if ((fail || file->updated) && status < us_question)
|
||||
{
|
||||
/* 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. */
|
||||
file = g->file;
|
||||
|
||||
if (wait)
|
||||
break;
|
||||
|
||||
if (stop || !any_not_updated)
|
||||
{
|
||||
/* 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
|
||||
for the next pass. */
|
||||
if (gu == 0)
|
||||
for the next pass. In the case of waiting, increment CONSIDERED to
|
||||
prevent the same file from getting pruned over and over again. */
|
||||
if (gu == 0 || wait)
|
||||
++considered;
|
||||
}
|
||||
|
||||
@ -384,7 +403,8 @@ update_file (struct file *file, unsigned int depth)
|
||||
if (f->command_state == cs_running
|
||||
|| f->command_state == cs_deps_running)
|
||||
/* 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;
|
||||
|
||||
if (new > status)
|
||||
|
@ -56,6 +56,73 @@ pre2: ; @#HELPER# -q out $@
|
||||
|
||||
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
|
||||
|
||||
run_make_test(q!
|
||||
@ -71,6 +138,20 @@ pre3: ; @#HELPER# -q wait TWO out $@ file 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
|
||||
|
||||
run_make_test(q!
|
||||
@ -88,6 +169,23 @@ post2: ; @#HELPER# -q file POST2 wait POST1 out $@
|
||||
|
||||
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
|
||||
# In the current implementation, .WAIT waits only between two prerequisites
|
||||
# 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");
|
||||
|
||||
# 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
|
||||
|
||||
run_make_test(q!
|
||||
|
Loading…
Reference in New Issue
Block a user