aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/driverdriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/driverdriver.c')
-rw-r--r--gcc-4.2.1-5666.3/driverdriver.c1654
1 files changed, 1654 insertions, 0 deletions
diff --git a/gcc-4.2.1-5666.3/driverdriver.c b/gcc-4.2.1-5666.3/driverdriver.c
new file mode 100644
index 000000000..eacc1dc36
--- /dev/null
+++ b/gcc-4.2.1-5666.3/driverdriver.c
@@ -0,0 +1,1654 @@
+/* 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;
+typedef int rtx;
+#define GTY(x) /* nothing */
+#define USED_FOR_TARGET 1
+/* 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;
+int dash_m32_seen = 0;
+int dash_m64_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"},
+ {"x86_64", "i686"},
+ /* Note: It's required that all supported ARM architectures be listed
+ * here explicitly */
+ {"arm", "arm"},
+ {"armv4t", "arm"},
+ {"armv5", "arm"},
+ {"xscale", "arm"},
+ {"armv6", "arm"},
+ {"armv7", "arm"},
+ {NULL, NULL}
+};
+
+/* List of interpreted command line flags. Supply this to gcc driver. */
+const char **new_argv;
+int new_argc;
+
+/* For each of the options in new_argv, specifies an architecture to
+ which the option applies (or if NULL, the option applies to all). */
+const char **arch_conditional;
+
+/* 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 void do_lipo (int, const char *);
+static void do_compile (const char **, int);
+static void do_compile_separately (void);
+static void do_lipo_separately (void);
+static int filter_args_for_arch (const char **, int, const char **,
+ const char *);
+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)
+{
+ 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 = (NXArchInfo *) NXGetArchInfoFromName (name);
+ /* radr://7148788 emit diagnostic for ARM architectures not explicitly
+ * handled by the driver. */
+ if (a_info && a_info->cputype == CPU_TYPE_ARM)
+ a_info = NULL;
+ } else {
+ a_info = (NXArchInfo *) NXGetLocalArchInfo();
+ if (a_info) {
+ if (dash_m32_seen) {
+ /* If -m32 is seen then do not change cpu type. */
+ } else if (dash_m64_seen) {
+ /* If -m64 is seen then enable CPU_ARCH_ABI64. */
+ a_info->cputype |= CPU_ARCH_ABI64;
+ } else if (sizeof (long) == 8)
+ /* On x86, by default (name is NULL here) enable 64 bit code. */
+ a_info->cputype |= CPU_ARCH_ABI64;
+ }
+ }
+
+ 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\n", 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 ();
+
+ arch_conditional = (const char **) malloc ((total_argc + 6) * sizeof (const char *));
+ if (!arch_conditional)
+ abort ();
+
+ for (i = 0; i < total_argc + 6; i++)
+ arch_conditional[i] = NULL;
+
+ /* 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 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]);
+}
+
+/* Invoke compiler for all architectures. */
+
+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;
+
+ const char **arch_specific_argv;
+
+ int arch_specific_argc;
+
+ 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;
+
+ current_argv[argc_count] = NULL;
+
+ arch_specific_argv =
+ (const char **) malloc ((argc_count + 1) * sizeof (const char *));
+
+ arch_specific_argc = filter_args_for_arch (current_argv,
+ argc_count,
+ arch_specific_argv,
+ get_arch_name (arches[index]));
+
+ commands[index].prog = arch_specific_argv[0];
+ commands[index].argv = arch_specific_argv;
+
+#ifdef DEBUG
+ debug_command_line (arch_specific_argv, arch_specific_argc);
+#endif
+ commands[index].pid = pexecute (arch_specific_argv[0],
+ (char *const *)arch_specific_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++;
+ free (arch_specific_argv);
+ }
+}
+
+/* Invoke compiler for each input file separately.
+ Construct command line for each invocation with one input file. */
+
+static void
+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 + arch specific options + NULL . */
+ new_new_argv = (const char **) malloc ((new_argc - num_infiles + 5) * 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;
+ bool ifn_found = false;
+
+ 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 (ifn_found)
+ fatal ("file %s specified more than once on the command line", 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];
+ arch_conditional[new_new_argc] = arch_conditional[i];
+ new_new_argc++;
+ ifn_found = true;
+ }
+ /* 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];
+ arch_conditional[new_new_argc] = arch_conditional[i];
+ new_new_argc++;
+ }
+ }
+
+ /* 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 void
+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"));
+}
+
+/* Remove all options which are architecture-specific and are not for the
+ current architecture (arch). */
+static int
+filter_args_for_arch (const char **orig_argv, int orig_argc,
+ const char **new_argv, const char *arch)
+{
+ int new_argc = 0;
+ int i;
+
+ for (i = 0; i < orig_argc; i++)
+ if (arch_conditional[i] == NULL
+ || *arch_conditional[i] == '\0'
+ || ! strcmp (arch_conditional[i], arch))
+ new_argv[new_argc++] = orig_argv[i];
+
+ new_argv[new_argc] = NULL;
+
+ return new_argc;
+}
+
+/* Replace -arch <blah> options with appropriate "-mcpu=<blah>" OR
+ "-march=<blah>". INDEX is the index in arches[] table. We cannot
+ return more than 1 as do_compile_separately only allocated one
+ extra slot for us. */
+
+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";
+ else if (!strcmp (arches[index], "x86_64"))
+ current_argv[arch_index] = "-m64";
+ else if (!strcmp (arches[index], "arm"))
+ current_argv[arch_index] = "-march=armv4t";
+ else if (!strcmp (arches[index], "armv4t"))
+ current_argv[arch_index] = "-march=armv4t";
+ else if (!strcmp (arches[index], "armv5"))
+ current_argv[arch_index] = "-march=armv5tej";
+ else if (!strcmp (arches[index], "xscale"))
+ current_argv[arch_index] = "-march=xscale";
+ else if (!strcmp (arches[index], "armv6"))
+ current_argv[arch_index] = "-march=armv6k";
+ else if (!strcmp (arches[index], "armv7"))
+ current_argv[arch_index] = "-march=armv7a";
+ 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(&regexp_search_struct, searchStr, REG_EXTENDED)) != 0) {
+ regerror(err, &regexp_search_struct, errbuf, ERRSIZ);
+ fprintf(stderr,"%s",errbuf);
+ return false;
+ }
+
+ for (i=0;i<arg_count;i++) {
+ regmatch_t matches[5];
+ if (regexec (&regexp_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 (&regexp_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, 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;
+}