参照元†
返り値†
/* Execute the command specified by the arguments on the current line of spec.
When using pipes, this includes several piped-together commands
with `|' between them.
Return 0 if successful, -1 if failed. */
static int
execute (void)
{
int i;
int n_commands; /* # of command. */
char *string;
struct pex_obj *pex;
struct command
{
const char *prog; /* program name. */
const char **argv; /* vector of args. */
};
const char *arg;
struct command *commands; /* each command buffer with above info. */
gcc_assert (!processing_spec_function);
if (wrapper_string)
{
string = find_a_file (&exec_prefixes,
argbuf[0], X_OK, false);
if (string)
argbuf[0] = string;
insert_wrapper (wrapper_string);
}
/* Count # of piped commands. */
for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++)
if (strcmp (arg, "|") == 0)
n_commands++;
/* Get storage for each command. */
commands = (struct command *) alloca (n_commands * sizeof (struct command));
/* Split argbuf into its separate piped processes,
and record info about each one.
Also search for the programs that are to be run. */
argbuf.safe_push (0);
commands[0].prog = argbuf[0]; /* first command. */
commands[0].argv = argbuf.address ();
if (!wrapper_string)
{
string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false);
commands[0].argv[0] = (string) ? string : commands[0].argv[0];
}
for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++)
if (arg && strcmp (arg, "|") == 0)
{ /* each command. */
#if defined (__MSDOS__) || defined (OS2) || defined (VMS)
fatal_error (input_location, "-pipe not supported");
#endif
argbuf[i] = 0; /* Termination of
command args. */
commands[n_commands].prog = argbuf[i + 1];
commands[n_commands].argv
= &(argbuf.address ())[i + 1];
string = find_a_file (&exec_prefixes, commands[n_commands].prog,
X_OK, false);
if (string)
commands[n_commands].argv[0] = string;
n_commands++;
}
/* If -v, print what we are about to do, and maybe query. */
if (verbose_flag)
{
/* For help listings, put a blank line between sub-processes. */
if (print_help_list)
fputc ('\n', stderr);
/* Print each piped command as a separate line. */
for (i = 0; i < n_commands; i++)
{
const char *const *j;
if (verbose_only_flag)
{
for (j = commands[i].argv; *j; j++)
{
const char *p;
for (p = *j; *p; ++p)
if (!ISALNUM ((unsigned char) *p)
&& *p != '_' && *p != '/' && *p != '-' && *p != '.')
break;
if (*p || !*j)
{
fprintf (stderr, " \"");
for (p = *j; *p; ++p)
{
if (*p == '"' || *p == '\\' || *p == '$')
fputc ('\\', stderr);
fputc (*p, stderr);
}
fputc ('"', stderr);
}
/* If it's empty, print "". */
else if (!**j)
fprintf (stderr, " \"\"");
else
fprintf (stderr, " %s", *j);
}
}
else
for (j = commands[i].argv; *j; j++)
/* If it's empty, print "". */
if (!**j)
fprintf (stderr, " \"\"");
else
fprintf (stderr, " %s", *j);
/* Print a pipe symbol after all but the last command. */
if (i + 1 != n_commands)
fprintf (stderr, " |");
fprintf (stderr, "\n");
}
fflush (stderr);
if (verbose_only_flag != 0)
{
/* verbose_only_flag should act as if the spec was
executed, so increment execution_count before
returning. This prevents spurious warnings about
unused linker input files, etc. */
execution_count++;
return 0;
}
#ifdef DEBUG
fnotice (stderr, "\nGo ahead? (y or n) ");
fflush (stderr);
i = getchar ();
if (i != '\n')
while (getchar () != '\n')
;
if (i != 'y' && i != 'Y')
return 0;
#endif /* DEBUG */
}
#ifdef ENABLE_VALGRIND_CHECKING
/* Run the each command through valgrind. To simplify prepending the
path to valgrind and the option "-q" (for quiet operation unless
something triggers), we allocate a separate argv array. */
for (i = 0; i < n_commands; i++)
{
const char **argv;
int argc;
int j;
for (argc = 0; commands[i].argv[argc] != NULL; argc++)
;
argv = XALLOCAVEC (const char *, argc + 3);
argv[0] = VALGRIND_PATH;
argv[1] = "-q";
for (j = 2; j < argc + 2; j++)
argv[j] = commands[i].argv[j - 2];
argv[j] = NULL;
commands[i].argv = argv;
commands[i].prog = argv[0];
}
#endif
/* Run each piped subprocess. */
pex = pex_init (PEX_USE_PIPES | ((report_times || report_times_to_file)
? PEX_RECORD_TIMES : 0),
progname, temp_filename);
if (pex == NULL)
fatal_error (input_location, "pex_init failed: %m");
for (i = 0; i < n_commands; i++)
{
const char *errmsg;
int err;
const char *string = commands[i].argv[0];
int kkk;
printf("\n------------------------------\n");
for (kkk = 0; commands[i].argv[kkk]; kkk++)
printf("%s ", commands[i].argv[kkk]);
printf("\n------------------------------\n");
errmsg = pex_run (pex,
((i + 1 == n_commands ? PEX_LAST : 0)
| (string == commands[i].prog ? PEX_SEARCH : 0)),
string, CONST_CAST (char **, commands[i].argv),
NULL, NULL, &err);
if (errmsg != NULL)
{
if (err == 0)
fatal_error (input_location, errmsg);
else
{
errno = err;
pfatal_with_name (errmsg);
}
}
if (i && string != commands[i].prog)
free (CONST_CAST (char *, string));
}
execution_count++;
/* Wait for all the subprocesses to finish. */
{
int *statuses;
struct pex_time *times = NULL;
int ret_code = 0;
statuses = (int *) alloca (n_commands * sizeof (int));
if (!pex_get_status (pex, n_commands, statuses))
fatal_error (input_location, "failed to get exit status: %m");
if (report_times || report_times_to_file)
{
times = (struct pex_time *) alloca (n_commands * sizeof (struct pex_time));
if (!pex_get_times (pex, n_commands, times))
fatal_error (input_location, "failed to get process times: %m");
}
pex_free (pex);
for (i = 0; i < n_commands; ++i)
{
int status = statuses[i];
if (WIFSIGNALED (status))
switch (WTERMSIG (status))
{
case SIGINT:
case SIGTERM:
/* SIGQUIT and SIGKILL are not available on MinGW. */
#ifdef SIGQUIT
case SIGQUIT:
#endif
#ifdef SIGKILL
case SIGKILL:
#endif
/* The user (or environment) did something to the
inferior. Making this an ICE confuses the user into
thinking there's a compiler bug. Much more likely is
the user or OOM killer nuked it. */
fatal_error (input_location,
"%s signal terminated program %s",
strsignal (WTERMSIG (status)),
commands[i].prog);
break;
#ifdef SIGPIPE
case SIGPIPE:
/* SIGPIPE is a special case. It happens in -pipe mode
when the compiler dies before the preprocessor is
done, or the assembler dies before the compiler is
done. There's generally been an error already, and
this is just fallout. So don't generate another
error unless we would otherwise have succeeded. */
if (signal_count || greatest_status >= MIN_FATAL_STATUS)
{
signal_count++;
ret_code = -1;
break;
}
#endif
/* FALLTHROUGH */
default:
/* The inferior failed to catch the signal. */
internal_error_no_backtrace ("%s signal terminated program %s",
strsignal (WTERMSIG (status)),
commands[i].prog);
}
else if (WIFEXITED (status)
&& WEXITSTATUS (status) >= MIN_FATAL_STATUS)
{
/* For ICEs in cc1, cc1obj, cc1plus see if it is
reproducible or not. */
const char *p;
if (flag_report_bug
&& WEXITSTATUS (status) == ICE_EXIT_CODE
&& i == 0
&& (p = strrchr (commands[0].argv[0], DIR_SEPARATOR))
&& ! strncmp (p + 1, "cc1", 3))
try_generate_repro (commands[0].argv);
if (WEXITSTATUS (status) > greatest_status)
greatest_status = WEXITSTATUS (status);
ret_code = -1;
}
if (report_times || report_times_to_file)
{
struct pex_time *pt = ×[i];
double ut, st;
ut = ((double) pt->user_seconds
+ (double) pt->user_microseconds / 1.0e6);
st = ((double) pt->system_seconds
+ (double) pt->system_microseconds / 1.0e6);
if (ut + st != 0)
{
if (report_times)
fnotice (stderr, "# %s %.2f %.2f\n",
commands[i].prog, ut, st);
if (report_times_to_file)
{
int c = 0;
const char *const *j;
fprintf (report_times_to_file, "%g %g", ut, st);
for (j = &commands[i].prog; *j; j = &commands[i].argv[++c])
{
const char *p;
for (p = *j; *p; ++p)
if (*p == '"' || *p == '\\' || *p == '$'
|| ISSPACE (*p))
break;
if (*p)
{
fprintf (report_times_to_file, " \"");
for (p = *j; *p; ++p)
{
if (*p == '"' || *p == '\\' || *p == '$')
fputc ('\\', report_times_to_file);
fputc (*p, report_times_to_file);
}
fputc ('"', report_times_to_file);
}
else
fprintf (report_times_to_file, " %s", *j);
}
fputc ('\n', report_times_to_file);
}
}
}
}
if (commands[0].argv[0] != commands[0].prog)
free (CONST_CAST (char *, commands[0].argv[0]));
return ret_code;
}
}
コメント†