参照元

説明

引数

返り値

参考

実装

/* 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];

      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 = &times[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;
  }
}

コメント


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-05-10 (金) 13:49:04