Exemplo n.º 1
0
static void
do_compile (const char **current_argv, int current_argc)
{
  char *errmsg_fmt, *errmsg_arg;
  int index = 0;

  int dash_o_index = current_argc;
  int of_index = current_argc + 1;
  int argc_count = current_argc + 2;

  while (index < num_arches)
    {
      int additional_arch_options = 0;

      current_argv[0] = get_driver_name (get_arch_name (arches[index]));

      /* setup output file.  */
      out_files[num_outfiles] = make_temp_file (".out");
      current_argv[dash_o_index] = "-o";
      current_argv[of_index] = out_files [num_outfiles];
      num_outfiles++;

      /* Add arch option as the last option. Do not add any other option
	 before removing this option.  */
      additional_arch_options = add_arch_options (index, current_argv, argc_count);
      argc_count += additional_arch_options;

      commands[index].prog = current_argv[0];
      commands[index].argv = current_argv;

      current_argv[argc_count] = NULL;

#ifdef DEBUG
      debug_command_line (current_argv, argc_count);
#endif
      commands[index].pid = pexecute (current_argv[0],
				      (char *const *)current_argv,
				      progname, NULL,
				      &errmsg_fmt,
				      &errmsg_arg,
				      PEXECUTE_SEARCH | PEXECUTE_ONE);

      if (commands[index].pid == -1)
	pfatal_pexecute (errmsg_fmt, errmsg_arg);

      do_wait (commands[index].pid, commands[index].prog);
      fflush (stdout);

      /* Remove the last arch option added in the current_argv list.  */
      if (additional_arch_options)
	argc_count -= remove_arch_options (current_argv, argc_count);
      index++;
    }
}
static void
do_lipo (int start_outfile_index, const char *out_file)
{
  int i, j, pid;
  char *errmsg_fmt, *errmsg_arg;

  /* Populate lipo arguments.  */
  lipo_argv[0] = "lipo";
  lipo_argv[1] = "-create";
  lipo_argv[2] = "-o";
  lipo_argv[3] = out_file;

  /* Already 4 lipo arguments are set.  Now add all lipo inputs.  */
  j = 4;
  for (i = 0; i < num_arches; i++)
    lipo_argv[j++] = out_files[start_outfile_index + i];

  /* Add the NULL at the end.  */
  lipo_argv[j++] = NULL;

#ifdef DEBUG
  debug_command_line (lipo_argv, j);
#endif

  if (verbose_flag)
    {
      for (i = 0; lipo_argv[i]; i++)
	fprintf (stderr, "%s ", lipo_argv[i]);
      fprintf (stderr, "\n");
    }
  pid = pexecute (lipo_argv[0], (char *const *)lipo_argv, progname, NULL, &errmsg_fmt,
		  &errmsg_arg, PEXECUTE_SEARCH | PEXECUTE_ONE);

  if (pid == -1)
    pfatal_pexecute (errmsg_fmt, errmsg_arg);

  do_wait (pid, lipo_argv[0]);
}
Exemplo n.º 3
0
static int
run (const char *what, char *args)
{
  char *s;
  int pid, wait_status, retcode;
  int i;
  const char **argv;
  char *errmsg_fmt, *errmsg_arg;
  char *temp_base = choose_temp_base ();
  int in_quote;
  char sep;

  if (verbose || dry_run)
    fprintf (stderr, "%s %s\n", what, args);

  /* Count the args */
  i = 0;
  for (s = args; *s; s++)
    if (*s == ' ')
      i++;
  i++;
  argv = xmalloc (sizeof (char *) * (i + 3));
  i = 0;
  argv[i++] = what;
  s = args;
  while (1)
    {
      while (*s == ' ' && *s != 0)
	s++;
      if (*s == 0)
	break;
      in_quote = (*s == '\'' || *s == '"');
      sep = (in_quote) ? *s++ : ' ';
      argv[i++] = s;
      while (*s != sep && *s != 0)
	s++;
      if (*s == 0)
	break;
      *s++ = 0;
      if (in_quote)
	s++;
    }
  argv[i++] = NULL;

  if (dry_run)
    return 0;

  pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
  free (argv);

  if (pid == -1)
    {
      int errno_val = errno;

      fprintf (stderr, "%s: ", prog_name);
      fprintf (stderr, errmsg_fmt, errmsg_arg);
      fprintf (stderr, ": %s\n", strerror (errno_val));
      return 1;
    }

  retcode = 0;
  pid = pwait (pid, &wait_status, 0);
  if (pid == -1)
    {
      warn (_("pwait returns: %s"), strerror (errno));
      retcode = 1;
    }
  else if (WIFSIGNALED (wait_status))
    {
      warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
      retcode = 1;
    }
  else if (WIFEXITED (wait_status))
    {
      if (WEXITSTATUS (wait_status) != 0)
	{
	  warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
	  retcode = 1;
	}
    }
  else
    retcode = 1;

  return retcode;
}
/* Main entry point. This is gcc driver driver!
   Interpret -arch flag from the list of input arguments. Invoke appropriate
   compiler driver. 'lipo' the results if more than one -arch is supplied.  */
int
main (int argc, const char **argv)
{
  size_t i;
  int l, pid, argv_0_len, prog_len;
  char *errmsg_fmt, *errmsg_arg;
  char *override_option_str = NULL;
  char path_buffer[2*PATH_MAX+1];
  int linklen;

  total_argc = argc;
  prog_len = 0;

  argv_0_len = strlen (argv[0]);

  /* Get the progname, required by pexecute () and program location.  */
  prog_len = get_prog_name_len (argv[0]);

  /* If argv[0] is all program name (no slashes), search the PATH environment
     variable to get the fully resolved path to the executable. */
  if (prog_len == argv_0_len)
    {
#ifdef DEBUG
      progname = argv[0] + argv_0_len - prog_len;
      fprintf (stderr,"%s: before PATH resolution, full progname = %s\n",
               argv[0]+argv_0_len-prog_len, argv[0]);
#endif
      argv[0] = resolve_path_to_executable (argv[0]);
      prog_len = get_prog_name_len (argv[0]);
      argv_0_len = strlen(argv[0]);
    }

  /* If argv[0] is a symbolic link, use the directory of the pointed-to file
     to find compiler components. */

  if ((linklen = readlink (argv[0], path_buffer, PATH_MAX)) != -1)
    {
      /* readlink succeeds if argv[0] is a symlink.  path_buffer now contains
	 the file referenced. */
      path_buffer[linklen] = '\0';
#ifdef DEBUG
      progname = argv[0] + argv_0_len - prog_len;
      fprintf (stderr, "%s: before symlink, full prog = %s target = %s\n",
	       progname, argv[0], path_buffer);
#endif
      argv[0] = resolve_symlink(argv[0], path_buffer, argv_0_len, prog_len);
      argv_0_len = strlen(argv[0]);

      /* Get the progname, required by pexecute () and program location.  */
      prog_len = get_prog_name_len (argv[0]);

#ifdef DEBUG
      progname = argv[0] + argv_0_len - prog_len;
      printf("%s: ARGV[0] after symlink = %s\n", progname, argv[0]);
#endif
    }

  progname = argv[0] + argv_0_len - prog_len;

  /* Setup driver prefix.  */
  prefix_len = argv_0_len - prog_len;
  curr_dir = (char *) malloc (sizeof (char) * (prefix_len + 1));
  strncpy (curr_dir, argv[0], prefix_len);
  curr_dir[prefix_len] = '\0';
  driver_exec_prefix = (argv[0], "/usr/bin", curr_dir);

#ifdef DEBUG
  fprintf (stderr,"%s: full progname = %s\n", progname, argv[0]);
  fprintf (stderr,"%s: progname = %s\n", progname, progname);
  fprintf (stderr,"%s: driver_exec_prefix = %s\n", progname, driver_exec_prefix);
#endif

  /* Before we get too far, rewrite the command line with any requested overrides */
  if ((override_option_str = getenv ("QA_OVERRIDE_GCC3_OPTIONS")) != NULL)
    rewrite_command_line(override_option_str, &argc, (char***)&argv);



  initialize ();

  /* Process arguments. Take appropriate actions when
     -arch, -c, -S, -E, -o is encountered. Find input file name.  */
  for (i = 1; i < argc; i++)
    {
      if (!strcmp (argv[i], "-arch"))
	{
	  if (i + 1 >= argc)
	    abort ();

	  add_arch (argv[i+1]);
	  i++;
	}
      else if (!strcmp (argv[i], "-c"))
	{
	  new_argv[new_argc++] = argv[i];
	  compile_only_request = 1;
	}
      else if (!strcmp (argv[i], "-S"))
	{
	  new_argv[new_argc++] = argv[i];
	  asm_output_request = 1;
	}
      else if (!strcmp (argv[i], "-E"))
	{
	  new_argv[new_argc++] = argv[i];
	  preprocessed_output_request = 1;
	}
      else if (!strcmp (argv[i], "-MD") || !strcmp (argv[i], "-MMD"))
	{
	  new_argv[new_argc++] = argv[i];
	  dash_capital_m_seen = 1;
	}
      else if (!strcmp (argv[i], "-m32"))
	{
	  new_argv[new_argc++] = argv[i];
	  dash_m32_seen = 1;
	}
      else if (!strcmp (argv[i], "-m64"))
	{
	  new_argv[new_argc++] = argv[i];
	  dash_m64_seen = 1;
	}
      else if (!strcmp (argv[i], "-dynamiclib"))
	{
	  new_argv[new_argc++] = argv[i];
	  dash_dynamiclib_seen = 1;
        }
      else if (!strcmp (argv[i], "-v"))
	{
	  new_argv[new_argc++] = argv[i];
	  verbose_flag = 1;
	}
      else if (!strcmp (argv[i], "-o"))
	{
	  if (i + 1 >= argc)
	    fatal ("argument to '-o' is missing");

	  output_filename = argv[i+1];
	  i++;
	}
      else if ((! strcmp (argv[i], "-pass-exit-codes"))
	       || (! strcmp (argv[i], "-print-search-dirs"))
	       || (! strcmp (argv[i], "-print-libgcc-file-name"))
	       || (! strncmp (argv[i], "-print-file-name=", 17))
	       || (! strncmp (argv[i], "-print-prog-name=", 17))
	       || (! strcmp (argv[i], "-print-multi-lib"))
	       || (! strcmp (argv[i], "-print-multi-directory"))
	       || (! strcmp (argv[i], "-print-multi-os-directory"))
	       || (! strcmp (argv[i], "-ftarget-help"))
	       || (! strcmp (argv[i], "-fhelp"))
	       || (! strcmp (argv[i], "+e"))
	       || (! strncmp (argv[i], "-Wa,",4))
	       || (! strncmp (argv[i], "-Wp,",4))
	       || (! strncmp (argv[i], "-Wl,",4))
	       || (! strncmp (argv[i], "-l", 2))
	       || (! strncmp (argv[i], "-weak-l", 7))
	       || (! strncmp (argv[i], "-specs=", 7))
	       || (! strcmp (argv[i], "-ObjC"))
	       || (! strcmp (argv[i], "-fobjC"))
	       || (! strcmp (argv[i], "-ObjC++"))
	       || (! strcmp (argv[i], "-time"))
	       || (! strcmp (argv[i], "-###"))
	       || (! strcmp (argv[i], "-fconstant-cfstrings"))
	       || (! strcmp (argv[i], "-fno-constant-cfstrings"))
	       || (! strcmp (argv[i], "-static-libgcc"))
	       || (! strcmp (argv[i], "-shared-libgcc"))
	       || (! strcmp (argv[i], "-pipe"))
	       )
	{
	  new_argv[new_argc++] = argv[i];
	}
      else if (! strcmp (argv[i], "-save-temps")
	       || ! strcmp (argv[i], "--save-temps"))
	{
	  new_argv[new_argc++] = argv[i];
	  save_temps_seen = 1;
	}
      else if ((! strcmp (argv[i], "-Xlinker"))
	       || (! strcmp (argv[i], "-Xassembler"))
	       || (! strcmp (argv[i], "-Xpreprocessor"))
	       || (! strcmp (argv[i], "-l"))
	       || (! strcmp (argv[i], "-weak_library"))
	       || (! strcmp (argv[i], "-weak_framework"))
	       || (! strcmp (argv[i], "-specs"))
	       || (! strcmp (argv[i], "-framework"))
	       )
	{
	  new_argv[new_argc++] = argv[i];
	  i++;
	  new_argv[new_argc++] = argv[i];
	}
      else if (! strncmp (argv[i], "-Xarch_", 7))
	{
	  arch_conditional[new_argc] = get_arch_name (argv[i] + 7);
	  i++;
	  new_argv[new_argc++] = argv[i];
	}
      else if (argv[i][0] == '-' && argv[i][1] != 0)
	{
	  const char *p = &argv[i][1];
	  int c = *p;

	  /* First copy this flag itself.  */
	  new_argv[new_argc++] = argv[i];

	  if (argv[i][1] == 'M')
	    dash_capital_m_seen = 1;

	  /* Now copy this flag's arguments, if any, appropriately.  */
	  if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
	      || WORD_SWITCH_TAKES_ARG (p))
	    {
	      int j = 0;
	      int n_args = WORD_SWITCH_TAKES_ARG (p);
	      if (n_args == 0)
		{
		  /* Count only the option arguments in separate argv elements.  */
		  n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
		}
	      if (i + n_args >= argc)
		fatal ("argument to `-%s' is missing", p);


	      while ( j < n_args)
		{
		  i++;
		  new_argv[new_argc++] = argv[i];
		  j++;
		}
	    }

	}
      else
	{
	  struct input_filename *ifn;
	  new_argv[new_argc++] = argv[i];
	  ifn = (struct input_filename *) malloc (sizeof (struct input_filename));
	  ifn->name = argv[i];
	  ifn->index = i;
	  ifn->next = NULL;
	  num_infiles++;

	  if (last_infile)
	      last_infile->next = ifn;
	  else
	    in_files = ifn;

	  last_infile = ifn;
	}
    }

#if 0
  if (num_infiles == 0)
    fatal ("no input files");
#endif

  if (num_arches == 0)
    add_arch(get_arch_name(NULL));

  if (num_arches > 1)
    {
      if (preprocessed_output_request
	  || save_temps_seen
	  || asm_output_request
	  || dash_capital_m_seen)
	fatal ("-E, -S, -save-temps and -M options are not allowed with multiple -arch flags");
    }
  /* If -arch is not present OR Only one -arch <blah> is specified.
     Invoke appropriate compiler driver.  FAT build is not required in this
     case.  */

  if (num_arches == 1)
    {
      int arch_specific_argc;
      const char **arch_specific_argv;

      /* Find compiler driver based on -arch <foo> and add approriate
	 -m* argument.  */
      new_argv[0] = get_driver_name (get_arch_name (arches[0]));
      new_argc = new_argc + add_arch_options (0, new_argv, new_argc);

#ifdef DEBUG
      printf ("%s: invoking single driver name = %s\n", progname, new_argv[0]);
#endif

      /* Re insert output file name.  */
      if (output_filename)
	{
	  new_argv[new_argc++] = "-o";
	  new_argv[new_argc++] = output_filename;
	}

      /* Add the NULL.  */
      new_argv[new_argc] = NULL;

      arch_specific_argv =
	(const char **) malloc ((new_argc + 1) * sizeof (const char *));
      arch_specific_argc = filter_args_for_arch (new_argv,
						 new_argc,
						 arch_specific_argv,
						 get_arch_name (arches[0]));

#ifdef DEBUG
      debug_command_line (arch_specific_argv, arch_specific_argc);
#endif

      pid = pexecute (arch_specific_argv[0], (char *const *)arch_specific_argv,
		      progname, NULL, &errmsg_fmt, &errmsg_arg,
		      PEXECUTE_SEARCH | PEXECUTE_ONE);

      if (pid == -1)
	pfatal_pexecute (errmsg_fmt, errmsg_arg);

      do_wait (pid, arch_specific_argv[0]);
    }
  else
    {
      /* Handle multiple -arch <blah>.  */

      /* If more than one input files are supplied but only one output filename
	 is present then IMA will be used.  */
      if (num_infiles > 1 && !compile_only_request)
	ima_is_used = 1;

      /* Linker wants to know this in case of multiple -arch.  */
      if (!compile_only_request && !dash_dynamiclib_seen)
	new_argv[new_argc++] = "-Wl,-arch_multiple";


      /* If only one input file is specified OR IMA is used then expected output
	 is one FAT binary.  */
      if (num_infiles == 1 || ima_is_used)
	{
	  const char *out_file;

	     /* Create output file name based on
	     input filename, if required.  */
	  if (compile_only_request && !output_filename && num_infiles == 1)
	    out_file = strip_path_and_suffix (in_files->name, ".o");
	  else
	    out_file = (output_filename ? output_filename : final_output);


	  /* Linker wants to know name of output file using one extra arg.  */
	  if (!compile_only_request)
	    {
	      char *oname = (char *)(output_filename ? output_filename : final_output);
	      char *n =  malloc (sizeof (char) * (strlen (oname) + 5));
	      strcpy (n, "-Wl,");
	      strcat (n, oname);
	      new_argv[new_argc++] = "-Wl,-final_output";
	      new_argv[new_argc++] = n;
	    }

	  /* Compile file(s) for each arch and lipo 'em together.  */
	  do_compile (new_argv, new_argc);

	  /* Make FAT binary by combining individual output files for each
	     architecture, using 'lipo'.  */
	  do_lipo (0, out_file);
	}
      else
	{
	  /* Multiple input files are present and IMA is not used.
	     Which means need to generate multiple FAT files.  */
	  do_compile_separately ();
	  do_lipo_separately ();
	}
    }

  final_cleanup ();
  free (curr_dir);
  return greatest_status;
}
Exemplo n.º 5
0
int
main (int argc, char **argv)
{
  int trace;
  struct pex_obj *test_pex_tmp;
  int test_pex_status;
  FILE *test_pex_file;
  struct pex_obj *pex1;
  char *subargv[10];
  int status;
  FILE *e;
  int statuses[10];

  trace = 0;
  if (argc > 1 && strcmp (argv[1], "-t") == 0)
    {
      trace = 1;
      --argc;
      ++argv;
    }

  if (argc > 1)
    do_cmd (argc, argv);

#define TEST_PEX_INIT(FLAGS, TEMPBASE)					\
  (((test_pex_tmp = pex_init (FLAGS, "test-pexecute", TEMPBASE))	\
    != NULL)								\
   ? test_pex_tmp							\
   : (FATAL_ERROR ("pex_init failed", 0), NULL))

#define TEST_PEX_RUN(PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, ERRNAME)	\
  do									\
    {									\
      int err;								\
      const char *pex_run_err;						\
      if (trace)							\
	fprintf (stderr, "Line %d: running %s %s\n",			\
		 __LINE__, EXECUTABLE, ARGV[0]);			\
      pex_run_err = pex_run (PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME,	\
			     ERRNAME, &err);				\
      if (pex_run_err != NULL)						\
	FATAL_ERROR (pex_run_err, err);					\
    }									\
  while (0)

#define TEST_PEX_GET_STATUS_1(PEXOBJ)					\
  (pex_get_status (PEXOBJ, 1, &test_pex_status)				\
   ? test_pex_status							\
   : (FATAL_ERROR ("pex_get_status failed", errno), 1))

#define TEST_PEX_GET_STATUS(PEXOBJ, COUNT, VECTOR)			\
  do									\
    {									\
      if (!pex_get_status (PEXOBJ, COUNT, VECTOR))			\
	FATAL_ERROR ("pex_get_status failed", errno);			\
    }									\
  while (0)

#define TEST_PEX_READ_OUTPUT(PEXOBJ)					\
  ((test_pex_file = pex_read_output (PEXOBJ, 0)) != NULL		\
   ? test_pex_file							\
   : (FATAL_ERROR ("pex_read_output failed", errno), NULL))

  remove ("temp.x");
  remove ("temp.y");

  memset (subargv, 0, sizeof subargv);

  subargv[0] = "./test-pexecute";

  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
  subargv[1] = "exit";
  subargv[2] = NULL;
  TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
  status = TEST_PEX_GET_STATUS_1 (pex1);
  if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
    ERROR ("exit failed");
  pex_free (pex1);

  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
  subargv[1] = "error";
  subargv[2] = NULL;
  TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
  status = TEST_PEX_GET_STATUS_1 (pex1);
  if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_FAILURE)
    ERROR ("error test failed");
  pex_free (pex1);

  /* We redirect stderr to a file to avoid an error message which is
     printed on mingw32 when the child calls abort.  */
  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
  subargv[1] = "abort";
  subargv[2] = NULL;
  TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, "temp.z");
  status = TEST_PEX_GET_STATUS_1 (pex1);
  if (!WIFSIGNALED (status) || WTERMSIG (status) != SIGABRT)
    ERROR ("abort failed");
  pex_free (pex1);
  remove ("temp.z");

  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
  subargv[1] = "echo";
  subargv[2] = "foo";
  subargv[3] = NULL;
  TEST_PEX_RUN (pex1, 0, "./test-pexecute", subargv, NULL, NULL);
  e = TEST_PEX_READ_OUTPUT (pex1);
  CHECK_LINE (e, "foo");
  if (TEST_PEX_GET_STATUS_1 (pex1) != 0)
    ERROR ("echo exit status failed");
  pex_free (pex1);

  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
  subargv[1] = "echo";
  subargv[2] = "bar";
  subargv[3] = NULL;
  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
  subargv[1] = "copy";
  subargv[2] = NULL;
  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
  e = TEST_PEX_READ_OUTPUT (pex1);
  CHECK_LINE (e, "bar");
  TEST_PEX_GET_STATUS (pex1, 2, statuses);
  if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
      || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
    ERROR ("copy exit status failed");
  pex_free (pex1);
  if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
    ERROR ("temporary files exist");

  pex1 = TEST_PEX_INIT (0, "temp");
  subargv[1] = "echo";
  subargv[2] = "bar";
  subargv[3] = NULL;
  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
  subargv[1] = "copy";
  subargv[2] = NULL;
  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
  e = TEST_PEX_READ_OUTPUT (pex1);
  CHECK_LINE (e, "bar");
  TEST_PEX_GET_STATUS (pex1, 2, statuses);
  if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
      || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
    ERROR ("copy exit status failed");
  pex_free (pex1);
  if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
    ERROR ("temporary files exist");

  pex1 = TEST_PEX_INIT (PEX_SAVE_TEMPS, "temp");
  subargv[1] = "echo";
  subargv[2] = "quux";
  subargv[3] = NULL;
  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
  subargv[1] = "copy";
  subargv[2] = NULL;
  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
  e = TEST_PEX_READ_OUTPUT (pex1);
  CHECK_LINE (e, "quux");
  TEST_PEX_GET_STATUS (pex1, 2, statuses);
  if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
      || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
    ERROR ("copy temp exit status failed");
  e = fopen ("temp.x", "r");
  if (e == NULL)
    FATAL_ERROR ("fopen temp.x failed in copy temp", errno);
  CHECK_LINE (e, "quux");
  fclose (e);
  e = fopen ("temp.y", "r");
  if (e == NULL)
    FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
  CHECK_LINE (e, "quux");
  fclose (e);
  pex_free (pex1);
  remove ("temp.x");
  remove ("temp.y");

  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
  subargv[1] = "echoerr";
  subargv[2] = "one";
  subargv[3] = "two";
  subargv[4] = NULL;
  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", "temp2.x");
  subargv[1] = "write";
  subargv[2] = "temp2.y";
  subargv[3] = NULL;
  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
  TEST_PEX_GET_STATUS (pex1, 2, statuses);
  if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
      || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
    ERROR ("echoerr exit status failed");
  pex_free (pex1);
  if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
    ERROR ("temporary files exist");
  e = fopen ("temp2.x", "r");
  if (e == NULL)
    FATAL_ERROR ("fopen temp2.x failed in echoerr", errno);
  CHECK_LINE (e, "two");
  fclose (e);
  e = fopen ("temp2.y", "r");
  if (e == NULL)
    FATAL_ERROR ("fopen temp2.y failed in echoerr", errno);
  CHECK_LINE (e, "one");
  fclose (e);
  remove ("temp2.x");
  remove ("temp2.y");

  /* Test the old pexecute interface.  */
  {
    int pid1, pid2;
    char *errmsg_fmt;
    char *errmsg_arg;
    char errbuf1[1000];
    char errbuf2[1000];

    subargv[1] = "echo";
    subargv[2] = "oldpexecute";
    subargv[3] = NULL;
    pid1 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
		     &errmsg_fmt, &errmsg_arg, PEXECUTE_FIRST);
    if (pid1 < 0)
      {
	snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
	snprintf (errbuf2, sizeof errbuf2, "pexecute 1 failed: %s", errbuf1);
	FATAL_ERROR (errbuf2, 0);
      }

    subargv[1] = "write";
    subargv[2] = "temp.y";
    subargv[3] = NULL;
    pid2 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
		     &errmsg_fmt, &errmsg_arg, PEXECUTE_LAST);
    if (pid2 < 0)
      {
	snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
	snprintf (errbuf2, sizeof errbuf2, "pexecute 2 failed: %s", errbuf1);
	FATAL_ERROR (errbuf2, 0);
      }

    if (pwait (pid1, &status, 0) < 0)
      FATAL_ERROR ("write pwait 1 failed", errno);
    if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
      ERROR ("write exit status 1 failed");

    if (pwait (pid2, &status, 0) < 0)
      FATAL_ERROR ("write pwait 1 failed", errno);
    if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
      ERROR ("write exit status 2 failed");

    e = fopen ("temp.y", "r");
    if (e == NULL)
      FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
    CHECK_LINE (e, "oldpexecute");
    fclose (e);

    remove ("temp.y");
  }

  if (trace)
    fprintf (stderr, "Exiting with status %d\n", error_count);

  return error_count;
}