mirror of
https://github.com/mirror/make.git
synced 2026-08-19 16:33:28 +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:
committed by
Paul Smith
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)
|
||||
|
||||
Reference in New Issue
Block a user