| /* APPLE LOCAL file driver driver */ | 
 | /* Darwin driver program that handles -arch commands and invokes | 
 |    appropriate compiler driver. | 
 |    Copyright (C) 2004, 2005 Free Software Foundation, Inc. | 
 |  | 
 | This file is part of GCC. | 
 |  | 
 | GCC is free software; you can redistribute it and/or modify it under | 
 | the terms of the GNU General Public License as published by the Free | 
 | Software Foundation; either version 2, or (at your option) any later | 
 | version. | 
 |  | 
 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | 
 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
 | FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
 | for more details. | 
 |  | 
 | You should have received a copy of the GNU General Public License | 
 | along with GCC; see the file COPYING.  If not, write to the Free | 
 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | 
 | 02111-1307, USA.  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <unistd.h> | 
 | #include <errno.h> | 
 | #include <mach-o/arch.h> | 
 | #include <limits.h> | 
 | #include <sys/types.h> | 
 | #include <sys/stat.h> | 
 | #include <sys/wait.h> | 
 | #include <regex.h> | 
 | #include "libiberty.h" | 
 | #include "filenames.h" | 
 | #include "stdbool.h" | 
 | /* Hack!. | 
 |    Pay the price for including darwin.h.  */ | 
 | typedef int tree; | 
 | #define GTY(x) /* nothing */ | 
 | /* Include darwin.h for SWITCH_TAKES_ARG and | 
 |    WORD_SWIATCH_TAKES_ARG. */ | 
 |  | 
 | #include "darwin.h" | 
 |  | 
 | /* Include gcc.h for DEFAULT_SWITCH_TAKES_ARG and | 
 |    DEFAULT_WORD_SWIATCH_TAKES_ARG. */ | 
 |  | 
 | #include "gcc.h" | 
 |  | 
 | /* This program name.  */ | 
 | const char *progname; | 
 |  | 
 | /* driver prefix.  */ | 
 | const char *driver_exec_prefix; | 
 |  | 
 | /* driver prefix length.  */ | 
 | int prefix_len; | 
 |  | 
 | /* current working directory.  */ | 
 | char *curr_dir; | 
 |  | 
 | /* Use if -o flag is absent.  */ | 
 | const char *final_output = "a.out"; | 
 |  | 
 | /* Variabless to track presence and/or absence of important command | 
 |    line options.  */ | 
 | int compile_only_request = 0; | 
 | int asm_output_request = 0; | 
 | int dash_capital_m_seen = 0; | 
 | int preprocessed_output_request = 0; | 
 | int ima_is_used = 0; | 
 | int dash_dynamiclib_seen = 0; | 
 | int verbose_flag = 0; | 
 | int save_temps_seen = 0; | 
 |  | 
 | /* Support at the max 10 arch. at a time. This is historical limit.  */ | 
 | #define MAX_ARCHES 10 | 
 |  | 
 | /* Name of user supplied architectures.  */ | 
 | const char *arches[MAX_ARCHES]; | 
 |  | 
 | /* -arch counter.  */ | 
 | static int num_arches; | 
 |  | 
 | /* Input filenames.  */ | 
 | struct input_filename | 
 | { | 
 |   const char *name; | 
 |   int index; | 
 |   struct input_filename *next; | 
 | }; | 
 | struct input_filename *in_files; | 
 | struct input_filename *last_infile; | 
 |  | 
 | static int num_infiles; | 
 |  | 
 | /* User specified output file name.  */ | 
 | const char *output_filename = NULL; | 
 |  | 
 | /* Output file names used for arch specific driver invocation. These | 
 |    are input file names for 'lipo'.  */ | 
 | const char **out_files; | 
 | static int num_outfiles; | 
 |  | 
 | /* Architecture names used by config.guess does not match the names | 
 |    used by NXGet... Use this hand coded mapping to connect them.  */ | 
 | struct arch_config_guess_map | 
 | { | 
 |   const char *arch_name; | 
 |   const char *config_string; | 
 | }; | 
 |  | 
 | struct arch_config_guess_map arch_config_map [] = | 
 | { | 
 |   {"i386", "i686"}, | 
 |   {"ppc", "powerpc"}, | 
 |   {"ppc64", "powerpc"}, | 
 |   /* APPLE LOCAL x86_64 support 2006-02-02 */ | 
 |   {"x86_64", "i686"}, | 
 |   {NULL, NULL} | 
 | }; | 
 |  | 
 | /* List of interpreted command line flags. Supply this to gcc driver.  */ | 
 | const char **new_argv; | 
 | int new_argc; | 
 |  | 
 | /* Argument list for 'lipo'.  */ | 
 | const char **lipo_argv; | 
 |  | 
 | /* Info about the sub process. Need one subprocess for each arch plus | 
 |    additional one for 'lipo'.  */ | 
 | struct command | 
 | { | 
 |   const char *prog; | 
 |   const char **argv; | 
 |   int pid; | 
 | } commands[MAX_ARCHES+1]; | 
 |  | 
 | /* total number of argc.  */ | 
 | static int total_argc; | 
 |  | 
 | static int greatest_status = 0; | 
 | static int signal_count = 0; | 
 |  | 
 | #ifndef SWITCH_TAKES_ARG | 
 | #define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR) | 
 | #endif | 
 |  | 
 | #ifndef WORD_SWITCH_TAKES_ARG | 
 | #define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR) | 
 | #endif | 
 |  | 
 |  | 
 | /* Local function prototypes.  */ | 
 | static const char * get_arch_name (const char *); | 
 | static char * get_driver_name (const char *); | 
 | static void delete_out_files (void); | 
 | static char * strip_path_and_suffix (const char *, const char *); | 
 | static void initialize (void); | 
 | static void final_cleanup (void); | 
 | static int do_wait (int, const char *); | 
 | static int do_lipo (int, const char *); | 
 | static int do_compile (const char **, int); | 
 | static int do_compile_separately (void); | 
 | static int do_lipo_separately (void); | 
 | static int add_arch_options (int, const char **, int); | 
 | static int remove_arch_options (const char**, int); | 
 | static void add_arch (const char *); | 
 | static const char *resolve_symlink (const char *, char *, int, int); | 
 | static const char *resolve_path_to_executable (const char *filename); | 
 | static int get_prog_name_len (const char *prog); | 
 |  | 
 | /* Find arch name for the given input string. If input name is NULL then local | 
 |    arch name is used.  */ | 
 |  | 
 | static const char * | 
 | get_arch_name (const char *name) | 
 | { | 
 |   const NXArchInfo * a_info; | 
 |   const NXArchInfo * all_info; | 
 |   cpu_type_t cputype; | 
 |   struct arch_config_guess_map *map; | 
 |   const char *aname; | 
 |  | 
 |   if (name) | 
 |     { | 
 |       /* Find config name based on arch name.  */ | 
 |       aname = NULL; | 
 |       map = arch_config_map; | 
 |       while (map->arch_name) | 
 | 	{ | 
 | 	  if (!strcmp (map->arch_name, name)) | 
 | 	    return name; | 
 | 	  else map++; | 
 | 	} | 
 |       a_info = NXGetArchInfoFromName (name); | 
 |     } | 
 |   else | 
 |     a_info = NXGetLocalArchInfo (); | 
 |  | 
 |   if (!a_info) | 
 |     fatal ("Invalid arch name : %s", name); | 
 |  | 
 |   all_info = NXGetAllArchInfos(); | 
 |  | 
 |   if (!all_info) | 
 |     fatal ("Unable to get architecture information"); | 
 |  | 
 |   /* Find first arch. that matches cputype.  */ | 
 |   cputype = a_info->cputype; | 
 |  | 
 |   while (all_info->name) | 
 |     { | 
 |       if (all_info->cputype == cputype) | 
 | 	break; | 
 |       else | 
 | 	all_info++; | 
 |     } | 
 |  | 
 |   return all_info->name; | 
 | } | 
 |  | 
 | /* Find driver name based on input arch name.  */ | 
 |  | 
 | static char * | 
 | get_driver_name (const char *arch_name) | 
 | { | 
 |   char *driver_name; | 
 |   const char *config_name; | 
 |   int len; | 
 |   int index; | 
 |   struct arch_config_guess_map *map; | 
 |  | 
 |   /* find config name based on arch name.  */ | 
 |   config_name = NULL; | 
 |   map = arch_config_map; | 
 |   while (map->arch_name) | 
 |     { | 
 |       if (!strcmp (map->arch_name, arch_name)) | 
 | 	{ | 
 | 	  config_name = map->config_string; | 
 | 	  break; | 
 | 	} | 
 |       else map++; | 
 |     } | 
 |  | 
 |   if (!config_name) | 
 |     fatal ("Unable to guess config name for arch %s", arch_name); | 
 |  | 
 |   len = strlen (config_name) + strlen (PDN) + prefix_len + 1; | 
 |   driver_name = (char *) malloc (sizeof (char) * len); | 
 |   driver_name[0] = '\0'; | 
 |  | 
 |   if (driver_exec_prefix) | 
 |     strcpy (driver_name, driver_exec_prefix); | 
 |   strcat (driver_name, config_name); | 
 |   strcat (driver_name, PDN); | 
 |  | 
 |   return driver_name; | 
 | } | 
 |  | 
 | /* Delete out_files.  */ | 
 |  | 
 | static void | 
 | delete_out_files (void) | 
 | { | 
 |   const char *temp; | 
 |   struct stat st; | 
 |   int i = 0; | 
 |  | 
 |   for (i = 0, temp = out_files[i]; | 
 |        temp && i < total_argc * MAX_ARCHES; | 
 |        temp = out_files[++i]) | 
 |     if (stat (temp, &st) >= 0 && S_ISREG (st.st_mode)) | 
 |       unlink (temp); | 
 |  | 
 | } | 
 |  | 
 | /* Put fatal error message on stderr and exit.  */ | 
 |  | 
 | void | 
 | fatal (const char *msgid, ...) | 
 | { | 
 |   va_list ap; | 
 |  | 
 |   va_start (ap, msgid); | 
 |  | 
 |   fprintf (stderr, "%s: ", progname); | 
 |   vfprintf (stderr, msgid, ap); | 
 |   va_end (ap); | 
 |   fprintf (stderr, "\n"); | 
 |   delete_out_files (); | 
 |   exit (1); | 
 | } | 
 |  | 
 | /* Print error message and exit.  */ | 
 |  | 
 | static void | 
 | pfatal_pexecute (const char *errmsg_fmt, const char *errmsg_arg) | 
 | { | 
 |   if (errmsg_arg) | 
 |     { | 
 |       int save_errno = errno; | 
 |  | 
 |       /* Space for trailing '\0' is in %s.  */ | 
 |       char *msg = (char *) malloc (strlen (errmsg_fmt) + strlen (errmsg_arg)); | 
 |       sprintf (msg, errmsg_fmt, errmsg_arg); | 
 |       errmsg_fmt = msg; | 
 |  | 
 |       errno = save_errno; | 
 |     } | 
 |  | 
 |   fprintf (stderr,"%s: %s: %s", progname, errmsg_fmt, xstrerror (errno)); | 
 |   delete_out_files (); | 
 |   exit (1); | 
 | } | 
 |  | 
 | #ifdef DEBUG | 
 | static void | 
 | debug_command_line (const char **debug_argv, int debug_argc) | 
 | { | 
 |   int i; | 
 |  | 
 |   fprintf (stderr,"%s: debug_command_line\n", progname); | 
 |   fprintf (stderr,"%s: arg count = %d\n", progname, debug_argc); | 
 |  | 
 |   for (i = 0; debug_argv[i]; i++) | 
 |     fprintf (stderr,"%s: arg [%d] %s\n", progname, i, debug_argv[i]); | 
 | } | 
 | #endif | 
 |  | 
 | /* Strip directory name from the input file name and replace file name | 
 |    suffix with new.  */ | 
 |  | 
 | static char * | 
 | strip_path_and_suffix (const char *full_name, const char *new_suffix) | 
 | { | 
 |   char *name; | 
 |   char *p; | 
 |  | 
 |   if (!full_name || !new_suffix) | 
 |     return NULL; | 
 |  | 
 |   /* Strip path name.  */ | 
 |   p = (char *)full_name + strlen (full_name); | 
 |   while (p != full_name && !IS_DIR_SEPARATOR (p[-1])) | 
 |     --p; | 
 |  | 
 |   /* Now 'p' is a file name with suffix.  */ | 
 |   name = (char *) malloc (strlen (p) + 1 + strlen (new_suffix)); | 
 |  | 
 |   strcpy (name, p); | 
 |  | 
 |   p = name + strlen (name); | 
 |   while (p != name && *p != '.') | 
 |     --p; | 
 |  | 
 |   /* If did not reach at the beginning of name then '.' is found. | 
 |      Replace '.' with NULL.  */ | 
 |   if (p != name) | 
 |     *p = '\0'; | 
 |  | 
 |   strcat (name, new_suffix); | 
 |   return name; | 
 | } | 
 |  | 
 | /* Initialization */ | 
 |  | 
 | static void | 
 | initialize (void) | 
 | { | 
 |  | 
 |   int i; | 
 |  | 
 |   /* Let's count, how many additional arguments driver driver will supply | 
 |      to compiler driver: | 
 |  | 
 |      Each "-arch" "<blah>" is replaced by approriate "-mcpu=<blah>". | 
 |      That leaves one additional arg space available. | 
 |  | 
 |      Note that only one -m* is supplied to each compiler driver. Which | 
 |      means, extra "-arch" "<blah>" are removed from the original command | 
 |      line. But lets not count how many additional slots are available. | 
 |  | 
 |      Driver driver may need to specify temp. output file name, say | 
 |      "-o" "foobar". That needs two extra argments. | 
 |  | 
 |      Sometimes linker wants one additional "-Wl,-arch_multiple". | 
 |  | 
 |      Sometimes linker wants to see "-final_output" "outputname". | 
 |  | 
 |      In the end, we may need five extra arguments, plus one extra | 
 |      space for the NULL terminator.  */ | 
 |  | 
 |   new_argv = (const char **) malloc ((total_argc + 6) * sizeof (const char *)); | 
 |   if (!new_argv) | 
 |     abort (); | 
 |  | 
 |   /* First slot, new_argv[0] is reserved for the driver name.  */ | 
 |   new_argc = 1; | 
 |  | 
 |   /* For each -arch, three arguments are needed. | 
 |      For example, "-arch" "ppc" "file".  Additional slots are for | 
 |      "lipo" "-create" "-o" "outputfilename" and the NULL. */ | 
 |   lipo_argv = (const char **) malloc ((total_argc * 3 + 5) * sizeof (const char *)); | 
 |   if (!lipo_argv) | 
 |     abort (); | 
 |  | 
 |   /* Need separate out_files for each arch, max is MAX_ARCHES. | 
 |      Need separate out_files for each input file.  */ | 
 |  | 
 |   out_files = (const char **) malloc ((total_argc * MAX_ARCHES) * sizeof (const char *)); | 
 |   if (!out_files) | 
 |     abort (); | 
 |  | 
 |   num_arches = 0; | 
 |   num_infiles = 0; | 
 |  | 
 |   in_files = NULL; | 
 |   last_infile = NULL; | 
 |  | 
 |   for (i = 0; i < (MAX_ARCHES + 1); i++) | 
 |     { | 
 |       commands[i].prog = NULL; | 
 |       commands[i].argv = NULL; | 
 |       commands[i].pid = 0; | 
 |     } | 
 | } | 
 |  | 
 | /* Cleanup.  */ | 
 |  | 
 | static void | 
 | final_cleanup (void) | 
 | { | 
 |   int i; | 
 |   struct input_filename *next; | 
 |   delete_out_files (); | 
 |   free (new_argv); | 
 |   free (lipo_argv); | 
 |   free (out_files); | 
 |  | 
 |   for (i = 0, next = in_files; | 
 |        i < num_infiles && next; | 
 |        i++) | 
 |     { | 
 |       next = in_files->next; | 
 |       free (in_files); | 
 |       in_files = next; | 
 |     } | 
 | } | 
 |  | 
 | /* Wait for the process pid and return appropriate code.  */ | 
 |  | 
 | static int | 
 | do_wait (int pid, const char *prog) | 
 | { | 
 |   int status = 0; | 
 |   int ret = 0; | 
 |  | 
 |   pid = pwait (pid, &status, 0); | 
 |  | 
 |   if (WIFSIGNALED (status)) | 
 |     { | 
 |       if (!signal_count && | 
 | 	  WEXITSTATUS (status) > greatest_status) | 
 | 	greatest_status = WEXITSTATUS (status); | 
 |       ret = -1; | 
 |     } | 
 |   else if (WIFEXITED (status) | 
 | 	   && WEXITSTATUS (status) >= 1) | 
 |     { | 
 |       if (WEXITSTATUS (status) > greatest_status) | 
 | 	greatest_status = WEXITSTATUS (status); | 
 |       signal_count++; | 
 |       ret = -1; | 
 |     } | 
 |   return ret; | 
 | } | 
 |  | 
 | /* Invoke 'lipo' and combine and all output files.  */ | 
 |  | 
 | static int | 
 | 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_LAST); | 
 |  | 
 |   if (pid == -1) | 
 |     pfatal_pexecute (errmsg_fmt, errmsg_arg); | 
 |  | 
 |   return do_wait (pid, lipo_argv[0]); | 
 | } | 
 |  | 
 | /* Invoke compiler for all architectures.  */ | 
 |  | 
 | static int | 
 | do_compile (const char **current_argv, int current_argc) | 
 | { | 
 |   char *errmsg_fmt, *errmsg_arg; | 
 |   int index = 0; | 
 |   int ret = 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_LAST); | 
 |  | 
 |       if (commands[index].pid == -1) | 
 | 	pfatal_pexecute (errmsg_fmt, errmsg_arg); | 
 |  | 
 |       /* 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++; | 
 |     } | 
 |  | 
 |   index = 0; | 
 |   while (index < num_arches) | 
 |     { | 
 |       ret = do_wait (commands[index].pid, commands[index].prog); | 
 |       fflush (stdout); | 
 |       index++; | 
 |     } | 
 |   return ret; | 
 | } | 
 |  | 
 | /* Invoke compiler for each input file separately. | 
 |    Construct command line for each invocation with one input file.  */ | 
 |  | 
 | static int | 
 | do_compile_separately (void) | 
 | { | 
 |   const char **new_new_argv; | 
 |   int i, new_new_argc; | 
 |   struct input_filename *current_ifn; | 
 |  | 
 |   if (num_infiles == 1 || ima_is_used) | 
 |     abort (); | 
 |  | 
 |   /* Total number of arguments in separate compiler invocation is : | 
 |      total number of original arguments - total no input files + one input | 
 |      file + "-o" + output file .  */ | 
 |   new_new_argv = (const char **) malloc ((new_argc - num_infiles + 4) * sizeof (const char *)); | 
 |   if (!new_new_argv) | 
 |     abort (); | 
 |  | 
 |   for (current_ifn = in_files; current_ifn && current_ifn->name; | 
 |        current_ifn = current_ifn->next) | 
 |     { | 
 |       struct input_filename *ifn = in_files; | 
 |       int go_back = 0; | 
 |       new_new_argc = 1; | 
 |  | 
 |       for (i = 1; i < new_argc; i++) | 
 | 	{ | 
 |  | 
 | 	  if (ifn && ifn->name && !strcmp (new_argv[i], ifn->name)) | 
 | 	    { | 
 | 	      /* This argument is one of the input file.  */ | 
 |  | 
 |  	      if (!strcmp (new_argv[i], current_ifn->name)) | 
 | 		{ | 
 | 		  /* If it is current input file name then add it in the new | 
 | 		     list.  */ | 
 | 		  new_new_argv[new_new_argc++] = new_argv[i]; | 
 | 		} | 
 | 	      /* This input file can  not appear in | 
 | 		 again on the command line so next time look for next input | 
 | 		 file.  */ | 
 | 	      ifn = ifn->next; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      /* This argument is not a input file name. Add it into new | 
 | 		 list.  */ | 
 | 	      new_new_argv[new_new_argc++] = new_argv[i]; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       /* OK now we have only one input file and all other arguments.  */ | 
 |       do_compile (new_new_argv, new_new_argc); | 
 |     } | 
 | } | 
 |  | 
 | /* Invoke 'lipo' on set of output files and create multile FAT binaries.  */ | 
 |  | 
 | static int | 
 | do_lipo_separately (void) | 
 | { | 
 |   int ifn_index; | 
 |   struct input_filename *ifn; | 
 |   for (ifn_index = 0, ifn = in_files; | 
 |        ifn_index < num_infiles && ifn && ifn->name; | 
 |        ifn_index++, ifn = ifn->next) | 
 |     do_lipo (ifn_index * num_arches, | 
 | 	     strip_path_and_suffix (ifn->name, ".o")); | 
 | } | 
 |  | 
 | /* Replace -arch <blah> options with appropriate "-mcpu=<blah>" OR | 
 |    "-march=<blah>".  INDEX is the index in arches[] table. */ | 
 |  | 
 | static int | 
 | add_arch_options (int index, const char **current_argv, int arch_index) | 
 | { | 
 |  | 
 |   int count; | 
 |  | 
 |   /* We are adding 1 argument for selected arches.  */ | 
 |   count = 1; | 
 |  | 
 | #ifdef DEBUG | 
 |   fprintf (stderr, "%s: add_arch_options: %s\n", progname, arches[index]); | 
 | #endif | 
 |  | 
 |   if (!strcmp (arches[index], "ppc601")) | 
 |     current_argv[arch_index] = "-mcpu=601"; | 
 |   else if (!strcmp (arches[index], "ppc603")) | 
 |     current_argv[arch_index] = "-mcpu=603"; | 
 |   else if (!strcmp (arches[index], "ppc604")) | 
 |     current_argv[arch_index] = "-mcpu=604"; | 
 |   else if (!strcmp (arches[index], "ppc604e")) | 
 |     current_argv[arch_index] = "-mcpu=604e"; | 
 |   else if (!strcmp (arches[index], "ppc750")) | 
 |     current_argv[arch_index] = "-mcpu=750"; | 
 |   else if (!strcmp (arches[index], "ppc7400")) | 
 |     current_argv[arch_index] = "-mcpu=7400"; | 
 |   else if (!strcmp (arches[index], "ppc7450")) | 
 |     current_argv[arch_index] = "-mcpu=7450"; | 
 |   else if (!strcmp (arches[index], "ppc970")) | 
 |     current_argv[arch_index] = "-mcpu=970"; | 
 |   else if (!strcmp (arches[index], "ppc64")) | 
 |     current_argv[arch_index] = "-m64"; | 
 |   else if (!strcmp (arches[index], "i486")) | 
 |     current_argv[arch_index] = "-march=i486"; | 
 |   else if (!strcmp (arches[index], "i586")) | 
 |     current_argv[arch_index] = "-march=i586"; | 
 |   else if (!strcmp (arches[index], "i686")) | 
 |     current_argv[arch_index] = "-march=i686"; | 
 |   else if (!strcmp (arches[index], "pentium")) | 
 |     current_argv[arch_index] = "-march=pentium"; | 
 |   else if (!strcmp (arches[index], "pentium2")) | 
 |     current_argv[arch_index] = "-march=pentium2"; | 
 |   else if (!strcmp (arches[index], "pentpro")) | 
 |     current_argv[arch_index] = "-march=pentiumpro"; | 
 |   else if (!strcmp (arches[index], "pentIIm3")) | 
 |     current_argv[arch_index] = "-march=pentium2"; | 
 |   /* APPLE LOCAL begin x86_64 support 2006-02-02 */ | 
 |   else if (!strcmp (arches[index], "x86_64")) | 
 |     current_argv[arch_index] = "-m64"; | 
 |   /* APPLE LOCAL end x86_64 support 2006-02-02 */ | 
 |   else | 
 |     count = 0; | 
 |  | 
 |   return count; | 
 | } | 
 |  | 
 | /* Remove the last option, which is arch option, added by | 
 |    add_arch_options.  Return how count of arguments removed.  */ | 
 | static int | 
 | remove_arch_options (const char **current_argv, int arch_index) | 
 | { | 
 | #ifdef DEBUG | 
 |   fprintf (stderr, "%s: Removing argument no %d\n", progname, arch_index); | 
 | #endif | 
 |  | 
 |   current_argv[arch_index] = '\0'; | 
 |  | 
 | #ifdef DEBUG | 
 |       debug_command_line (current_argv, arch_index); | 
 | #endif | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Add new arch request.  */ | 
 | void | 
 | add_arch (const char *new_arch) | 
 | { | 
 |   int i; | 
 |  | 
 |   /* User can say cc -arch ppc -arch ppc foo.c | 
 |      Do not invoke ppc compiler twice in this case.  */ | 
 |   for (i = 0; i < num_arches; i++) | 
 |     { | 
 |       if (!strcmp (arches[i], new_arch)) | 
 | 	return; | 
 |     } | 
 |  | 
 |   arches[num_arches] = new_arch; | 
 |   num_arches++; | 
 | } | 
 |  | 
 | /* Rewrite the command line as requested in the QA_OVERRIDE_GCC3_OPTIONS | 
 |    environment variable -- used for testing the compiler, working around bugs | 
 |    in the Apple build environment, etc. | 
 |  | 
 |    The override string is made up of a set of space-separated clauses.  The | 
 |    first letter of each clause describes what's to be done: | 
 |    +string       Add string as a new argument (at the end of the command line). | 
 |                  Multi-word command lines can be added with +x +y | 
 |    s/x/y/        substitute x for y in the command line. X must be an entire | 
 |                  argument, and can be a regular expression as accepted by the | 
 |                  POSIX regexp code.  Y will be substituted as a single argument, | 
 |                  and will not have regexp replacements added in. | 
 |    xoption       Removes argument matching option | 
 |    Xoption       Removes argument matching option and following word | 
 |    Ox            Removes any optimization flags in command line and replaces | 
 |                  with -Ox. | 
 |  | 
 |  | 
 |    Here's some examples: | 
 |      O2 | 
 |      s/precomp-trustfile=foo// | 
 |      +-fexplore-antartica | 
 |      +-fast | 
 |      s/-fsetvalue=* // | 
 |      x-fwritable-strings | 
 |      s/-O[0-2]/-Osize/ | 
 |      x-v | 
 |      X-o +-o +foo.o | 
 |  | 
 |    Option substitutions are processed from left to right; matches and changes | 
 |    are cumulative.  An error in processing one element (such as trying to | 
 |    remove an element and successor when the match is at the end) cause the | 
 |    particular change to stop, but additional changes in the environment | 
 |    variable to be applied. | 
 |  | 
 |    Key details: | 
 |    * we always want to be able to adjust optimization levels for testing | 
 |    * adding options is a common task | 
 |    * substitution and deletion are less common. | 
 |  | 
 |    If the first character of the environment variable is #, changes are | 
 |    silent.  If not, diagnostics are written to stderr explaining what | 
 |    changes are being performed. | 
 |  | 
 | */ | 
 |  | 
 | char **arg_array; | 
 | int arg_array_size=0; | 
 | int arg_count = 0; | 
 | int confirm_changes = 1; | 
 | const int ARG_ARRAY_INCREMENT_SIZE = 8; | 
 | #define FALSE 0 | 
 |  | 
 | /* Routines for the argument array.  The argument array routines are | 
 |    responsible for allocation and deallocation of all objects in the | 
 |    array */ | 
 |  | 
 | void read_args (int argc, char **argv) | 
 | { | 
 |   int i; | 
 |  | 
 |   arg_array_size = argc+10; | 
 |   arg_count = argc; | 
 |   arg_array = (char**) malloc(sizeof(char*)*arg_array_size); | 
 |  | 
 |   for (i=0;i<argc;i++) { | 
 |     arg_array[i] = malloc (strlen (argv[i])+1); | 
 |     strcpy (arg_array[i], argv[i]); | 
 |   } | 
 | } | 
 |  | 
 | /* Insert the argument before pos. */ | 
 | void insert_arg(int pos, char *arg_to_insert) | 
 | { | 
 |   int i; | 
 |   char *newArg = malloc (strlen (arg_to_insert)+1); | 
 |   strcpy(newArg, arg_to_insert); | 
 |  | 
 |   if (arg_count == arg_array_size) { | 
 |     /* expand array */ | 
 |     arg_array_size = arg_count + ARG_ARRAY_INCREMENT_SIZE; | 
 |     arg_array = (char**) realloc (arg_array, arg_array_size); | 
 |   } | 
 |  | 
 |   for (i = arg_count; i > pos; i--) { | 
 |     arg_array[i+1] = arg_array[i]; | 
 |   } | 
 |  | 
 |   arg_array[pos] = newArg; | 
 |   arg_count++; | 
 |  | 
 |   if (confirm_changes) | 
 |     fprintf(stderr,"### Adding argument %s at position %d\n",arg_to_insert, pos); | 
 | } | 
 |  | 
 |  | 
 | void replace_arg (char *str, int pos) { | 
 |   char *newArg = malloc(strlen(str)+1); | 
 |   strcpy(newArg,str); | 
 |  | 
 |   if (confirm_changes) | 
 |     fprintf (stderr,"### Replacing %s with %s\n",arg_array[pos], str); | 
 |  | 
 |   free (arg_array[pos]); | 
 |   arg_array[pos] = newArg; | 
 | } | 
 |  | 
 | void append_arg (char *str) | 
 | { | 
 |   char *new_arg = malloc (strlen (str)+1); | 
 |   strcpy (new_arg, str); | 
 |   if (confirm_changes) | 
 |     fprintf(stderr,"### Adding argument %s at end\n", str); | 
 |  | 
 |   if (arg_count == arg_array_size) { | 
 |     /* expand array */ | 
 |     arg_array_size = arg_count + ARG_ARRAY_INCREMENT_SIZE; | 
 |     arg_array = (char**) realloc (arg_array, arg_array_size); | 
 |   } | 
 |  | 
 |   arg_array[arg_count++] = new_arg; | 
 | } | 
 |  | 
 | void delete_arg(int pos) { | 
 |   int i; | 
 |  | 
 |   if (confirm_changes) | 
 |     fprintf(stderr,"### Deleting argument %s\n",arg_array[pos]); | 
 |  | 
 |   free (arg_array[pos]); | 
 |  | 
 |   for (i=pos; i < arg_count; i++) | 
 |     arg_array[i] = arg_array[i+1]; | 
 |  | 
 |   arg_count--; | 
 | } | 
 |  | 
 | /* Changing optimization levels is a common testing pattern -- | 
 |    we've got a special option that searches for and replaces anything | 
 |    beginning with -O */ | 
 | void replace_optimization_level (char *new_level) { | 
 |   int i; | 
 |   int optionFound = 0; | 
 |   char *new_opt = malloc(strlen(new_opt)+3); | 
 |   sprintf(new_opt, "-O%s",new_level); | 
 |  | 
 |  | 
 |   for (i=0;i<arg_count;i++) { | 
 |     if (strncmp(arg_array[i],"-O",2) == 0) { | 
 |       replace_arg (new_opt, i); | 
 |       optionFound = 1; | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   if (optionFound == 0) | 
 |     /* No optimization level?  Add it! */ | 
 |     append_arg (new_opt); | 
 |  | 
 |   free (new_opt); | 
 | } | 
 |  | 
 | /* Returns a NULL terminated string holding whatever was in the original | 
 |    string at that point.  This must be freed by the caller. */ | 
 |  | 
 | char *arg_string(char *str, int begin, int len) { | 
 |   char *new_str = malloc(len+1); | 
 |   strncpy(new_str,&str[begin],len); | 
 |   new_str[len] = '\0'; | 
 |   return new_str; | 
 | } | 
 |  | 
 | /* Given a search-and-replace string of the form | 
 |    s/x/y/ | 
 |  | 
 |    do search and replace on the arg list.  Make sure to check that the | 
 |    string is sane -- that it has all the proper slashes that are necessary. | 
 |    The search string can be a regular expression, but the replace string | 
 |    must be a literal; the search must also be for a full argument, not for | 
 |    a chain of arguments.  The result will be treated as a single argument. | 
 |  | 
 |    Return true if success, false if bad failure. | 
 | */ | 
 |  | 
 | bool search_and_replace (char *str) { | 
 |   regex_t regexp_search_struct; | 
 |   int searchLen; | 
 |   int replaceLen; | 
 |   int i; | 
 |   int err; | 
 |  | 
 |   char *searchStr; | 
 |   char *replaceStr; | 
 |   char *replacedStr; | 
 |   const int  ERRSIZ = 512; | 
 |   char errbuf[ERRSIZ]; | 
 |  | 
 |  | 
 |   if (str[0] != '/') { | 
 |     return false; | 
 |   } | 
 |  | 
 |   searchLen = strcspn (str + 1, "/\0"); | 
 |  | 
 |   if (str[1 + searchLen] != '/') | 
 |     return false; | 
 |  | 
 |   replaceLen = strcspn(str+1+searchLen+1, "/\0"); | 
 |  | 
 |   if (str[1 + searchLen + 1 +replaceLen] != '/') | 
 |     return false; | 
 |  | 
 |   searchStr = arg_string(str, 1, searchLen); | 
 |   replaceStr = arg_string (str, 1 + searchLen + 1, replaceLen); | 
 |  | 
 |   if ((err = regcomp(®exp_search_struct, searchStr, REG_EXTENDED)) != 0) { | 
 |     regerror(err, ®exp_search_struct, errbuf, ERRSIZ); | 
 |     fprintf(stderr,"%s",errbuf); | 
 |     return false; | 
 |   } | 
 |  | 
 |   for (i=0;i<arg_count;i++) { | 
 |     regmatch_t matches[5]; | 
 |     if (regexec (®exp_search_struct, arg_array[i], | 
 | 		 5, matches, 0) == 0) { | 
 |       if ((matches[0].rm_eo - matches[0].rm_so) == strlen (arg_array[i])) { | 
 | 	/* Success! Change the string. */ | 
 | 	replace_arg(replaceStr,i); | 
 | 	break; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   regfree (®exp_search_struct); | 
 |   free (searchStr); | 
 |   free (replaceStr); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 |  | 
 | /* Given a string, return the argument number where the first match occurs. */ | 
 | int find_arg (char *str) { | 
 |   int i; | 
 |   int matchIndex = -1; | 
 |  | 
 |   for (i=0;i<arg_count;i++) { | 
 |     if (strcmp(arg_array[i],str) == 0) { | 
 |       matchIndex = i; | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   return matchIndex; | 
 | } | 
 |  | 
 | void rewrite_command_line (char *override_options_line, int *argc, char ***argv){ | 
 |   int line_pos = 0; | 
 |  | 
 |   read_args (*argc, *argv); | 
 |  | 
 |   if (override_options_line[0] == '#') | 
 |     { | 
 |       confirm_changes = 0; | 
 |       line_pos++; | 
 |     } | 
 |  | 
 |  | 
 |   if (confirm_changes) | 
 |     fprintf (stderr, "### QA_OVERRIDE_GCC3_OPTIONS: %s\n", | 
 | 	     override_options_line); | 
 |  | 
 |   /* Loop through all commands in the file */ | 
 |  | 
 |   while (override_options_line[line_pos] != '\0') | 
 |     { | 
 |       char first_char; | 
 |       char *searchStr; | 
 |       char *arg; | 
 |       int search_index; | 
 |       int arg_len; | 
 |  | 
 |       /* Any spaces in between options don't count. */ | 
 |       if (override_options_line[line_pos] == ' ') | 
 | 	{ | 
 | 	  line_pos++; | 
 | 	  continue; | 
 | 	} | 
 |  | 
 |       /* The first non-space character is the command. */ | 
 |       first_char = override_options_line[line_pos]; | 
 |       line_pos++; | 
 |       arg_len = strcspn(override_options_line+line_pos, " "); | 
 |  | 
 |       switch (first_char) { | 
 |       case '+': | 
 | 	/* Add an argument to the end of the arg list */ | 
 | 	arg = arg_string (override_options_line, | 
 | 			  line_pos, | 
 | 			  arg_len); | 
 | 	append_arg (arg); | 
 | 	free (arg); | 
 | 	break; | 
 |  | 
 |       case 'x': | 
 | 	/* Delete a matching argument */ | 
 | 	searchStr = arg_string(override_options_line, line_pos, arg_len); | 
 | 	if ((search_index = find_arg(searchStr)) != -1) { | 
 | 	  delete_arg(search_index); | 
 | 	} | 
 | 	free (searchStr); | 
 | 	break; | 
 |  | 
 |       case 'X': | 
 | 	/* Delete a matching argument and the argument following. */ | 
 | 	searchStr = arg_string(override_options_line, line_pos, arg_len); | 
 | 	if ((search_index = find_arg(searchStr)) != -1) { | 
 | 	  if (search_index >= arg_count -1) { | 
 | 	    if (confirm_changes) | 
 | 	      fprintf(stderr,"Not enough arguments to do X\n"); | 
 | 	  } else { | 
 | 	    delete_arg(search_index); /* Delete the matching argument */ | 
 | 	    delete_arg(search_index); /* Delete the following argument */ | 
 | 	  } | 
 | 	} | 
 | 	free (searchStr); | 
 | 	break; | 
 |  | 
 |       case 'O': | 
 | 	/* Change the optimization level to the specified value, and | 
 | 	   remove any optimization arguments.   This is a separate command | 
 | 	   because we often want is to substitute our favorite | 
 | 	   optimization level for whatever the project normally wants. | 
 | 	   As we probably care about this a lot (for things like | 
 | 	   testing file sizes at different optimization levels) we | 
 | 	   make a special rewrite clause. */ | 
 | 	arg = arg_string (override_options_line, line_pos, arg_len); | 
 | 	replace_optimization_level(arg); | 
 | 	free (arg); | 
 | 	break; | 
 |       case 's': | 
 | 	/* Search for the regexp passed in, and replace a matching argument | 
 | 	   with the provided replacement string */ | 
 | 	searchStr = arg_string (override_options_line, line_pos, arg_len); | 
 | 	search_and_replace (searchStr); | 
 | 	free (searchStr); | 
 | 	break; | 
 |  | 
 |       default: | 
 | 	fprintf(stderr,"### QA_OVERRIDE_GCC3_OPTIONS: invalid string (pos %d)\n", | 
 | 		line_pos); | 
 | 	break; | 
 |       } | 
 |       line_pos += arg_len; | 
 |     } | 
 |   *argc = arg_count; | 
 |   *argv = arg_array; | 
 | } | 
 |  | 
 | /* Given a path to a file, potentially containing a directory name, return the | 
 |    number of characters at the end of the path that make up the filename part of | 
 |    the path. */ | 
 |  | 
 | static int | 
 | get_prog_name_len (const char *prog) | 
 | { | 
 |   int result = 0; | 
 |   const char *progend = prog + strlen(prog); | 
 |   const char *progname = progend; | 
 |   while (progname != prog && !IS_DIR_SEPARATOR (progname[-1])) | 
 |     --progname; | 
 |   return progend-progname; | 
 | } | 
 |  | 
 | /* Return true iff the path is an executable file and not a directory.  */ | 
 |  | 
 | static bool | 
 | is_x_file (const char *path) | 
 | { | 
 |   struct stat st; | 
 |   if (access (path, X_OK)) | 
 |     return false; | 
 |   if (stat (path, &st) == -1) | 
 |     return false; | 
 |   if (S_ISDIR (st.st_mode)) | 
 |     return false; | 
 |   return true; | 
 | } | 
 |  | 
 | /* Given a FILENAME of an executable (for example "gcc") search the PATH | 
 |    environment variable to find out which directory it is in and return a fully | 
 |    qualified path to the executable. | 
 |  */ | 
 |  | 
 | static const char * | 
 | resolve_path_to_executable (const char *filename) | 
 | { | 
 |   char path_buffer[2*PATH_MAX+1]; | 
 |   char *PATH = getenv ("PATH"); | 
 |   if (PATH == 0) return filename;  /* PATH not set */ | 
 |  | 
 |   do { | 
 |     unsigned prefix_size; | 
 |     struct stat st; | 
 |     char *colon = strchr (PATH, ':'); | 
 |  | 
 |     /* If we didn't find a :, use the whole last chunk. */ | 
 |     prefix_size = colon ? colon-PATH : strlen (PATH); | 
 |  | 
 |     /* Form the full path. */ | 
 |     memcpy (path_buffer, PATH, prefix_size); | 
 |     path_buffer[prefix_size] = '/'; | 
 |     strcpy (path_buffer+prefix_size+1, filename); | 
 |  | 
 |     /* Check to see if this file is executable, if so, return it. */ | 
 |     if (is_x_file (path_buffer)) | 
 |       return strdup (path_buffer); | 
 |     PATH = colon ? colon+1 : PATH+prefix_size; | 
 |   } while (PATH[0]); | 
 |  | 
 |   return filename; | 
 | } | 
 |  | 
 | /* If prog is a symlink, we want to rewrite prog to an absolute location, | 
 |    symlink_buffer contains the destination of the symlink.  Glue these pieces | 
 |    together to form an absolute path. */ | 
 |  | 
 | static const char * | 
 | resolve_symlink (const char *prog, char *symlink_buffer, | 
 | 		 int argv_0_len, int prog_len) | 
 | { | 
 |   /* If the link isn't to an absolute path, prefix it with the argv[0] | 
 |     directory. */ | 
 |   if (!IS_ABSOLUTE_PATH (symlink_buffer)) | 
 |   { | 
 |     int prefix_len = argv_0_len - prog_len; | 
 |     memmove (symlink_buffer+prefix_len, symlink_buffer, | 
 |              PATH_MAX-prefix_len+1); | 
 |     memcpy (symlink_buffer, prog, prefix_len); | 
 |   } | 
 |   return strdup(symlink_buffer); | 
 | } | 
 |  | 
 | /* 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, ret, argv_0_len, prog_len; | 
 |   char *errmsg_fmt, *errmsg_arg; | 
 |   char *override_option_str = NULL; | 
 |   char path_buffer[2*PATH_MAX+1]; | 
 |   int linklen; | 
 |   int delete_prefix = 0; | 
 |  | 
 |   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'; | 
 |   /* LLVM LOCAL begin - These drivers live in /.../usr/llvm-gcc-4.0/bin */ | 
 |   { | 
 |     size_t curr_dir_len = strlen (curr_dir); | 
 |     const char *llvm_bin_dir = "/usr/llvm-gcc-4.0/bin/"; | 
 |     size_t bin_dir_len = strlen (llvm_bin_dir); | 
 |  | 
 |     if (curr_dir_len <= bin_dir_len || | 
 |         strncmp (&curr_dir[curr_dir_len - bin_dir_len], llvm_bin_dir, bin_dir_len) != 0) { | 
 |       driver_exec_prefix = | 
 |         make_relative_prefix (argv[0], curr_dir, "/usr/llvm-gcc-4.0/bin/"); | 
 |       delete_prefix = 1; | 
 |       prefix_len = strlen (driver_exec_prefix); | 
 |     } else | 
 |       driver_exec_prefix = curr_dir; | 
 |   } | 
 |   /* LLVM LOCAL end - These drivers live in /.../usr/llvm-gcc-4.0/bin */ | 
 |  | 
 | #ifdef DEBUG | 
 |   fprintf (stderr,"%s: full progname = %s\n", progname, argv[0]); | 
 |   fprintf (stderr,"%s: progname = %s\n", progname, progname); | 
 |   fprintf (stderr,"%s: curr_dir = %s\n", progname, curr_dir); | 
 |   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], "-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) | 
 | 	    abort (); | 
 |  | 
 | 	  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 (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 > 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 == 0 || num_arches == 1) | 
 |     { | 
 |  | 
 |       /* If no -arch is specified than use host compiler driver.  */ | 
 |       if (num_arches == 0) | 
 | 	new_argv[0] = get_driver_name (get_arch_name (NULL)); | 
 |       else if (num_arches == 1) | 
 | 	{ | 
 | 	  /* 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; | 
 |  | 
 | #ifdef DEBUG | 
 |       debug_command_line (new_argv, new_argc); | 
 | #endif | 
 |  | 
 |       pid = pexecute (new_argv[0], (char *const *)new_argv, progname, NULL, | 
 | 		      &errmsg_fmt, &errmsg_arg, PEXECUTE_SEARCH | PEXECUTE_LAST); | 
 |  | 
 |       if (pid == -1) | 
 | 	pfatal_pexecute (errmsg_fmt, errmsg_arg); | 
 |  | 
 |       ret = do_wait (pid, new_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.  */ | 
 | 	  ret = do_compile (new_argv, new_argc); | 
 |  | 
 | 	  /* Make FAT binary by combining individual output files for each | 
 | 	     architecture, using 'lipo'.  */ | 
 | 	  ret = do_lipo (0, out_file); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Multiple input files are present and IMA is not used. | 
 | 	     Which means need to generate multiple FAT files.  */ | 
 | 	  ret = do_compile_separately (); | 
 | 	  ret = do_lipo_separately (); | 
 | 	} | 
 |     } | 
 |  | 
 |   final_cleanup (); | 
 |   free (curr_dir); | 
 |   if (delete_prefix) | 
 |     free (driver_exec_prefix); | 
 |   return greatest_status; | 
 | } |