xref: /dragonfly/contrib/gcc-8.0/gcc/gcc.c (revision df642abc)
138fd1498Szrj /* Compiler driver program that can handle many languages.
238fd1498Szrj    Copyright (C) 1987-2018 Free Software Foundation, Inc.
338fd1498Szrj 
438fd1498Szrj This file is part of GCC.
538fd1498Szrj 
638fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
738fd1498Szrj the terms of the GNU General Public License as published by the Free
838fd1498Szrj Software Foundation; either version 3, or (at your option) any later
938fd1498Szrj version.
1038fd1498Szrj 
1138fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1238fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1338fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1438fd1498Szrj for more details.
1538fd1498Szrj 
1638fd1498Szrj You should have received a copy of the GNU General Public License
1738fd1498Szrj along with GCC; see the file COPYING3.  If not see
1838fd1498Szrj <http://www.gnu.org/licenses/>.  */
1938fd1498Szrj 
2038fd1498Szrj /* This program is the user interface to the C compiler and possibly to
2138fd1498Szrj other compilers.  It is used because compilation is a complicated procedure
2238fd1498Szrj which involves running several programs and passing temporary files between
2338fd1498Szrj them, forwarding the users switches to those programs selectively,
2438fd1498Szrj and deleting the temporary files at the end.
2538fd1498Szrj 
2638fd1498Szrj CC recognizes how to compile each input file by suffixes in the file names.
2738fd1498Szrj Once it knows which kind of compilation to perform, the procedure for
2838fd1498Szrj compilation is specified by a string called a "spec".  */
2938fd1498Szrj 
3038fd1498Szrj #include "config.h"
3138fd1498Szrj #include "system.h"
3238fd1498Szrj #include "coretypes.h"
3338fd1498Szrj #include "multilib.h" /* before tm.h */
3438fd1498Szrj #include "tm.h"
3538fd1498Szrj #include "xregex.h"
3638fd1498Szrj #include "obstack.h"
3738fd1498Szrj #include "intl.h"
3838fd1498Szrj #include "prefix.h"
3938fd1498Szrj #include "gcc.h"
4038fd1498Szrj #include "diagnostic.h"
4138fd1498Szrj #include "flags.h"
4238fd1498Szrj #include "opts.h"
4338fd1498Szrj #include "params.h"
4438fd1498Szrj #include "filenames.h"
4538fd1498Szrj #include "spellcheck.h"
4638fd1498Szrj 
4738fd1498Szrj 
4838fd1498Szrj 
4938fd1498Szrj /* Manage the manipulation of env vars.
5038fd1498Szrj 
5138fd1498Szrj    We poison "getenv" and "putenv", so that all enviroment-handling is
5238fd1498Szrj    done through this class.  Note that poisoning happens in the
5338fd1498Szrj    preprocessor at the identifier level, and doesn't distinguish between
5438fd1498Szrj      env.getenv ();
5538fd1498Szrj    and
5638fd1498Szrj      getenv ();
5738fd1498Szrj    Hence we need to use "get" for the accessor method, not "getenv".  */
5838fd1498Szrj 
5938fd1498Szrj class env_manager
6038fd1498Szrj {
6138fd1498Szrj  public:
6238fd1498Szrj   void init (bool can_restore, bool debug);
6338fd1498Szrj   const char *get (const char *name);
6438fd1498Szrj   void xput (const char *string);
6538fd1498Szrj   void restore ();
6638fd1498Szrj 
6738fd1498Szrj  private:
6838fd1498Szrj   bool m_can_restore;
6938fd1498Szrj   bool m_debug;
7038fd1498Szrj   struct kv
7138fd1498Szrj   {
7238fd1498Szrj     char *m_key;
7338fd1498Szrj     char *m_value;
7438fd1498Szrj   };
7538fd1498Szrj   vec<kv> m_keys;
7638fd1498Szrj 
7738fd1498Szrj };
7838fd1498Szrj 
7938fd1498Szrj /* The singleton instance of class env_manager.  */
8038fd1498Szrj 
8138fd1498Szrj static env_manager env;
8238fd1498Szrj 
8338fd1498Szrj /* Initializer for class env_manager.
8438fd1498Szrj 
8538fd1498Szrj    We can't do this as a constructor since we have a statically
8638fd1498Szrj    allocated instance ("env" above).  */
8738fd1498Szrj 
8838fd1498Szrj void
init(bool can_restore,bool debug)8938fd1498Szrj env_manager::init (bool can_restore, bool debug)
9038fd1498Szrj {
9138fd1498Szrj   m_can_restore = can_restore;
9238fd1498Szrj   m_debug = debug;
9338fd1498Szrj }
9438fd1498Szrj 
9538fd1498Szrj /* Get the value of NAME within the environment.  Essentially
9638fd1498Szrj    a wrapper for ::getenv, but adding logging, and the possibility
9738fd1498Szrj    of caching results.  */
9838fd1498Szrj 
9938fd1498Szrj const char *
get(const char * name)10038fd1498Szrj env_manager::get (const char *name)
10138fd1498Szrj {
10238fd1498Szrj   const char *result = ::getenv (name);
10338fd1498Szrj   if (m_debug)
10438fd1498Szrj     fprintf (stderr, "env_manager::getenv (%s) -> %s\n", name, result);
10538fd1498Szrj   return result;
10638fd1498Szrj }
10738fd1498Szrj 
10838fd1498Szrj /* Put the given KEY=VALUE entry STRING into the environment.
10938fd1498Szrj    If the env_manager was initialized with CAN_RESTORE set, then
11038fd1498Szrj    also record the old value of KEY within the environment, so that it
11138fd1498Szrj    can be later restored.  */
11238fd1498Szrj 
11338fd1498Szrj void
xput(const char * string)11438fd1498Szrj env_manager::xput (const char *string)
11538fd1498Szrj {
11638fd1498Szrj   if (m_debug)
11738fd1498Szrj     fprintf (stderr, "env_manager::xput (%s)\n", string);
11838fd1498Szrj   if (verbose_flag)
11938fd1498Szrj     fnotice (stderr, "%s\n", string);
12038fd1498Szrj 
12138fd1498Szrj   if (m_can_restore)
12238fd1498Szrj     {
12338fd1498Szrj       char *equals = strchr (const_cast <char *> (string), '=');
12438fd1498Szrj       gcc_assert (equals);
12538fd1498Szrj 
12638fd1498Szrj       struct kv kv;
12738fd1498Szrj       kv.m_key = xstrndup (string, equals - string);
12838fd1498Szrj       const char *cur_value = ::getenv (kv.m_key);
12938fd1498Szrj       if (m_debug)
13038fd1498Szrj 	fprintf (stderr, "saving old value: %s\n",cur_value);
13138fd1498Szrj       kv.m_value = cur_value ? xstrdup (cur_value) : NULL;
13238fd1498Szrj       m_keys.safe_push (kv);
13338fd1498Szrj     }
13438fd1498Szrj 
13538fd1498Szrj   ::putenv (CONST_CAST (char *, string));
13638fd1498Szrj }
13738fd1498Szrj 
13838fd1498Szrj /* Undo any xputenv changes made since last restore.
13938fd1498Szrj    Can only be called if the env_manager was initialized with
14038fd1498Szrj    CAN_RESTORE enabled.  */
14138fd1498Szrj 
14238fd1498Szrj void
restore()14338fd1498Szrj env_manager::restore ()
14438fd1498Szrj {
14538fd1498Szrj   unsigned int i;
14638fd1498Szrj   struct kv *item;
14738fd1498Szrj 
14838fd1498Szrj   gcc_assert (m_can_restore);
14938fd1498Szrj 
15038fd1498Szrj   FOR_EACH_VEC_ELT_REVERSE (m_keys, i, item)
15138fd1498Szrj     {
15238fd1498Szrj       if (m_debug)
15338fd1498Szrj 	printf ("restoring saved key: %s value: %s\n", item->m_key, item->m_value);
15438fd1498Szrj       if (item->m_value)
15538fd1498Szrj 	::setenv (item->m_key, item->m_value, 1);
15638fd1498Szrj       else
15738fd1498Szrj 	::unsetenv (item->m_key);
15838fd1498Szrj       free (item->m_key);
15938fd1498Szrj       free (item->m_value);
16038fd1498Szrj     }
16138fd1498Szrj 
16238fd1498Szrj   m_keys.truncate (0);
16338fd1498Szrj }
16438fd1498Szrj 
16538fd1498Szrj /* Forbid other uses of getenv and putenv.  */
16638fd1498Szrj #if (GCC_VERSION >= 3000)
16738fd1498Szrj #pragma GCC poison getenv putenv
16838fd1498Szrj #endif
16938fd1498Szrj 
17038fd1498Szrj 
17138fd1498Szrj 
17238fd1498Szrj /* By default there is no special suffix for target executables.  */
17338fd1498Szrj #ifdef TARGET_EXECUTABLE_SUFFIX
17438fd1498Szrj #define HAVE_TARGET_EXECUTABLE_SUFFIX
17538fd1498Szrj #else
17638fd1498Szrj #define TARGET_EXECUTABLE_SUFFIX ""
17738fd1498Szrj #endif
17838fd1498Szrj 
17938fd1498Szrj /* By default there is no special suffix for host executables.  */
18038fd1498Szrj #ifdef HOST_EXECUTABLE_SUFFIX
18138fd1498Szrj #define HAVE_HOST_EXECUTABLE_SUFFIX
18238fd1498Szrj #else
18338fd1498Szrj #define HOST_EXECUTABLE_SUFFIX ""
18438fd1498Szrj #endif
18538fd1498Szrj 
18638fd1498Szrj /* By default, the suffix for target object files is ".o".  */
18738fd1498Szrj #ifdef TARGET_OBJECT_SUFFIX
18838fd1498Szrj #define HAVE_TARGET_OBJECT_SUFFIX
18938fd1498Szrj #else
19038fd1498Szrj #define TARGET_OBJECT_SUFFIX ".o"
19138fd1498Szrj #endif
19238fd1498Szrj 
19338fd1498Szrj static const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
19438fd1498Szrj 
19538fd1498Szrj /* Most every one is fine with LIBRARY_PATH.  For some, it conflicts.  */
19638fd1498Szrj #ifndef LIBRARY_PATH_ENV
19738fd1498Szrj #define LIBRARY_PATH_ENV "LIBRARY_PATH"
19838fd1498Szrj #endif
19938fd1498Szrj 
20038fd1498Szrj /* If a stage of compilation returns an exit status >= 1,
20138fd1498Szrj    compilation of that file ceases.  */
20238fd1498Szrj 
20338fd1498Szrj #define MIN_FATAL_STATUS 1
20438fd1498Szrj 
20538fd1498Szrj /* Flag set by cppspec.c to 1.  */
20638fd1498Szrj int is_cpp_driver;
20738fd1498Szrj 
20838fd1498Szrj /* Flag set to nonzero if an @file argument has been supplied to gcc.  */
20938fd1498Szrj static bool at_file_supplied;
21038fd1498Szrj 
21138fd1498Szrj /* Definition of string containing the arguments given to configure.  */
21238fd1498Szrj #include "configargs.h"
21338fd1498Szrj 
21438fd1498Szrj /* Flag saying to print the command line options understood by gcc and its
21538fd1498Szrj    sub-processes.  */
21638fd1498Szrj 
21738fd1498Szrj static int print_help_list;
21838fd1498Szrj 
21938fd1498Szrj /* Flag saying to print the version of gcc and its sub-processes.  */
22038fd1498Szrj 
22138fd1498Szrj static int print_version;
22238fd1498Szrj 
22338fd1498Szrj /* Flag indicating whether we should ONLY print the command and
22438fd1498Szrj    arguments (like verbose_flag) without executing the command.
22538fd1498Szrj    Displayed arguments are quoted so that the generated command
22638fd1498Szrj    line is suitable for execution.  This is intended for use in
22738fd1498Szrj    shell scripts to capture the driver-generated command line.  */
22838fd1498Szrj static int verbose_only_flag;
22938fd1498Szrj 
23038fd1498Szrj /* Flag indicating how to print command line options of sub-processes.  */
23138fd1498Szrj 
23238fd1498Szrj static int print_subprocess_help;
23338fd1498Szrj 
23438fd1498Szrj /* Linker suffix passed to -fuse-ld=... */
23538fd1498Szrj static const char *use_ld;
23638fd1498Szrj 
23738fd1498Szrj /* Whether we should report subprocess execution times to a file.  */
23838fd1498Szrj 
23938fd1498Szrj FILE *report_times_to_file = NULL;
24038fd1498Szrj 
24138fd1498Szrj /* Nonzero means place this string before uses of /, so that include
24238fd1498Szrj    and library files can be found in an alternate location.  */
24338fd1498Szrj 
24438fd1498Szrj #ifdef TARGET_SYSTEM_ROOT
24538fd1498Szrj #define DEFAULT_TARGET_SYSTEM_ROOT (TARGET_SYSTEM_ROOT)
24638fd1498Szrj #else
24738fd1498Szrj #define DEFAULT_TARGET_SYSTEM_ROOT (0)
24838fd1498Szrj #endif
24938fd1498Szrj static const char *target_system_root = DEFAULT_TARGET_SYSTEM_ROOT;
25038fd1498Szrj 
25138fd1498Szrj /* Nonzero means pass the updated target_system_root to the compiler.  */
25238fd1498Szrj 
25338fd1498Szrj static int target_system_root_changed;
25438fd1498Szrj 
25538fd1498Szrj /* Nonzero means append this string to target_system_root.  */
25638fd1498Szrj 
25738fd1498Szrj static const char *target_sysroot_suffix = 0;
25838fd1498Szrj 
25938fd1498Szrj /* Nonzero means append this string to target_system_root for headers.  */
26038fd1498Szrj 
26138fd1498Szrj static const char *target_sysroot_hdrs_suffix = 0;
26238fd1498Szrj 
26338fd1498Szrj /* Nonzero means write "temp" files in source directory
26438fd1498Szrj    and use the source file's name in them, and don't delete them.  */
26538fd1498Szrj 
26638fd1498Szrj static enum save_temps {
26738fd1498Szrj   SAVE_TEMPS_NONE,		/* no -save-temps */
26838fd1498Szrj   SAVE_TEMPS_CWD,		/* -save-temps in current directory */
269*df642abcSzrj   SAVE_TEMPS_OBJ,		/* -save-temps in object directory */
270*df642abcSzrj   SAVE_TEMPS_OBJZ		/* -save-temps in object directory with mangling */
27138fd1498Szrj } save_temps_flag;
27238fd1498Szrj 
27338fd1498Szrj /* Output file to use to get the object directory for -save-temps=obj  */
27438fd1498Szrj static char *save_temps_prefix = 0;
27538fd1498Szrj static size_t save_temps_length = 0;
27638fd1498Szrj 
27738fd1498Szrj /* The compiler version.  */
27838fd1498Szrj 
27938fd1498Szrj static const char *compiler_version;
28038fd1498Szrj 
28138fd1498Szrj /* The target version.  */
28238fd1498Szrj 
28338fd1498Szrj static const char *const spec_version = DEFAULT_TARGET_VERSION;
28438fd1498Szrj 
28538fd1498Szrj /* The target machine.  */
28638fd1498Szrj 
28738fd1498Szrj static const char *spec_machine = DEFAULT_TARGET_MACHINE;
28838fd1498Szrj static const char *spec_host_machine = DEFAULT_REAL_TARGET_MACHINE;
28938fd1498Szrj 
29038fd1498Szrj /* List of offload targets.  Separated by colon.  Empty string for
29138fd1498Szrj    -foffload=disable.  */
29238fd1498Szrj 
29338fd1498Szrj static char *offload_targets = NULL;
29438fd1498Szrj 
29538fd1498Szrj /* Nonzero if cross-compiling.
29638fd1498Szrj    When -b is used, the value comes from the `specs' file.  */
29738fd1498Szrj 
29838fd1498Szrj #ifdef CROSS_DIRECTORY_STRUCTURE
29938fd1498Szrj static const char *cross_compile = "1";
30038fd1498Szrj #else
30138fd1498Szrj static const char *cross_compile = "0";
30238fd1498Szrj #endif
30338fd1498Szrj 
30438fd1498Szrj /* Greatest exit code of sub-processes that has been encountered up to
30538fd1498Szrj    now.  */
30638fd1498Szrj static int greatest_status = 1;
30738fd1498Szrj 
30838fd1498Szrj /* This is the obstack which we use to allocate many strings.  */
30938fd1498Szrj 
31038fd1498Szrj static struct obstack obstack;
31138fd1498Szrj 
31238fd1498Szrj /* This is the obstack to build an environment variable to pass to
31338fd1498Szrj    collect2 that describes all of the relevant switches of what to
31438fd1498Szrj    pass the compiler in building the list of pointers to constructors
31538fd1498Szrj    and destructors.  */
31638fd1498Szrj 
31738fd1498Szrj static struct obstack collect_obstack;
31838fd1498Szrj 
31938fd1498Szrj /* Forward declaration for prototypes.  */
32038fd1498Szrj struct path_prefix;
32138fd1498Szrj struct prefix_list;
32238fd1498Szrj 
32338fd1498Szrj static void init_spec (void);
32438fd1498Szrj static void store_arg (const char *, int, int);
32538fd1498Szrj static void insert_wrapper (const char *);
32638fd1498Szrj static char *load_specs (const char *);
32738fd1498Szrj static void read_specs (const char *, bool, bool);
32838fd1498Szrj static void set_spec (const char *, const char *, bool);
32938fd1498Szrj static struct compiler *lookup_compiler (const char *, size_t, const char *);
33038fd1498Szrj static char *build_search_list (const struct path_prefix *, const char *,
33138fd1498Szrj 				bool, bool);
33238fd1498Szrj static void xputenv (const char *);
33338fd1498Szrj static void putenv_from_prefixes (const struct path_prefix *, const char *,
33438fd1498Szrj 				  bool);
33538fd1498Szrj static int access_check (const char *, int);
33638fd1498Szrj static char *find_a_file (const struct path_prefix *, const char *, int, bool);
33738fd1498Szrj static void add_prefix (struct path_prefix *, const char *, const char *,
33838fd1498Szrj 			int, int, int);
33938fd1498Szrj static void add_sysrooted_prefix (struct path_prefix *, const char *,
34038fd1498Szrj 				  const char *, int, int, int);
34138fd1498Szrj static char *skip_whitespace (char *);
34238fd1498Szrj static void delete_if_ordinary (const char *);
34338fd1498Szrj static void delete_temp_files (void);
34438fd1498Szrj static void delete_failure_queue (void);
34538fd1498Szrj static void clear_failure_queue (void);
34638fd1498Szrj static int check_live_switch (int, int);
34738fd1498Szrj static const char *handle_braces (const char *);
34838fd1498Szrj static inline bool input_suffix_matches (const char *, const char *);
34938fd1498Szrj static inline bool switch_matches (const char *, const char *, int);
35038fd1498Szrj static inline void mark_matching_switches (const char *, const char *, int);
35138fd1498Szrj static inline void process_marked_switches (void);
35238fd1498Szrj static const char *process_brace_body (const char *, const char *, const char *, int, int);
35338fd1498Szrj static const struct spec_function *lookup_spec_function (const char *);
35438fd1498Szrj static const char *eval_spec_function (const char *, const char *);
35538fd1498Szrj static const char *handle_spec_function (const char *, bool *);
35638fd1498Szrj static char *save_string (const char *, int);
35738fd1498Szrj static void set_collect_gcc_options (void);
35838fd1498Szrj static int do_spec_1 (const char *, int, const char *);
35938fd1498Szrj static int do_spec_2 (const char *);
36038fd1498Szrj static void do_option_spec (const char *, const char *);
36138fd1498Szrj static void do_self_spec (const char *);
36238fd1498Szrj static const char *find_file (const char *);
36338fd1498Szrj static int is_directory (const char *, bool);
36438fd1498Szrj static const char *validate_switches (const char *, bool);
36538fd1498Szrj static void validate_all_switches (void);
36638fd1498Szrj static inline void validate_switches_from_spec (const char *, bool);
36738fd1498Szrj static void give_switch (int, int);
36838fd1498Szrj static int default_arg (const char *, int);
36938fd1498Szrj static void set_multilib_dir (void);
37038fd1498Szrj static void print_multilib_info (void);
37138fd1498Szrj static void perror_with_name (const char *);
37238fd1498Szrj static void display_help (void);
37338fd1498Szrj static void add_preprocessor_option (const char *, int);
37438fd1498Szrj static void add_assembler_option (const char *, int);
37538fd1498Szrj static void add_linker_option (const char *, int);
37638fd1498Szrj static void process_command (unsigned int, struct cl_decoded_option *);
37738fd1498Szrj static int execute (void);
37838fd1498Szrj static void alloc_args (void);
37938fd1498Szrj static void clear_args (void);
38038fd1498Szrj static void fatal_signal (int);
38138fd1498Szrj #if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC)
38238fd1498Szrj static void init_gcc_specs (struct obstack *, const char *, const char *,
38338fd1498Szrj 			    const char *);
38438fd1498Szrj #endif
38538fd1498Szrj #if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
38638fd1498Szrj static const char *convert_filename (const char *, int, int);
38738fd1498Szrj #endif
38838fd1498Szrj 
38938fd1498Szrj static void try_generate_repro (const char **argv);
39038fd1498Szrj static const char *getenv_spec_function (int, const char **);
39138fd1498Szrj static const char *if_exists_spec_function (int, const char **);
39238fd1498Szrj static const char *if_exists_else_spec_function (int, const char **);
39338fd1498Szrj static const char *sanitize_spec_function (int, const char **);
39438fd1498Szrj static const char *replace_outfile_spec_function (int, const char **);
39538fd1498Szrj static const char *remove_outfile_spec_function (int, const char **);
39638fd1498Szrj static const char *version_compare_spec_function (int, const char **);
39738fd1498Szrj static const char *include_spec_function (int, const char **);
39838fd1498Szrj static const char *find_file_spec_function (int, const char **);
39938fd1498Szrj static const char *find_plugindir_spec_function (int, const char **);
40038fd1498Szrj static const char *print_asm_header_spec_function (int, const char **);
40138fd1498Szrj static const char *compare_debug_dump_opt_spec_function (int, const char **);
40238fd1498Szrj static const char *compare_debug_self_opt_spec_function (int, const char **);
40338fd1498Szrj static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
40438fd1498Szrj static const char *pass_through_libs_spec_func (int, const char **);
40538fd1498Szrj static const char *replace_extension_spec_func (int, const char **);
40638fd1498Szrj static const char *greater_than_spec_func (int, const char **);
40738fd1498Szrj static const char *debug_level_greater_than_spec_func (int, const char **);
40838fd1498Szrj static char *convert_white_space (char *);
40938fd1498Szrj 
41038fd1498Szrj /* The Specs Language
41138fd1498Szrj 
41238fd1498Szrj Specs are strings containing lines, each of which (if not blank)
41338fd1498Szrj is made up of a program name, and arguments separated by spaces.
41438fd1498Szrj The program name must be exact and start from root, since no path
41538fd1498Szrj is searched and it is unreliable to depend on the current working directory.
41638fd1498Szrj Redirection of input or output is not supported; the subprograms must
41738fd1498Szrj accept filenames saying what files to read and write.
41838fd1498Szrj 
41938fd1498Szrj In addition, the specs can contain %-sequences to substitute variable text
42038fd1498Szrj or for conditional text.  Here is a table of all defined %-sequences.
42138fd1498Szrj Note that spaces are not generated automatically around the results of
42238fd1498Szrj expanding these sequences; therefore, you can concatenate them together
42338fd1498Szrj or with constant text in a single argument.
42438fd1498Szrj 
42538fd1498Szrj  %%	substitute one % into the program name or argument.
42638fd1498Szrj  %i     substitute the name of the input file being processed.
42738fd1498Szrj  %b     substitute the basename of the input file being processed.
42838fd1498Szrj 	This is the substring up to (and not including) the last period
42938fd1498Szrj 	and not including the directory unless -save-temps was specified
43038fd1498Szrj 	to put temporaries in a different location.
43138fd1498Szrj  %B	same as %b, but include the file suffix (text after the last period).
43238fd1498Szrj  %gSUFFIX
43338fd1498Szrj 	substitute a file name that has suffix SUFFIX and is chosen
43438fd1498Szrj 	once per compilation, and mark the argument a la %d.  To reduce
43538fd1498Szrj 	exposure to denial-of-service attacks, the file name is now
43638fd1498Szrj 	chosen in a way that is hard to predict even when previously
43738fd1498Szrj 	chosen file names are known.  For example, `%g.s ... %g.o ... %g.s'
43838fd1498Szrj 	might turn into `ccUVUUAU.s ccXYAXZ12.o ccUVUUAU.s'.  SUFFIX matches
43938fd1498Szrj 	the regexp "[.0-9A-Za-z]*%O"; "%O" is treated exactly as if it
44038fd1498Szrj 	had been pre-processed.  Previously, %g was simply substituted
44138fd1498Szrj 	with a file name chosen once per compilation, without regard
44238fd1498Szrj 	to any appended suffix (which was therefore treated just like
44338fd1498Szrj 	ordinary text), making such attacks more likely to succeed.
44438fd1498Szrj  %|SUFFIX
44538fd1498Szrj 	like %g, but if -pipe is in effect, expands simply to "-".
44638fd1498Szrj  %mSUFFIX
44738fd1498Szrj         like %g, but if -pipe is in effect, expands to nothing.  (We have both
44838fd1498Szrj 	%| and %m to accommodate differences between system assemblers; see
44938fd1498Szrj 	the AS_NEEDS_DASH_FOR_PIPED_INPUT target macro.)
45038fd1498Szrj  %uSUFFIX
45138fd1498Szrj 	like %g, but generates a new temporary file name even if %uSUFFIX
45238fd1498Szrj 	was already seen.
45338fd1498Szrj  %USUFFIX
45438fd1498Szrj 	substitutes the last file name generated with %uSUFFIX, generating a
45538fd1498Szrj 	new one if there is no such last file name.  In the absence of any
45638fd1498Szrj 	%uSUFFIX, this is just like %gSUFFIX, except they don't share
45738fd1498Szrj 	the same suffix "space", so `%g.s ... %U.s ... %g.s ... %U.s'
45838fd1498Szrj 	would involve the generation of two distinct file names, one
45938fd1498Szrj 	for each `%g.s' and another for each `%U.s'.  Previously, %U was
46038fd1498Szrj 	simply substituted with a file name chosen for the previous %u,
46138fd1498Szrj 	without regard to any appended suffix.
46238fd1498Szrj  %jSUFFIX
46338fd1498Szrj         substitutes the name of the HOST_BIT_BUCKET, if any, and if it is
46438fd1498Szrj         writable, and if save-temps is off; otherwise, substitute the name
46538fd1498Szrj         of a temporary file, just like %u.  This temporary file is not
46638fd1498Szrj         meant for communication between processes, but rather as a junk
46738fd1498Szrj         disposal mechanism.
46838fd1498Szrj  %.SUFFIX
46938fd1498Szrj         substitutes .SUFFIX for the suffixes of a matched switch's args when
47038fd1498Szrj         it is subsequently output with %*. SUFFIX is terminated by the next
47138fd1498Szrj         space or %.
47238fd1498Szrj  %d	marks the argument containing or following the %d as a
47338fd1498Szrj 	temporary file name, so that file will be deleted if GCC exits
47438fd1498Szrj 	successfully.  Unlike %g, this contributes no text to the argument.
47538fd1498Szrj  %w	marks the argument containing or following the %w as the
47638fd1498Szrj 	"output file" of this compilation.  This puts the argument
47738fd1498Szrj 	into the sequence of arguments that %o will substitute later.
47838fd1498Szrj  %V	indicates that this compilation produces no "output file".
47938fd1498Szrj  %W{...}
48038fd1498Szrj 	like %{...} but mark last argument supplied within
48138fd1498Szrj 	as a file to be deleted on failure.
48238fd1498Szrj  %o	substitutes the names of all the output files, with spaces
48338fd1498Szrj 	automatically placed around them.  You should write spaces
48438fd1498Szrj 	around the %o as well or the results are undefined.
48538fd1498Szrj 	%o is for use in the specs for running the linker.
48638fd1498Szrj 	Input files whose names have no recognized suffix are not compiled
48738fd1498Szrj 	at all, but they are included among the output files, so they will
48838fd1498Szrj 	be linked.
48938fd1498Szrj  %O	substitutes the suffix for object files.  Note that this is
49038fd1498Szrj         handled specially when it immediately follows %g, %u, or %U
49138fd1498Szrj 	(with or without a suffix argument) because of the need for
49238fd1498Szrj 	those to form complete file names.  The handling is such that
49338fd1498Szrj 	%O is treated exactly as if it had already been substituted,
49438fd1498Szrj 	except that %g, %u, and %U do not currently support additional
49538fd1498Szrj 	SUFFIX characters following %O as they would following, for
49638fd1498Szrj 	example, `.o'.
49738fd1498Szrj  %I	Substitute any of -iprefix (made from GCC_EXEC_PREFIX), -isysroot
49838fd1498Szrj 	(made from TARGET_SYSTEM_ROOT), -isystem (made from COMPILER_PATH
49938fd1498Szrj 	and -B options) and -imultilib as necessary.
50038fd1498Szrj  %s     current argument is the name of a library or startup file of some sort.
50138fd1498Szrj         Search for that file in a standard list of directories
50238fd1498Szrj 	and substitute the full name found.
50338fd1498Szrj  %eSTR  Print STR as an error message.  STR is terminated by a newline.
50438fd1498Szrj         Use this when inconsistent options are detected.
50538fd1498Szrj  %nSTR  Print STR as a notice.  STR is terminated by a newline.
50638fd1498Szrj  %x{OPTION}	Accumulate an option for %X.
50738fd1498Szrj  %X	Output the accumulated linker options specified by compilations.
50838fd1498Szrj  %Y	Output the accumulated assembler options specified by compilations.
50938fd1498Szrj  %Z	Output the accumulated preprocessor options specified by compilations.
51038fd1498Szrj  %a     process ASM_SPEC as a spec.
51138fd1498Szrj         This allows config.h to specify part of the spec for running as.
51238fd1498Szrj  %A	process ASM_FINAL_SPEC as a spec.  A capital A is actually
51338fd1498Szrj 	used here.  This can be used to run a post-processor after the
51438fd1498Szrj 	assembler has done its job.
51538fd1498Szrj  %D	Dump out a -L option for each directory in startfile_prefixes.
51638fd1498Szrj 	If multilib_dir is set, extra entries are generated with it affixed.
51738fd1498Szrj  %l     process LINK_SPEC as a spec.
51838fd1498Szrj  %L     process LIB_SPEC as a spec.
51938fd1498Szrj  %M     Output multilib_os_dir.
52038fd1498Szrj  %G     process LIBGCC_SPEC as a spec.
52138fd1498Szrj  %R     Output the concatenation of target_system_root and
52238fd1498Szrj         target_sysroot_suffix.
52338fd1498Szrj  %S     process STARTFILE_SPEC as a spec.  A capital S is actually used here.
52438fd1498Szrj  %E     process ENDFILE_SPEC as a spec.  A capital E is actually used here.
52538fd1498Szrj  %C     process CPP_SPEC as a spec.
52638fd1498Szrj  %1	process CC1_SPEC as a spec.
52738fd1498Szrj  %2	process CC1PLUS_SPEC as a spec.
52838fd1498Szrj  %*	substitute the variable part of a matched option.  (See below.)
52938fd1498Szrj 	Note that each comma in the substituted string is replaced by
53038fd1498Szrj 	a single space.  A space is appended after the last substition
53138fd1498Szrj 	unless there is more text in current sequence.
53238fd1498Szrj  %<S    remove all occurrences of -S from the command line.
53338fd1498Szrj         Note - this command is position dependent.  % commands in the
53438fd1498Szrj         spec string before this one will see -S, % commands in the
53538fd1498Szrj         spec string after this one will not.
53638fd1498Szrj  %>S	Similar to "%<S", but keep it in the GCC command line.
53738fd1498Szrj  %<S*	remove all occurrences of all switches beginning with -S from the
53838fd1498Szrj         command line.
53938fd1498Szrj  %:function(args)
54038fd1498Szrj 	Call the named function FUNCTION, passing it ARGS.  ARGS is
54138fd1498Szrj 	first processed as a nested spec string, then split into an
54238fd1498Szrj 	argument vector in the usual fashion.  The function returns
54338fd1498Szrj 	a string which is processed as if it had appeared literally
54438fd1498Szrj 	as part of the current spec.
54538fd1498Szrj  %{S}   substitutes the -S switch, if that switch was given to GCC.
54638fd1498Szrj 	If that switch was not specified, this substitutes nothing.
54738fd1498Szrj 	Here S is a metasyntactic variable.
54838fd1498Szrj  %{S*}  substitutes all the switches specified to GCC whose names start
54938fd1498Szrj 	with -S.  This is used for -o, -I, etc; switches that take
55038fd1498Szrj 	arguments.  GCC considers `-o foo' as being one switch whose
55138fd1498Szrj 	name starts with `o'.  %{o*} would substitute this text,
55238fd1498Szrj 	including the space; thus, two arguments would be generated.
55338fd1498Szrj  %{S*&T*} likewise, but preserve order of S and T options (the order
55438fd1498Szrj 	of S and T in the spec is not significant).  Can be any number
55538fd1498Szrj 	of ampersand-separated variables; for each the wild card is
55638fd1498Szrj 	optional.  Useful for CPP as %{D*&U*&A*}.
55738fd1498Szrj 
55838fd1498Szrj  %{S:X}   substitutes X, if the -S switch was given to GCC.
55938fd1498Szrj  %{!S:X}  substitutes X, if the -S switch was NOT given to GCC.
56038fd1498Szrj  %{S*:X}  substitutes X if one or more switches whose names start
56138fd1498Szrj           with -S was given to GCC.  Normally X is substituted only
56238fd1498Szrj           once, no matter how many such switches appeared.  However,
56338fd1498Szrj           if %* appears somewhere in X, then X will be substituted
56438fd1498Szrj           once for each matching switch, with the %* replaced by the
56538fd1498Szrj           part of that switch that matched the '*'.  A space will be
56638fd1498Szrj 	  appended after the last substition unless there is more
56738fd1498Szrj 	  text in current sequence.
56838fd1498Szrj  %{.S:X}  substitutes X, if processing a file with suffix S.
56938fd1498Szrj  %{!.S:X} substitutes X, if NOT processing a file with suffix S.
57038fd1498Szrj  %{,S:X}  substitutes X, if processing a file which will use spec S.
57138fd1498Szrj  %{!,S:X} substitutes X, if NOT processing a file which will use spec S.
57238fd1498Szrj 
57338fd1498Szrj  %{S|T:X} substitutes X if either -S or -T was given to GCC.  This may be
57438fd1498Szrj 	  combined with '!', '.', ',', and '*' as above binding stronger
57538fd1498Szrj 	  than the OR.
57638fd1498Szrj 	  If %* appears in X, all of the alternatives must be starred, and
57738fd1498Szrj 	  only the first matching alternative is substituted.
57838fd1498Szrj  %{%:function(args):X}
57938fd1498Szrj 	  Call function named FUNCTION with args ARGS.  If the function
58038fd1498Szrj 	  returns non-NULL, then X is substituted, if it returns
58138fd1498Szrj 	  NULL, it isn't substituted.
58238fd1498Szrj  %{S:X;   if S was given to GCC, substitutes X;
58338fd1498Szrj    T:Y;   else if T was given to GCC, substitutes Y;
58438fd1498Szrj     :D}   else substitutes D.  There can be as many clauses as you need.
58538fd1498Szrj           This may be combined with '.', '!', ',', '|', and '*' as above.
58638fd1498Szrj 
58738fd1498Szrj  %(Spec) processes a specification defined in a specs file as *Spec:
58838fd1498Szrj 
58938fd1498Szrj The switch matching text S in a %{S}, %{S:X}, or similar construct can use
59038fd1498Szrj a backslash to ignore the special meaning of the character following it,
59138fd1498Szrj thus allowing literal matching of a character that is otherwise specially
59238fd1498Szrj treated.  For example, %{std=iso9899\:1999:X} substitutes X if the
59338fd1498Szrj -std=iso9899:1999 option is given.
59438fd1498Szrj 
59538fd1498Szrj The conditional text X in a %{S:X} or similar construct may contain
59638fd1498Szrj other nested % constructs or spaces, or even newlines.  They are
59738fd1498Szrj processed as usual, as described above.  Trailing white space in X is
59838fd1498Szrj ignored.  White space may also appear anywhere on the left side of the
59938fd1498Szrj colon in these constructs, except between . or * and the corresponding
60038fd1498Szrj word.
60138fd1498Szrj 
60238fd1498Szrj The -O, -f, -g, -m, and -W switches are handled specifically in these
60338fd1498Szrj constructs.  If another value of -O or the negated form of a -f, -m, or
60438fd1498Szrj -W switch is found later in the command line, the earlier switch
60538fd1498Szrj value is ignored, except with {S*} where S is just one letter; this
60638fd1498Szrj passes all matching options.
60738fd1498Szrj 
60838fd1498Szrj The character | at the beginning of the predicate text is used to indicate
60938fd1498Szrj that a command should be piped to the following command, but only if -pipe
61038fd1498Szrj is specified.
61138fd1498Szrj 
61238fd1498Szrj Note that it is built into GCC which switches take arguments and which
61338fd1498Szrj do not.  You might think it would be useful to generalize this to
61438fd1498Szrj allow each compiler's spec to say which switches take arguments.  But
61538fd1498Szrj this cannot be done in a consistent fashion.  GCC cannot even decide
61638fd1498Szrj which input files have been specified without knowing which switches
61738fd1498Szrj take arguments, and it must know which input files to compile in order
61838fd1498Szrj to tell which compilers to run.
61938fd1498Szrj 
62038fd1498Szrj GCC also knows implicitly that arguments starting in `-l' are to be
62138fd1498Szrj treated as compiler output files, and passed to the linker in their
62238fd1498Szrj proper position among the other output files.  */
62338fd1498Szrj 
62438fd1498Szrj /* Define the macros used for specs %a, %l, %L, %S, %C, %1.  */
62538fd1498Szrj 
62638fd1498Szrj /* config.h can define ASM_SPEC to provide extra args to the assembler
62738fd1498Szrj    or extra switch-translations.  */
62838fd1498Szrj #ifndef ASM_SPEC
62938fd1498Szrj #define ASM_SPEC ""
63038fd1498Szrj #endif
63138fd1498Szrj 
63238fd1498Szrj /* config.h can define ASM_FINAL_SPEC to run a post processor after
63338fd1498Szrj    the assembler has run.  */
63438fd1498Szrj #ifndef ASM_FINAL_SPEC
63538fd1498Szrj #define ASM_FINAL_SPEC \
63638fd1498Szrj   "%{gsplit-dwarf: \n\
63738fd1498Szrj        objcopy --extract-dwo \
63838fd1498Szrj 	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
63938fd1498Szrj 	 %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
64038fd1498Szrj        objcopy --strip-dwo \
64138fd1498Szrj 	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
64238fd1498Szrj     }"
64338fd1498Szrj #endif
64438fd1498Szrj 
64538fd1498Szrj /* config.h can define CPP_SPEC to provide extra args to the C preprocessor
64638fd1498Szrj    or extra switch-translations.  */
64738fd1498Szrj #ifndef CPP_SPEC
64838fd1498Szrj #define CPP_SPEC ""
64938fd1498Szrj #endif
65038fd1498Szrj 
65138fd1498Szrj /* config.h can define CC1_SPEC to provide extra args to cc1 and cc1plus
65238fd1498Szrj    or extra switch-translations.  */
65338fd1498Szrj #ifndef CC1_SPEC
65438fd1498Szrj #define CC1_SPEC ""
65538fd1498Szrj #endif
65638fd1498Szrj 
65738fd1498Szrj /* config.h can define CC1PLUS_SPEC to provide extra args to cc1plus
65838fd1498Szrj    or extra switch-translations.  */
65938fd1498Szrj #ifndef CC1PLUS_SPEC
66038fd1498Szrj #define CC1PLUS_SPEC ""
66138fd1498Szrj #endif
66238fd1498Szrj 
66338fd1498Szrj /* config.h can define LINK_SPEC to provide extra args to the linker
66438fd1498Szrj    or extra switch-translations.  */
66538fd1498Szrj #ifndef LINK_SPEC
66638fd1498Szrj #define LINK_SPEC ""
66738fd1498Szrj #endif
66838fd1498Szrj 
66938fd1498Szrj /* config.h can define LIB_SPEC to override the default libraries.  */
67038fd1498Szrj #ifndef LIB_SPEC
67138fd1498Szrj #define LIB_SPEC "%{!shared:%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}"
67238fd1498Szrj #endif
67338fd1498Szrj 
67438fd1498Szrj /* When using -fsplit-stack we need to wrap pthread_create, in order
67538fd1498Szrj    to initialize the stack guard.  We always use wrapping, rather than
67638fd1498Szrj    shared library ordering, and we keep the wrapper function in
67738fd1498Szrj    libgcc.  This is not yet a real spec, though it could become one;
67838fd1498Szrj    it is currently just stuffed into LINK_SPEC.  FIXME: This wrapping
67938fd1498Szrj    only works with GNU ld and gold.  */
68038fd1498Szrj #ifdef HAVE_GOLD_NON_DEFAULT_SPLIT_STACK
68138fd1498Szrj #define STACK_SPLIT_SPEC " %{fsplit-stack: -fuse-ld=gold --wrap=pthread_create}"
68238fd1498Szrj #else
68338fd1498Szrj #define STACK_SPLIT_SPEC " %{fsplit-stack: --wrap=pthread_create}"
68438fd1498Szrj #endif
68538fd1498Szrj 
68638fd1498Szrj #ifndef LIBASAN_SPEC
68738fd1498Szrj #define STATIC_LIBASAN_LIBS \
68838fd1498Szrj   " %{static-libasan|static:%:include(libsanitizer.spec)%(link_libasan)}"
68938fd1498Szrj #ifdef LIBASAN_EARLY_SPEC
69038fd1498Szrj #define LIBASAN_SPEC STATIC_LIBASAN_LIBS
69138fd1498Szrj #elif defined(HAVE_LD_STATIC_DYNAMIC)
69238fd1498Szrj #define LIBASAN_SPEC "%{static-libasan:" LD_STATIC_OPTION \
69338fd1498Szrj 		     "} -lasan %{static-libasan:" LD_DYNAMIC_OPTION "}" \
69438fd1498Szrj 		     STATIC_LIBASAN_LIBS
69538fd1498Szrj #else
69638fd1498Szrj #define LIBASAN_SPEC "-lasan" STATIC_LIBASAN_LIBS
69738fd1498Szrj #endif
69838fd1498Szrj #endif
69938fd1498Szrj 
70038fd1498Szrj #ifndef LIBASAN_EARLY_SPEC
70138fd1498Szrj #define LIBASAN_EARLY_SPEC ""
70238fd1498Szrj #endif
70338fd1498Szrj 
70438fd1498Szrj #ifndef LIBTSAN_SPEC
70538fd1498Szrj #define STATIC_LIBTSAN_LIBS \
70638fd1498Szrj   " %{static-libtsan|static:%:include(libsanitizer.spec)%(link_libtsan)}"
70738fd1498Szrj #ifdef LIBTSAN_EARLY_SPEC
70838fd1498Szrj #define LIBTSAN_SPEC STATIC_LIBTSAN_LIBS
70938fd1498Szrj #elif defined(HAVE_LD_STATIC_DYNAMIC)
71038fd1498Szrj #define LIBTSAN_SPEC "%{static-libtsan:" LD_STATIC_OPTION \
71138fd1498Szrj 		     "} -ltsan %{static-libtsan:" LD_DYNAMIC_OPTION "}" \
71238fd1498Szrj 		     STATIC_LIBTSAN_LIBS
71338fd1498Szrj #else
71438fd1498Szrj #define LIBTSAN_SPEC "-ltsan" STATIC_LIBTSAN_LIBS
71538fd1498Szrj #endif
71638fd1498Szrj #endif
71738fd1498Szrj 
71838fd1498Szrj #ifndef LIBTSAN_EARLY_SPEC
71938fd1498Szrj #define LIBTSAN_EARLY_SPEC ""
72038fd1498Szrj #endif
72138fd1498Szrj 
72238fd1498Szrj #ifndef LIBLSAN_SPEC
72338fd1498Szrj #define STATIC_LIBLSAN_LIBS \
72438fd1498Szrj   " %{static-liblsan|static:%:include(libsanitizer.spec)%(link_liblsan)}"
72538fd1498Szrj #ifdef LIBLSAN_EARLY_SPEC
72638fd1498Szrj #define LIBLSAN_SPEC STATIC_LIBLSAN_LIBS
72738fd1498Szrj #elif defined(HAVE_LD_STATIC_DYNAMIC)
72838fd1498Szrj #define LIBLSAN_SPEC "%{static-liblsan:" LD_STATIC_OPTION \
72938fd1498Szrj 		     "} -llsan %{static-liblsan:" LD_DYNAMIC_OPTION "}" \
73038fd1498Szrj 		     STATIC_LIBLSAN_LIBS
73138fd1498Szrj #else
73238fd1498Szrj #define LIBLSAN_SPEC "-llsan" STATIC_LIBLSAN_LIBS
73338fd1498Szrj #endif
73438fd1498Szrj #endif
73538fd1498Szrj 
73638fd1498Szrj #ifndef LIBLSAN_EARLY_SPEC
73738fd1498Szrj #define LIBLSAN_EARLY_SPEC ""
73838fd1498Szrj #endif
73938fd1498Szrj 
74038fd1498Szrj #ifndef LIBUBSAN_SPEC
74138fd1498Szrj #define STATIC_LIBUBSAN_LIBS \
74238fd1498Szrj   " %{static-libubsan|static:%:include(libsanitizer.spec)%(link_libubsan)}"
74338fd1498Szrj #ifdef HAVE_LD_STATIC_DYNAMIC
74438fd1498Szrj #define LIBUBSAN_SPEC "%{static-libubsan:" LD_STATIC_OPTION \
74538fd1498Szrj 		     "} -lubsan %{static-libubsan:" LD_DYNAMIC_OPTION "}" \
74638fd1498Szrj 		     STATIC_LIBUBSAN_LIBS
74738fd1498Szrj #else
74838fd1498Szrj #define LIBUBSAN_SPEC "-lubsan" STATIC_LIBUBSAN_LIBS
74938fd1498Szrj #endif
75038fd1498Szrj #endif
75138fd1498Szrj 
75238fd1498Szrj /* Linker options for compressed debug sections.  */
75338fd1498Szrj #if HAVE_LD_COMPRESS_DEBUG == 0
75438fd1498Szrj /* No linker support.  */
75538fd1498Szrj #define LINK_COMPRESS_DEBUG_SPEC \
75638fd1498Szrj 	" %{gz*:%e-gz is not supported in this configuration} "
75738fd1498Szrj #elif HAVE_LD_COMPRESS_DEBUG == 1
75838fd1498Szrj /* GNU style on input, GNU ld options.  Reject, not useful.  */
75938fd1498Szrj #define LINK_COMPRESS_DEBUG_SPEC \
76038fd1498Szrj 	" %{gz*:%e-gz is not supported in this configuration} "
76138fd1498Szrj #elif HAVE_LD_COMPRESS_DEBUG == 2
76238fd1498Szrj /* GNU style, GNU gold options.  */
76338fd1498Szrj #define LINK_COMPRESS_DEBUG_SPEC \
76438fd1498Szrj 	" %{gz|gz=zlib-gnu:" LD_COMPRESS_DEBUG_OPTION "=zlib}" \
76538fd1498Szrj 	" %{gz=none:"        LD_COMPRESS_DEBUG_OPTION "=none}" \
76638fd1498Szrj 	" %{gz=zlib:%e-gz=zlib is not supported in this configuration} "
76738fd1498Szrj #elif HAVE_LD_COMPRESS_DEBUG == 3
76838fd1498Szrj /* ELF gABI style.  */
76938fd1498Szrj #define LINK_COMPRESS_DEBUG_SPEC \
77038fd1498Szrj 	" %{gz|gz=zlib:"  LD_COMPRESS_DEBUG_OPTION "=zlib}" \
77138fd1498Szrj 	" %{gz=none:"	  LD_COMPRESS_DEBUG_OPTION "=none}" \
77238fd1498Szrj 	" %{gz=zlib-gnu:" LD_COMPRESS_DEBUG_OPTION "=zlib-gnu} "
77338fd1498Szrj #else
77438fd1498Szrj #error Unknown value for HAVE_LD_COMPRESS_DEBUG.
77538fd1498Szrj #endif
77638fd1498Szrj 
77738fd1498Szrj /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
77838fd1498Szrj    included.  */
77938fd1498Szrj #ifndef LIBGCC_SPEC
78038fd1498Szrj #if defined(REAL_LIBGCC_SPEC)
78138fd1498Szrj #define LIBGCC_SPEC REAL_LIBGCC_SPEC
78238fd1498Szrj #elif defined(LINK_LIBGCC_SPECIAL_1)
78338fd1498Szrj /* Have gcc do the search for libgcc.a.  */
78438fd1498Szrj #define LIBGCC_SPEC "libgcc.a%s"
78538fd1498Szrj #else
78638fd1498Szrj #define LIBGCC_SPEC "-lgcc"
78738fd1498Szrj #endif
78838fd1498Szrj #endif
78938fd1498Szrj 
79038fd1498Szrj /* config.h can define STARTFILE_SPEC to override the default crt0 files.  */
79138fd1498Szrj #ifndef STARTFILE_SPEC
79238fd1498Szrj #define STARTFILE_SPEC  \
79338fd1498Szrj   "%{!shared:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}"
79438fd1498Szrj #endif
79538fd1498Szrj 
79638fd1498Szrj /* config.h can define ENDFILE_SPEC to override the default crtn files.  */
79738fd1498Szrj #ifndef ENDFILE_SPEC
79838fd1498Szrj #define ENDFILE_SPEC ""
79938fd1498Szrj #endif
80038fd1498Szrj 
80138fd1498Szrj #ifndef LINKER_NAME
80238fd1498Szrj #define LINKER_NAME "collect2"
80338fd1498Szrj #endif
80438fd1498Szrj 
80538fd1498Szrj #ifdef HAVE_AS_DEBUG_PREFIX_MAP
80638fd1498Szrj #define ASM_MAP " %{fdebug-prefix-map=*:--debug-prefix-map %*}"
80738fd1498Szrj #else
80838fd1498Szrj #define ASM_MAP ""
80938fd1498Szrj #endif
81038fd1498Szrj 
81138fd1498Szrj /* Assembler options for compressed debug sections.  */
81238fd1498Szrj #if HAVE_LD_COMPRESS_DEBUG < 2
81338fd1498Szrj /* Reject if the linker cannot write compressed debug sections.  */
81438fd1498Szrj #define ASM_COMPRESS_DEBUG_SPEC \
81538fd1498Szrj 	" %{gz*:%e-gz is not supported in this configuration} "
81638fd1498Szrj #else /* HAVE_LD_COMPRESS_DEBUG >= 2 */
81738fd1498Szrj #if HAVE_AS_COMPRESS_DEBUG == 0
81838fd1498Szrj /* No assembler support.  Ignore silently.  */
81938fd1498Szrj #define ASM_COMPRESS_DEBUG_SPEC \
82038fd1498Szrj 	" %{gz*:} "
82138fd1498Szrj #elif HAVE_AS_COMPRESS_DEBUG == 1
82238fd1498Szrj /* GNU style, GNU as options.  */
82338fd1498Szrj #define ASM_COMPRESS_DEBUG_SPEC \
82438fd1498Szrj 	" %{gz|gz=zlib-gnu:" AS_COMPRESS_DEBUG_OPTION "}" \
82538fd1498Szrj 	" %{gz=none:"        AS_NO_COMPRESS_DEBUG_OPTION "}" \
82638fd1498Szrj 	" %{gz=zlib:%e-gz=zlib is not supported in this configuration} "
82738fd1498Szrj #elif HAVE_AS_COMPRESS_DEBUG == 2
82838fd1498Szrj /* ELF gABI style.  */
82938fd1498Szrj #define ASM_COMPRESS_DEBUG_SPEC \
83038fd1498Szrj 	" %{gz|gz=zlib:"  AS_COMPRESS_DEBUG_OPTION "=zlib}" \
83138fd1498Szrj 	" %{gz=none:"	  AS_COMPRESS_DEBUG_OPTION "=none}" \
83238fd1498Szrj 	" %{gz=zlib-gnu:" AS_COMPRESS_DEBUG_OPTION "=zlib-gnu} "
83338fd1498Szrj #else
83438fd1498Szrj #error Unknown value for HAVE_AS_COMPRESS_DEBUG.
83538fd1498Szrj #endif
83638fd1498Szrj #endif /* HAVE_LD_COMPRESS_DEBUG >= 2 */
83738fd1498Szrj 
83838fd1498Szrj /* Define ASM_DEBUG_SPEC to be a spec suitable for translating '-g'
83938fd1498Szrj    to the assembler.  */
84038fd1498Szrj #ifndef ASM_DEBUG_SPEC
84138fd1498Szrj # if defined(DBX_DEBUGGING_INFO) && defined(DWARF2_DEBUGGING_INFO) \
84238fd1498Szrj      && defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
84338fd1498Szrj #  define ASM_DEBUG_SPEC						\
84438fd1498Szrj       (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG				\
84538fd1498Szrj        ? "%{%:debug-level-gt(0):"					\
84638fd1498Szrj 	 "%{gdwarf*:--gdwarf2}%{!gdwarf*:%{g*:--gstabs}}}" ASM_MAP	\
84738fd1498Szrj        : "%{%:debug-level-gt(0):"					\
84838fd1498Szrj 	 "%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}}" ASM_MAP)
84938fd1498Szrj # else
85038fd1498Szrj #  if defined(DBX_DEBUGGING_INFO) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
85138fd1498Szrj #   define ASM_DEBUG_SPEC "%{g*:%{%:debug-level-gt(0):--gstabs}}" ASM_MAP
85238fd1498Szrj #  endif
85338fd1498Szrj #  if defined(DWARF2_DEBUGGING_INFO) && defined(HAVE_AS_GDWARF2_DEBUG_FLAG)
85438fd1498Szrj #   define ASM_DEBUG_SPEC "%{g*:%{%:debug-level-gt(0):--gdwarf2}}" ASM_MAP
85538fd1498Szrj #  endif
85638fd1498Szrj # endif
85738fd1498Szrj #endif
85838fd1498Szrj #ifndef ASM_DEBUG_SPEC
85938fd1498Szrj # define ASM_DEBUG_SPEC ""
86038fd1498Szrj #endif
86138fd1498Szrj 
86238fd1498Szrj /* Here is the spec for running the linker, after compiling all files.  */
86338fd1498Szrj 
86438fd1498Szrj /* This is overridable by the target in case they need to specify the
86538fd1498Szrj    -lgcc and -lc order specially, yet not require them to override all
86638fd1498Szrj    of LINK_COMMAND_SPEC.  */
86738fd1498Szrj #ifndef LINK_GCC_C_SEQUENCE_SPEC
86838fd1498Szrj #define LINK_GCC_C_SEQUENCE_SPEC "%G %L %G"
86938fd1498Szrj #endif
87038fd1498Szrj 
87138fd1498Szrj #ifndef LINK_SSP_SPEC
87238fd1498Szrj #ifdef TARGET_LIBC_PROVIDES_SSP
87338fd1498Szrj #define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \
87438fd1498Szrj 		       "|fstack-protector-strong|fstack-protector-explicit:}"
87538fd1498Szrj #else
87638fd1498Szrj #define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \
87738fd1498Szrj 		       "|fstack-protector-strong|fstack-protector-explicit" \
87838fd1498Szrj 		       ":-lssp_nonshared -lssp}"
87938fd1498Szrj #endif
88038fd1498Szrj #endif
88138fd1498Szrj 
88238fd1498Szrj #ifdef ENABLE_DEFAULT_PIE
88338fd1498Szrj #define PIE_SPEC		"!no-pie"
88438fd1498Szrj #define NO_FPIE1_SPEC		"fno-pie"
88538fd1498Szrj #define FPIE1_SPEC		NO_FPIE1_SPEC ":;"
88638fd1498Szrj #define NO_FPIE2_SPEC		"fno-PIE"
88738fd1498Szrj #define FPIE2_SPEC		NO_FPIE2_SPEC ":;"
88838fd1498Szrj #define NO_FPIE_SPEC		NO_FPIE1_SPEC "|" NO_FPIE2_SPEC
88938fd1498Szrj #define FPIE_SPEC		NO_FPIE_SPEC ":;"
89038fd1498Szrj #define NO_FPIC1_SPEC		"fno-pic"
89138fd1498Szrj #define FPIC1_SPEC		NO_FPIC1_SPEC ":;"
89238fd1498Szrj #define NO_FPIC2_SPEC		"fno-PIC"
89338fd1498Szrj #define FPIC2_SPEC		NO_FPIC2_SPEC ":;"
89438fd1498Szrj #define NO_FPIC_SPEC		NO_FPIC1_SPEC "|" NO_FPIC2_SPEC
89538fd1498Szrj #define FPIC_SPEC		NO_FPIC_SPEC ":;"
89638fd1498Szrj #define NO_FPIE1_AND_FPIC1_SPEC	NO_FPIE1_SPEC "|" NO_FPIC1_SPEC
89738fd1498Szrj #define FPIE1_OR_FPIC1_SPEC	NO_FPIE1_AND_FPIC1_SPEC ":;"
89838fd1498Szrj #define NO_FPIE2_AND_FPIC2_SPEC	NO_FPIE2_SPEC "|" NO_FPIC2_SPEC
89938fd1498Szrj #define FPIE2_OR_FPIC2_SPEC	NO_FPIE2_AND_FPIC2_SPEC ":;"
90038fd1498Szrj #define NO_FPIE_AND_FPIC_SPEC	NO_FPIE_SPEC "|" NO_FPIC_SPEC
90138fd1498Szrj #define FPIE_OR_FPIC_SPEC	NO_FPIE_AND_FPIC_SPEC ":;"
90238fd1498Szrj #else
90338fd1498Szrj #define PIE_SPEC		"pie"
90438fd1498Szrj #define FPIE1_SPEC		"fpie"
90538fd1498Szrj #define NO_FPIE1_SPEC		FPIE1_SPEC ":;"
90638fd1498Szrj #define FPIE2_SPEC		"fPIE"
90738fd1498Szrj #define NO_FPIE2_SPEC		FPIE2_SPEC ":;"
90838fd1498Szrj #define FPIE_SPEC		FPIE1_SPEC "|" FPIE2_SPEC
90938fd1498Szrj #define NO_FPIE_SPEC		FPIE_SPEC ":;"
91038fd1498Szrj #define FPIC1_SPEC		"fpic"
91138fd1498Szrj #define NO_FPIC1_SPEC		FPIC1_SPEC ":;"
91238fd1498Szrj #define FPIC2_SPEC		"fPIC"
91338fd1498Szrj #define NO_FPIC2_SPEC		FPIC2_SPEC ":;"
91438fd1498Szrj #define FPIC_SPEC		FPIC1_SPEC "|" FPIC2_SPEC
91538fd1498Szrj #define NO_FPIC_SPEC		FPIC_SPEC ":;"
91638fd1498Szrj #define FPIE1_OR_FPIC1_SPEC	FPIE1_SPEC "|" FPIC1_SPEC
91738fd1498Szrj #define NO_FPIE1_AND_FPIC1_SPEC	FPIE1_OR_FPIC1_SPEC ":;"
91838fd1498Szrj #define FPIE2_OR_FPIC2_SPEC	FPIE2_SPEC "|" FPIC2_SPEC
91938fd1498Szrj #define NO_FPIE2_AND_FPIC2_SPEC	FPIE1_OR_FPIC2_SPEC ":;"
92038fd1498Szrj #define FPIE_OR_FPIC_SPEC	FPIE_SPEC "|" FPIC_SPEC
92138fd1498Szrj #define NO_FPIE_AND_FPIC_SPEC	FPIE_OR_FPIC_SPEC ":;"
92238fd1498Szrj #endif
92338fd1498Szrj 
92438fd1498Szrj #ifndef LINK_PIE_SPEC
92538fd1498Szrj #ifdef HAVE_LD_PIE
92638fd1498Szrj #ifndef LD_PIE_SPEC
92738fd1498Szrj #define LD_PIE_SPEC "-pie"
92838fd1498Szrj #endif
92938fd1498Szrj #else
93038fd1498Szrj #define LD_PIE_SPEC ""
93138fd1498Szrj #endif
93238fd1498Szrj #define LINK_PIE_SPEC "%{static|shared|r:;" PIE_SPEC ":" LD_PIE_SPEC "} "
93338fd1498Szrj #endif
93438fd1498Szrj 
93538fd1498Szrj #ifndef LINK_BUILDID_SPEC
93638fd1498Szrj # if defined(HAVE_LD_BUILDID) && defined(ENABLE_LD_BUILDID)
93738fd1498Szrj #  define LINK_BUILDID_SPEC "%{!r:--build-id} "
93838fd1498Szrj # endif
93938fd1498Szrj #endif
94038fd1498Szrj 
94138fd1498Szrj /* Conditional to test whether the LTO plugin is used or not.
94238fd1498Szrj    FIXME: For slim LTO we will need to enable plugin unconditionally.  This
94338fd1498Szrj    still cause problems with PLUGIN_LD != LD and when plugin is built but
94438fd1498Szrj    not useable.  For GCC 4.6 we don't support slim LTO and thus we can enable
94538fd1498Szrj    plugin only when LTO is enabled.  We still honor explicit
94638fd1498Szrj    -fuse-linker-plugin if the linker used understands -plugin.  */
94738fd1498Szrj 
94838fd1498Szrj /* The linker has some plugin support.  */
94938fd1498Szrj #if HAVE_LTO_PLUGIN > 0
95038fd1498Szrj /* The linker used has full plugin support, use LTO plugin by default.  */
95138fd1498Szrj #if HAVE_LTO_PLUGIN == 2
95238fd1498Szrj #define PLUGIN_COND "!fno-use-linker-plugin:%{!fno-lto"
95338fd1498Szrj #define PLUGIN_COND_CLOSE "}"
95438fd1498Szrj #else
95538fd1498Szrj /* The linker used has limited plugin support, use LTO plugin with explicit
95638fd1498Szrj    -fuse-linker-plugin.  */
95738fd1498Szrj #define PLUGIN_COND "fuse-linker-plugin"
95838fd1498Szrj #define PLUGIN_COND_CLOSE ""
95938fd1498Szrj #endif
96038fd1498Szrj #define LINK_PLUGIN_SPEC \
96138fd1498Szrj     "%{" PLUGIN_COND": \
96238fd1498Szrj     -plugin %(linker_plugin_file) \
96338fd1498Szrj     -plugin-opt=%(lto_wrapper) \
96438fd1498Szrj     -plugin-opt=-fresolution=%u.res \
96538fd1498Szrj     %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
96638fd1498Szrj     }" PLUGIN_COND_CLOSE
96738fd1498Szrj #else
96838fd1498Szrj /* The linker used doesn't support -plugin, reject -fuse-linker-plugin.  */
96938fd1498Szrj #define LINK_PLUGIN_SPEC "%{fuse-linker-plugin:\
97038fd1498Szrj     %e-fuse-linker-plugin is not supported in this configuration}"
97138fd1498Szrj #endif
97238fd1498Szrj 
97338fd1498Szrj /* Linker command line options for -fsanitize= early on the command line.  */
97438fd1498Szrj #ifndef SANITIZER_EARLY_SPEC
97538fd1498Szrj #define SANITIZER_EARLY_SPEC "\
97638fd1498Szrj %{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
97738fd1498Szrj     %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \
97838fd1498Szrj     %{%:sanitize(leak):" LIBLSAN_EARLY_SPEC "}}}"
97938fd1498Szrj #endif
98038fd1498Szrj 
98138fd1498Szrj /* Linker command line options for -fsanitize= late on the command line.  */
98238fd1498Szrj #ifndef SANITIZER_SPEC
98338fd1498Szrj #define SANITIZER_SPEC "\
98438fd1498Szrj %{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\
98538fd1498Szrj     %{static:%ecannot specify -static with -fsanitize=address}}\
98638fd1498Szrj     %{%:sanitize(thread):" LIBTSAN_SPEC "\
98738fd1498Szrj     %{static:%ecannot specify -static with -fsanitize=thread}}\
98838fd1498Szrj     %{%:sanitize(undefined):" LIBUBSAN_SPEC "}\
98938fd1498Szrj     %{%:sanitize(leak):" LIBLSAN_SPEC "}}}"
99038fd1498Szrj #endif
99138fd1498Szrj 
99238fd1498Szrj #ifndef POST_LINK_SPEC
99338fd1498Szrj #define POST_LINK_SPEC ""
99438fd1498Szrj #endif
99538fd1498Szrj 
99638fd1498Szrj /*  This is the spec to use, once the code for creating the vtable
99738fd1498Szrj     verification runtime library, libvtv.so, has been created.  Currently
99838fd1498Szrj     the vtable verification runtime functions are in libstdc++, so we use
99938fd1498Szrj     the spec just below this one.  */
100038fd1498Szrj #ifndef VTABLE_VERIFICATION_SPEC
100138fd1498Szrj #if ENABLE_VTABLE_VERIFY
100238fd1498Szrj #define VTABLE_VERIFICATION_SPEC "\
100338fd1498Szrj %{!nostdlib:%{fvtable-verify=std: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}\
100438fd1498Szrj     %{fvtable-verify=preinit: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}}"
100538fd1498Szrj #else
100638fd1498Szrj #define VTABLE_VERIFICATION_SPEC "\
100738fd1498Szrj %{fvtable-verify=none:} \
100838fd1498Szrj %{fvtable-verify=std: \
100938fd1498Szrj   %e-fvtable-verify=std is not supported in this configuration} \
101038fd1498Szrj %{fvtable-verify=preinit: \
101138fd1498Szrj   %e-fvtable-verify=preinit is not supported in this configuration}"
101238fd1498Szrj #endif
101338fd1498Szrj #endif
101438fd1498Szrj 
101538fd1498Szrj #ifndef CHKP_SPEC
101638fd1498Szrj #define CHKP_SPEC ""
101738fd1498Szrj #endif
101838fd1498Szrj 
101938fd1498Szrj /* -u* was put back because both BSD and SysV seem to support it.  */
102038fd1498Szrj /* %{static|no-pie|static-pie:} simply prevents an error message:
102138fd1498Szrj    1. If the target machine doesn't handle -static.
102238fd1498Szrj    2. If PIE isn't enabled by default.
102338fd1498Szrj    3. If the target machine doesn't handle -static-pie.
102438fd1498Szrj  */
102538fd1498Szrj /* We want %{T*} after %{L*} and %D so that it can be used to specify linker
102638fd1498Szrj    scripts which exist in user specified directories, or in standard
102738fd1498Szrj    directories.  */
102838fd1498Szrj /* We pass any -flto flags on to the linker, which is expected
102938fd1498Szrj    to understand them.  In practice, this means it had better be collect2.  */
103038fd1498Szrj /* %{e*} includes -export-dynamic; see comment in common.opt.  */
103138fd1498Szrj #ifndef LINK_COMMAND_SPEC
103238fd1498Szrj #define LINK_COMMAND_SPEC "\
103338fd1498Szrj %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
103438fd1498Szrj     %(linker) " \
103538fd1498Szrj     LINK_PLUGIN_SPEC \
103638fd1498Szrj    "%{flto|flto=*:%<fcompare-debug*} \
103738fd1498Szrj     %{flto} %{fno-lto} %{flto=*} %l " LINK_PIE_SPEC \
103838fd1498Szrj    "%{fuse-ld=*:-fuse-ld=%*} " LINK_COMPRESS_DEBUG_SPEC \
103938fd1498Szrj    "%X %{o*} %{e*} %{N} %{n} %{r}\
104038fd1498Szrj     %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} \
104138fd1498Szrj     %{static|no-pie|static-pie:} %{L*} %(mfwrap) %(link_libgcc) " \
104238fd1498Szrj     VTABLE_VERIFICATION_SPEC " " SANITIZER_EARLY_SPEC " %o " CHKP_SPEC " \
104338fd1498Szrj     %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1):\
104438fd1498Szrj 	%:include(libgomp.spec)%(link_gomp)}\
104538fd1498Szrj     %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
104638fd1498Szrj     %(mflib) " STACK_SPLIT_SPEC "\
104738fd1498Szrj     %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} " SANITIZER_SPEC " \
104838fd1498Szrj     %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
104938fd1498Szrj     %{!nostdlib:%{!nostartfiles:%E}} %{T*}  \n%(post_link) }}}}}}"
105038fd1498Szrj #endif
105138fd1498Szrj 
105238fd1498Szrj #ifndef LINK_LIBGCC_SPEC
105338fd1498Szrj /* Generate -L options for startfile prefix list.  */
105438fd1498Szrj # define LINK_LIBGCC_SPEC "%D"
105538fd1498Szrj #endif
105638fd1498Szrj 
105738fd1498Szrj #ifndef STARTFILE_PREFIX_SPEC
105838fd1498Szrj # define STARTFILE_PREFIX_SPEC ""
105938fd1498Szrj #endif
106038fd1498Szrj 
106138fd1498Szrj #ifndef SYSROOT_SPEC
106238fd1498Szrj # define SYSROOT_SPEC "--sysroot=%R"
106338fd1498Szrj #endif
106438fd1498Szrj 
106538fd1498Szrj #ifndef SYSROOT_SUFFIX_SPEC
106638fd1498Szrj # define SYSROOT_SUFFIX_SPEC ""
106738fd1498Szrj #endif
106838fd1498Szrj 
106938fd1498Szrj #ifndef SYSROOT_HEADERS_SUFFIX_SPEC
107038fd1498Szrj # define SYSROOT_HEADERS_SUFFIX_SPEC ""
107138fd1498Szrj #endif
107238fd1498Szrj 
107338fd1498Szrj static const char *asm_debug = ASM_DEBUG_SPEC;
107438fd1498Szrj static const char *cpp_spec = CPP_SPEC;
107538fd1498Szrj static const char *cc1_spec = CC1_SPEC;
107638fd1498Szrj static const char *cc1plus_spec = CC1PLUS_SPEC;
107738fd1498Szrj static const char *link_gcc_c_sequence_spec = LINK_GCC_C_SEQUENCE_SPEC;
107838fd1498Szrj static const char *link_ssp_spec = LINK_SSP_SPEC;
107938fd1498Szrj static const char *asm_spec = ASM_SPEC;
108038fd1498Szrj static const char *asm_final_spec = ASM_FINAL_SPEC;
108138fd1498Szrj static const char *link_spec = LINK_SPEC;
108238fd1498Szrj static const char *lib_spec = LIB_SPEC;
108338fd1498Szrj static const char *link_gomp_spec = "";
108438fd1498Szrj static const char *libgcc_spec = LIBGCC_SPEC;
108538fd1498Szrj static const char *endfile_spec = ENDFILE_SPEC;
108638fd1498Szrj static const char *startfile_spec = STARTFILE_SPEC;
108738fd1498Szrj static const char *linker_name_spec = LINKER_NAME;
108838fd1498Szrj static const char *linker_plugin_file_spec = "";
108938fd1498Szrj static const char *lto_wrapper_spec = "";
109038fd1498Szrj static const char *lto_gcc_spec = "";
109138fd1498Szrj static const char *post_link_spec = POST_LINK_SPEC;
109238fd1498Szrj static const char *link_command_spec = LINK_COMMAND_SPEC;
109338fd1498Szrj static const char *link_libgcc_spec = LINK_LIBGCC_SPEC;
109438fd1498Szrj static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC;
109538fd1498Szrj static const char *sysroot_spec = SYSROOT_SPEC;
109638fd1498Szrj static const char *sysroot_suffix_spec = SYSROOT_SUFFIX_SPEC;
109738fd1498Szrj static const char *sysroot_hdrs_suffix_spec = SYSROOT_HEADERS_SUFFIX_SPEC;
109838fd1498Szrj static const char *self_spec = "";
109938fd1498Szrj 
110038fd1498Szrj /* Standard options to cpp, cc1, and as, to reduce duplication in specs.
110138fd1498Szrj    There should be no need to override these in target dependent files,
110238fd1498Szrj    but we need to copy them to the specs file so that newer versions
110338fd1498Szrj    of the GCC driver can correctly drive older tool chains with the
110438fd1498Szrj    appropriate -B options.  */
110538fd1498Szrj 
110638fd1498Szrj /* When cpplib handles traditional preprocessing, get rid of this, and
110738fd1498Szrj    call cc1 (or cc1obj in objc/lang-specs.h) from the main specs so
110838fd1498Szrj    that we default the front end language better.  */
110938fd1498Szrj static const char *trad_capable_cpp =
111038fd1498Szrj "cc1 -E %{traditional|traditional-cpp:-traditional-cpp}";
111138fd1498Szrj 
111238fd1498Szrj /* We don't wrap .d files in %W{} since a missing .d file, and
111338fd1498Szrj    therefore no dependency entry, confuses make into thinking a .o
111438fd1498Szrj    file that happens to exist is up-to-date.  */
111538fd1498Szrj static const char *cpp_unique_options =
111638fd1498Szrj "%{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I\
111738fd1498Szrj  %{MD:-MD %{!o:%b.d}%{o*:%.d%*}}\
111838fd1498Szrj  %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\
111938fd1498Szrj  %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
112038fd1498Szrj  %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}}\
112138fd1498Szrj  %{remap} %{g3|ggdb3|gstabs3|gxcoff3|gvms3:-dD}\
112238fd1498Szrj  %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
112338fd1498Szrj  %{H} %C %{D*&U*&A*} %{i*} %Z %i\
112438fd1498Szrj  %{E|M|MM:%W{o*}}";
112538fd1498Szrj 
112638fd1498Szrj /* This contains cpp options which are common with cc1_options and are passed
112738fd1498Szrj    only when preprocessing only to avoid duplication.  We pass the cc1 spec
112838fd1498Szrj    options to the preprocessor so that it the cc1 spec may manipulate
112938fd1498Szrj    options used to set target flags.  Those special target flags settings may
113038fd1498Szrj    in turn cause preprocessor symbols to be defined specially.  */
113138fd1498Szrj static const char *cpp_options =
113238fd1498Szrj "%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w}\
113338fd1498Szrj  %{f*} %{g*:%{%:debug-level-gt(0):%{g*}\
113438fd1498Szrj  %{!fno-working-directory:-fworking-directory}}} %{O*}\
113538fd1498Szrj  %{undef} %{save-temps*:-fpch-preprocess}";
113638fd1498Szrj 
113738fd1498Szrj /* This contains cpp options which are not passed when the preprocessor
113838fd1498Szrj    output will be used by another program.  */
113938fd1498Szrj static const char *cpp_debug_options = "%{d*}";
114038fd1498Szrj 
114138fd1498Szrj /* NB: This is shared amongst all front-ends, except for Ada.  */
114238fd1498Szrj static const char *cc1_options =
114338fd1498Szrj "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
114438fd1498Szrj  %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
114538fd1498Szrj  %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
114638fd1498Szrj  %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
114738fd1498Szrj  %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
114838fd1498Szrj  %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
114938fd1498Szrj  %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
115038fd1498Szrj  %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
115138fd1498Szrj  %{-target-help:--target-help}\
115238fd1498Szrj  %{-version:--version}\
115338fd1498Szrj  %{-help=*:--help=%*}\
115438fd1498Szrj  %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
115538fd1498Szrj  %{fsyntax-only:-o %j} %{-param*}\
115638fd1498Szrj  %{coverage:-fprofile-arcs -ftest-coverage}\
115738fd1498Szrj  %{fprofile-arcs|fprofile-generate*|coverage:\
115838fd1498Szrj    %{!fprofile-update=single:\
115938fd1498Szrj      %{pthread:-fprofile-update=prefer-atomic}}}";
116038fd1498Szrj 
116138fd1498Szrj static const char *asm_options =
116238fd1498Szrj "%{-target-help:%:print-asm-header()} "
116338fd1498Szrj #if HAVE_GNU_AS
116438fd1498Szrj /* If GNU AS is used, then convert -w (no warnings), -I, and -v
116538fd1498Szrj    to the assembler equivalents.  */
116638fd1498Szrj "%{v} %{w:-W} %{I*} "
116738fd1498Szrj #endif
116838fd1498Szrj ASM_COMPRESS_DEBUG_SPEC
116938fd1498Szrj "%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}";
117038fd1498Szrj 
117138fd1498Szrj static const char *invoke_as =
117238fd1498Szrj #ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
117338fd1498Szrj "%{!fwpa*:\
117438fd1498Szrj    %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
117538fd1498Szrj    %{!S:-o %|.s |\n as %(asm_options) %|.s %A }\
117638fd1498Szrj   }";
117738fd1498Szrj #else
117838fd1498Szrj "%{!fwpa*:\
117938fd1498Szrj    %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
118038fd1498Szrj    %{!S:-o %|.s |\n as %(asm_options) %m.s %A }\
118138fd1498Szrj   }";
118238fd1498Szrj #endif
118338fd1498Szrj 
118438fd1498Szrj /* Some compilers have limits on line lengths, and the multilib_select
118538fd1498Szrj    and/or multilib_matches strings can be very long, so we build them at
118638fd1498Szrj    run time.  */
118738fd1498Szrj static struct obstack multilib_obstack;
118838fd1498Szrj static const char *multilib_select;
118938fd1498Szrj static const char *multilib_matches;
119038fd1498Szrj static const char *multilib_defaults;
119138fd1498Szrj static const char *multilib_exclusions;
119238fd1498Szrj static const char *multilib_reuse;
119338fd1498Szrj 
119438fd1498Szrj /* Check whether a particular argument is a default argument.  */
119538fd1498Szrj 
119638fd1498Szrj #ifndef MULTILIB_DEFAULTS
119738fd1498Szrj #define MULTILIB_DEFAULTS { "" }
119838fd1498Szrj #endif
119938fd1498Szrj 
120038fd1498Szrj static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
120138fd1498Szrj 
120238fd1498Szrj #ifndef DRIVER_SELF_SPECS
120338fd1498Szrj #define DRIVER_SELF_SPECS ""
120438fd1498Szrj #endif
120538fd1498Szrj 
120638fd1498Szrj /* Linking to libgomp implies pthreads.  This is particularly important
120738fd1498Szrj    for targets that use different start files and suchlike.  */
120838fd1498Szrj #ifndef GOMP_SELF_SPECS
120938fd1498Szrj #define GOMP_SELF_SPECS \
121038fd1498Szrj   "%{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1): " \
121138fd1498Szrj   "-pthread}"
121238fd1498Szrj #endif
121338fd1498Szrj 
121438fd1498Szrj /* Likewise for -fgnu-tm.  */
121538fd1498Szrj #ifndef GTM_SELF_SPECS
121638fd1498Szrj #define GTM_SELF_SPECS "%{fgnu-tm: -pthread}"
121738fd1498Szrj #endif
121838fd1498Szrj 
121938fd1498Szrj static const char *const driver_self_specs[] = {
122038fd1498Szrj   "%{fdump-final-insns:-fdump-final-insns=.} %<fdump-final-insns",
122138fd1498Szrj   DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS, GTM_SELF_SPECS
122238fd1498Szrj };
122338fd1498Szrj 
122438fd1498Szrj #ifndef OPTION_DEFAULT_SPECS
122538fd1498Szrj #define OPTION_DEFAULT_SPECS { "", "" }
122638fd1498Szrj #endif
122738fd1498Szrj 
122838fd1498Szrj struct default_spec
122938fd1498Szrj {
123038fd1498Szrj   const char *name;
123138fd1498Szrj   const char *spec;
123238fd1498Szrj };
123338fd1498Szrj 
123438fd1498Szrj static const struct default_spec
123538fd1498Szrj   option_default_specs[] = { OPTION_DEFAULT_SPECS };
123638fd1498Szrj 
123738fd1498Szrj struct user_specs
123838fd1498Szrj {
123938fd1498Szrj   struct user_specs *next;
124038fd1498Szrj   const char *filename;
124138fd1498Szrj };
124238fd1498Szrj 
124338fd1498Szrj static struct user_specs *user_specs_head, *user_specs_tail;
124438fd1498Szrj 
124538fd1498Szrj 
124638fd1498Szrj /* Record the mapping from file suffixes for compilation specs.  */
124738fd1498Szrj 
124838fd1498Szrj struct compiler
124938fd1498Szrj {
125038fd1498Szrj   const char *suffix;		/* Use this compiler for input files
125138fd1498Szrj 				   whose names end in this suffix.  */
125238fd1498Szrj 
125338fd1498Szrj   const char *spec;		/* To use this compiler, run this spec.  */
125438fd1498Szrj 
125538fd1498Szrj   const char *cpp_spec;         /* If non-NULL, substitute this spec
125638fd1498Szrj 				   for `%C', rather than the usual
125738fd1498Szrj 				   cpp_spec.  */
125838fd1498Szrj   int combinable;               /* If nonzero, compiler can deal with
125938fd1498Szrj 				    multiple source files at once (IMA).  */
126038fd1498Szrj   int needs_preprocessing;       /* If nonzero, source files need to
126138fd1498Szrj 				    be run through a preprocessor.  */
126238fd1498Szrj };
126338fd1498Szrj 
126438fd1498Szrj /* Pointer to a vector of `struct compiler' that gives the spec for
126538fd1498Szrj    compiling a file, based on its suffix.
126638fd1498Szrj    A file that does not end in any of these suffixes will be passed
126738fd1498Szrj    unchanged to the loader and nothing else will be done to it.
126838fd1498Szrj 
126938fd1498Szrj    An entry containing two 0s is used to terminate the vector.
127038fd1498Szrj 
127138fd1498Szrj    If multiple entries match a file, the last matching one is used.  */
127238fd1498Szrj 
127338fd1498Szrj static struct compiler *compilers;
127438fd1498Szrj 
127538fd1498Szrj /* Number of entries in `compilers', not counting the null terminator.  */
127638fd1498Szrj 
127738fd1498Szrj static int n_compilers;
127838fd1498Szrj 
127938fd1498Szrj /* The default list of file name suffixes and their compilation specs.  */
128038fd1498Szrj 
128138fd1498Szrj static const struct compiler default_compilers[] =
128238fd1498Szrj {
128338fd1498Szrj   /* Add lists of suffixes of known languages here.  If those languages
128438fd1498Szrj      were not present when we built the driver, we will hit these copies
128538fd1498Szrj      and be given a more meaningful error than "file not used since
128638fd1498Szrj      linking is not done".  */
128738fd1498Szrj   {".m",  "#Objective-C", 0, 0, 0}, {".mi",  "#Objective-C", 0, 0, 0},
128838fd1498Szrj   {".mm", "#Objective-C++", 0, 0, 0}, {".M", "#Objective-C++", 0, 0, 0},
128938fd1498Szrj   {".mii", "#Objective-C++", 0, 0, 0},
129038fd1498Szrj   {".cc", "#C++", 0, 0, 0}, {".cxx", "#C++", 0, 0, 0},
129138fd1498Szrj   {".cpp", "#C++", 0, 0, 0}, {".cp", "#C++", 0, 0, 0},
129238fd1498Szrj   {".c++", "#C++", 0, 0, 0}, {".C", "#C++", 0, 0, 0},
129338fd1498Szrj   {".CPP", "#C++", 0, 0, 0}, {".ii", "#C++", 0, 0, 0},
129438fd1498Szrj   {".ads", "#Ada", 0, 0, 0}, {".adb", "#Ada", 0, 0, 0},
129538fd1498Szrj   {".f", "#Fortran", 0, 0, 0}, {".F", "#Fortran", 0, 0, 0},
129638fd1498Szrj   {".for", "#Fortran", 0, 0, 0}, {".FOR", "#Fortran", 0, 0, 0},
129738fd1498Szrj   {".ftn", "#Fortran", 0, 0, 0}, {".FTN", "#Fortran", 0, 0, 0},
129838fd1498Szrj   {".fpp", "#Fortran", 0, 0, 0}, {".FPP", "#Fortran", 0, 0, 0},
129938fd1498Szrj   {".f90", "#Fortran", 0, 0, 0}, {".F90", "#Fortran", 0, 0, 0},
130038fd1498Szrj   {".f95", "#Fortran", 0, 0, 0}, {".F95", "#Fortran", 0, 0, 0},
130138fd1498Szrj   {".f03", "#Fortran", 0, 0, 0}, {".F03", "#Fortran", 0, 0, 0},
130238fd1498Szrj   {".f08", "#Fortran", 0, 0, 0}, {".F08", "#Fortran", 0, 0, 0},
130338fd1498Szrj   {".r", "#Ratfor", 0, 0, 0},
130438fd1498Szrj   {".go", "#Go", 0, 1, 0},
130538fd1498Szrj   /* Next come the entries for C.  */
130638fd1498Szrj   {".c", "@c", 0, 0, 1},
130738fd1498Szrj   {"@c",
130838fd1498Szrj    /* cc1 has an integrated ISO C preprocessor.  We should invoke the
130938fd1498Szrj       external preprocessor if -save-temps is given.  */
131038fd1498Szrj      "%{E|M|MM:%(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)}\
131138fd1498Szrj       %{!E:%{!M:%{!MM:\
131238fd1498Szrj           %{traditional:\
131338fd1498Szrj %eGNU C no longer supports -traditional without -E}\
131438fd1498Szrj       %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
131538fd1498Szrj 	  %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
131638fd1498Szrj 	    cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
131738fd1498Szrj 	  %(cc1_options)}\
131838fd1498Szrj       %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
131938fd1498Szrj 	  cc1 %(cpp_unique_options) %(cc1_options)}}}\
132038fd1498Szrj       %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 1},
132138fd1498Szrj   {"-",
132238fd1498Szrj    "%{!E:%e-E or -x required when input is from standard input}\
132338fd1498Szrj     %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0, 0, 0},
132438fd1498Szrj   {".h", "@c-header", 0, 0, 0},
132538fd1498Szrj   {"@c-header",
132638fd1498Szrj    /* cc1 has an integrated ISO C preprocessor.  We should invoke the
132738fd1498Szrj       external preprocessor if -save-temps is given.  */
132838fd1498Szrj      "%{E|M|MM:%(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)}\
132938fd1498Szrj       %{!E:%{!M:%{!MM:\
133038fd1498Szrj 	  %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
133138fd1498Szrj 		%(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
133238fd1498Szrj 		    cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
133338fd1498Szrj 			%(cc1_options)\
133438fd1498Szrj 			%{!fsyntax-only:%{!S:-o %g.s} \
133538fd1498Szrj 			    %{!fdump-ada-spec*:%{!o*:--output-pch=%i.gch}\
133638fd1498Szrj 					       %W{o*:--output-pch=%*}}%V}}\
133738fd1498Szrj 	  %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
133838fd1498Szrj 		cc1 %(cpp_unique_options) %(cc1_options)\
133938fd1498Szrj 		    %{!fsyntax-only:%{!S:-o %g.s} \
134038fd1498Szrj 		        %{!fdump-ada-spec*:%{!o*:--output-pch=%i.gch}\
134138fd1498Szrj 					   %W{o*:--output-pch=%*}}%V}}}}}}}", 0, 0, 0},
134238fd1498Szrj   {".i", "@cpp-output", 0, 0, 0},
134338fd1498Szrj   {"@cpp-output",
134438fd1498Szrj    "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0},
134538fd1498Szrj   {".s", "@assembler", 0, 0, 0},
134638fd1498Szrj   {"@assembler",
134738fd1498Szrj    "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0, 0, 0},
134838fd1498Szrj   {".sx", "@assembler-with-cpp", 0, 0, 0},
134938fd1498Szrj   {".S", "@assembler-with-cpp", 0, 0, 0},
135038fd1498Szrj   {"@assembler-with-cpp",
135138fd1498Szrj #ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
135238fd1498Szrj    "%(trad_capable_cpp) -lang-asm %(cpp_options) -fno-directives-only\
135338fd1498Szrj       %{E|M|MM:%(cpp_debug_options)}\
135438fd1498Szrj       %{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\
135538fd1498Szrj        as %(asm_debug) %(asm_options) %|.s %A }}}}"
135638fd1498Szrj #else
135738fd1498Szrj    "%(trad_capable_cpp) -lang-asm %(cpp_options) -fno-directives-only\
135838fd1498Szrj       %{E|M|MM:%(cpp_debug_options)}\
135938fd1498Szrj       %{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\
136038fd1498Szrj        as %(asm_debug) %(asm_options) %m.s %A }}}}"
136138fd1498Szrj #endif
136238fd1498Szrj    , 0, 0, 0},
136338fd1498Szrj 
136438fd1498Szrj #include "specs.h"
136538fd1498Szrj   /* Mark end of table.  */
136638fd1498Szrj   {0, 0, 0, 0, 0}
136738fd1498Szrj };
136838fd1498Szrj 
136938fd1498Szrj /* Number of elements in default_compilers, not counting the terminator.  */
137038fd1498Szrj 
137138fd1498Szrj static const int n_default_compilers = ARRAY_SIZE (default_compilers) - 1;
137238fd1498Szrj 
137338fd1498Szrj typedef char *char_p; /* For DEF_VEC_P.  */
137438fd1498Szrj 
137538fd1498Szrj /* A vector of options to give to the linker.
137638fd1498Szrj    These options are accumulated by %x,
137738fd1498Szrj    and substituted into the linker command with %X.  */
137838fd1498Szrj static vec<char_p> linker_options;
137938fd1498Szrj 
138038fd1498Szrj /* A vector of options to give to the assembler.
138138fd1498Szrj    These options are accumulated by -Wa,
138238fd1498Szrj    and substituted into the assembler command with %Y.  */
138338fd1498Szrj static vec<char_p> assembler_options;
138438fd1498Szrj 
138538fd1498Szrj /* A vector of options to give to the preprocessor.
138638fd1498Szrj    These options are accumulated by -Wp,
138738fd1498Szrj    and substituted into the preprocessor command with %Z.  */
138838fd1498Szrj static vec<char_p> preprocessor_options;
138938fd1498Szrj 
139038fd1498Szrj static char *
skip_whitespace(char * p)139138fd1498Szrj skip_whitespace (char *p)
139238fd1498Szrj {
139338fd1498Szrj   while (1)
139438fd1498Szrj     {
139538fd1498Szrj       /* A fully-blank line is a delimiter in the SPEC file and shouldn't
139638fd1498Szrj 	 be considered whitespace.  */
139738fd1498Szrj       if (p[0] == '\n' && p[1] == '\n' && p[2] == '\n')
139838fd1498Szrj 	return p + 1;
139938fd1498Szrj       else if (*p == '\n' || *p == ' ' || *p == '\t')
140038fd1498Szrj 	p++;
140138fd1498Szrj       else if (*p == '#')
140238fd1498Szrj 	{
140338fd1498Szrj 	  while (*p != '\n')
140438fd1498Szrj 	    p++;
140538fd1498Szrj 	  p++;
140638fd1498Szrj 	}
140738fd1498Szrj       else
140838fd1498Szrj 	break;
140938fd1498Szrj     }
141038fd1498Szrj 
141138fd1498Szrj   return p;
141238fd1498Szrj }
141338fd1498Szrj /* Structures to keep track of prefixes to try when looking for files.  */
141438fd1498Szrj 
141538fd1498Szrj struct prefix_list
141638fd1498Szrj {
141738fd1498Szrj   const char *prefix;	      /* String to prepend to the path.  */
141838fd1498Szrj   struct prefix_list *next;   /* Next in linked list.  */
141938fd1498Szrj   int require_machine_suffix; /* Don't use without machine_suffix.  */
142038fd1498Szrj   /* 2 means try both machine_suffix and just_machine_suffix.  */
142138fd1498Szrj   int priority;		      /* Sort key - priority within list.  */
142238fd1498Szrj   int os_multilib;	      /* 1 if OS multilib scheme should be used,
142338fd1498Szrj 				 0 for GCC multilib scheme.  */
142438fd1498Szrj };
142538fd1498Szrj 
142638fd1498Szrj struct path_prefix
142738fd1498Szrj {
142838fd1498Szrj   struct prefix_list *plist;  /* List of prefixes to try */
142938fd1498Szrj   int max_len;                /* Max length of a prefix in PLIST */
143038fd1498Szrj   const char *name;           /* Name of this list (used in config stuff) */
143138fd1498Szrj };
143238fd1498Szrj 
143338fd1498Szrj /* List of prefixes to try when looking for executables.  */
143438fd1498Szrj 
143538fd1498Szrj static struct path_prefix exec_prefixes = { 0, 0, "exec" };
143638fd1498Szrj 
143738fd1498Szrj /* List of prefixes to try when looking for startup (crt0) files.  */
143838fd1498Szrj 
143938fd1498Szrj static struct path_prefix startfile_prefixes = { 0, 0, "startfile" };
144038fd1498Szrj 
144138fd1498Szrj /* List of prefixes to try when looking for include files.  */
144238fd1498Szrj 
144338fd1498Szrj static struct path_prefix include_prefixes = { 0, 0, "include" };
144438fd1498Szrj 
144538fd1498Szrj /* Suffix to attach to directories searched for commands.
144638fd1498Szrj    This looks like `MACHINE/VERSION/'.  */
144738fd1498Szrj 
144838fd1498Szrj static const char *machine_suffix = 0;
144938fd1498Szrj 
145038fd1498Szrj /* Suffix to attach to directories searched for commands.
145138fd1498Szrj    This is just `MACHINE/'.  */
145238fd1498Szrj 
145338fd1498Szrj static const char *just_machine_suffix = 0;
145438fd1498Szrj 
145538fd1498Szrj /* Adjusted value of GCC_EXEC_PREFIX envvar.  */
145638fd1498Szrj 
145738fd1498Szrj static const char *gcc_exec_prefix;
145838fd1498Szrj 
145938fd1498Szrj /* Adjusted value of standard_libexec_prefix.  */
146038fd1498Szrj 
146138fd1498Szrj static const char *gcc_libexec_prefix;
146238fd1498Szrj 
146338fd1498Szrj /* Default prefixes to attach to command names.  */
146438fd1498Szrj 
146538fd1498Szrj #ifndef STANDARD_STARTFILE_PREFIX_1
146638fd1498Szrj #define STANDARD_STARTFILE_PREFIX_1 "/lib/"
146738fd1498Szrj #endif
146838fd1498Szrj #ifndef STANDARD_STARTFILE_PREFIX_2
146938fd1498Szrj #define STANDARD_STARTFILE_PREFIX_2 "/usr/lib/"
147038fd1498Szrj #endif
147138fd1498Szrj 
147238fd1498Szrj #ifdef CROSS_DIRECTORY_STRUCTURE  /* Don't use these prefixes for a cross compiler.  */
147338fd1498Szrj #undef MD_EXEC_PREFIX
147438fd1498Szrj #undef MD_STARTFILE_PREFIX
147538fd1498Szrj #undef MD_STARTFILE_PREFIX_1
147638fd1498Szrj #endif
147738fd1498Szrj 
147838fd1498Szrj /* If no prefixes defined, use the null string, which will disable them.  */
147938fd1498Szrj #ifndef MD_EXEC_PREFIX
148038fd1498Szrj #define MD_EXEC_PREFIX ""
148138fd1498Szrj #endif
148238fd1498Szrj #ifndef MD_STARTFILE_PREFIX
148338fd1498Szrj #define MD_STARTFILE_PREFIX ""
148438fd1498Szrj #endif
148538fd1498Szrj #ifndef MD_STARTFILE_PREFIX_1
148638fd1498Szrj #define MD_STARTFILE_PREFIX_1 ""
148738fd1498Szrj #endif
148838fd1498Szrj 
148938fd1498Szrj /* These directories are locations set at configure-time based on the
149038fd1498Szrj    --prefix option provided to configure.  Their initializers are
149138fd1498Szrj    defined in Makefile.in.  These paths are not *directly* used when
149238fd1498Szrj    gcc_exec_prefix is set because, in that case, we know where the
149338fd1498Szrj    compiler has been installed, and use paths relative to that
149438fd1498Szrj    location instead.  */
149538fd1498Szrj static const char *const standard_exec_prefix = STANDARD_EXEC_PREFIX;
149638fd1498Szrj static const char *const standard_libexec_prefix = STANDARD_LIBEXEC_PREFIX;
149738fd1498Szrj static const char *const standard_bindir_prefix = STANDARD_BINDIR_PREFIX;
149838fd1498Szrj static const char *const standard_startfile_prefix = STANDARD_STARTFILE_PREFIX;
149938fd1498Szrj 
150038fd1498Szrj /* For native compilers, these are well-known paths containing
150138fd1498Szrj    components that may be provided by the system.  For cross
150238fd1498Szrj    compilers, these paths are not used.  */
150338fd1498Szrj static const char *md_exec_prefix = MD_EXEC_PREFIX;
150438fd1498Szrj static const char *md_startfile_prefix = MD_STARTFILE_PREFIX;
150538fd1498Szrj static const char *md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1;
150638fd1498Szrj static const char *const standard_startfile_prefix_1
150738fd1498Szrj   = STANDARD_STARTFILE_PREFIX_1;
150838fd1498Szrj static const char *const standard_startfile_prefix_2
150938fd1498Szrj   = STANDARD_STARTFILE_PREFIX_2;
151038fd1498Szrj 
151138fd1498Szrj /* A relative path to be used in finding the location of tools
151238fd1498Szrj    relative to the driver.  */
151338fd1498Szrj static const char *const tooldir_base_prefix = TOOLDIR_BASE_PREFIX;
151438fd1498Szrj 
151538fd1498Szrj /* A prefix to be used when this is an accelerator compiler.  */
151638fd1498Szrj static const char *const accel_dir_suffix = ACCEL_DIR_SUFFIX;
151738fd1498Szrj 
151838fd1498Szrj /* Subdirectory to use for locating libraries.  Set by
151938fd1498Szrj    set_multilib_dir based on the compilation options.  */
152038fd1498Szrj 
152138fd1498Szrj static const char *multilib_dir;
152238fd1498Szrj 
152338fd1498Szrj /* Subdirectory to use for locating libraries in OS conventions.  Set by
152438fd1498Szrj    set_multilib_dir based on the compilation options.  */
152538fd1498Szrj 
152638fd1498Szrj static const char *multilib_os_dir;
152738fd1498Szrj 
152838fd1498Szrj /* Subdirectory to use for locating libraries in multiarch conventions.  Set by
152938fd1498Szrj    set_multilib_dir based on the compilation options.  */
153038fd1498Szrj 
153138fd1498Szrj static const char *multiarch_dir;
153238fd1498Szrj 
153338fd1498Szrj /* Structure to keep track of the specs that have been defined so far.
153438fd1498Szrj    These are accessed using %(specname) in a compiler or link
153538fd1498Szrj    spec.  */
153638fd1498Szrj 
153738fd1498Szrj struct spec_list
153838fd1498Szrj {
153938fd1498Szrj 				/* The following 2 fields must be first */
154038fd1498Szrj 				/* to allow EXTRA_SPECS to be initialized */
154138fd1498Szrj   const char *name;		/* name of the spec.  */
154238fd1498Szrj   const char *ptr;		/* available ptr if no static pointer */
154338fd1498Szrj 
154438fd1498Szrj 				/* The following fields are not initialized */
154538fd1498Szrj 				/* by EXTRA_SPECS */
154638fd1498Szrj   const char **ptr_spec;	/* pointer to the spec itself.  */
154738fd1498Szrj   struct spec_list *next;	/* Next spec in linked list.  */
154838fd1498Szrj   int name_len;			/* length of the name */
154938fd1498Szrj   bool user_p;			/* whether string come from file spec.  */
155038fd1498Szrj   bool alloc_p;			/* whether string was allocated */
155138fd1498Szrj   const char *default_ptr;	/* The default value of *ptr_spec.  */
155238fd1498Szrj };
155338fd1498Szrj 
155438fd1498Szrj #define INIT_STATIC_SPEC(NAME,PTR) \
155538fd1498Szrj   { NAME, NULL, PTR, (struct spec_list *) 0, sizeof (NAME) - 1, false, false, \
155638fd1498Szrj     *PTR }
155738fd1498Szrj 
155838fd1498Szrj /* List of statically defined specs.  */
155938fd1498Szrj static struct spec_list static_specs[] =
156038fd1498Szrj {
156138fd1498Szrj   INIT_STATIC_SPEC ("asm",			&asm_spec),
156238fd1498Szrj   INIT_STATIC_SPEC ("asm_debug",		&asm_debug),
156338fd1498Szrj   INIT_STATIC_SPEC ("asm_final",		&asm_final_spec),
156438fd1498Szrj   INIT_STATIC_SPEC ("asm_options",		&asm_options),
156538fd1498Szrj   INIT_STATIC_SPEC ("invoke_as",		&invoke_as),
156638fd1498Szrj   INIT_STATIC_SPEC ("cpp",			&cpp_spec),
156738fd1498Szrj   INIT_STATIC_SPEC ("cpp_options",		&cpp_options),
156838fd1498Szrj   INIT_STATIC_SPEC ("cpp_debug_options",	&cpp_debug_options),
156938fd1498Szrj   INIT_STATIC_SPEC ("cpp_unique_options",	&cpp_unique_options),
157038fd1498Szrj   INIT_STATIC_SPEC ("trad_capable_cpp",		&trad_capable_cpp),
157138fd1498Szrj   INIT_STATIC_SPEC ("cc1",			&cc1_spec),
157238fd1498Szrj   INIT_STATIC_SPEC ("cc1_options",		&cc1_options),
157338fd1498Szrj   INIT_STATIC_SPEC ("cc1plus",			&cc1plus_spec),
157438fd1498Szrj   INIT_STATIC_SPEC ("link_gcc_c_sequence",	&link_gcc_c_sequence_spec),
157538fd1498Szrj   INIT_STATIC_SPEC ("link_ssp",			&link_ssp_spec),
157638fd1498Szrj   INIT_STATIC_SPEC ("endfile",			&endfile_spec),
157738fd1498Szrj   INIT_STATIC_SPEC ("link",			&link_spec),
157838fd1498Szrj   INIT_STATIC_SPEC ("lib",			&lib_spec),
157938fd1498Szrj   INIT_STATIC_SPEC ("link_gomp",		&link_gomp_spec),
158038fd1498Szrj   INIT_STATIC_SPEC ("libgcc",			&libgcc_spec),
158138fd1498Szrj   INIT_STATIC_SPEC ("startfile",		&startfile_spec),
158238fd1498Szrj   INIT_STATIC_SPEC ("cross_compile",		&cross_compile),
158338fd1498Szrj   INIT_STATIC_SPEC ("version",			&compiler_version),
158438fd1498Szrj   INIT_STATIC_SPEC ("multilib",			&multilib_select),
158538fd1498Szrj   INIT_STATIC_SPEC ("multilib_defaults",	&multilib_defaults),
158638fd1498Szrj   INIT_STATIC_SPEC ("multilib_extra",		&multilib_extra),
158738fd1498Szrj   INIT_STATIC_SPEC ("multilib_matches",		&multilib_matches),
158838fd1498Szrj   INIT_STATIC_SPEC ("multilib_exclusions",	&multilib_exclusions),
158938fd1498Szrj   INIT_STATIC_SPEC ("multilib_options",		&multilib_options),
159038fd1498Szrj   INIT_STATIC_SPEC ("multilib_reuse",		&multilib_reuse),
159138fd1498Szrj   INIT_STATIC_SPEC ("linker",			&linker_name_spec),
159238fd1498Szrj   INIT_STATIC_SPEC ("linker_plugin_file",	&linker_plugin_file_spec),
159338fd1498Szrj   INIT_STATIC_SPEC ("lto_wrapper",		&lto_wrapper_spec),
159438fd1498Szrj   INIT_STATIC_SPEC ("lto_gcc",			&lto_gcc_spec),
159538fd1498Szrj   INIT_STATIC_SPEC ("post_link",		&post_link_spec),
159638fd1498Szrj   INIT_STATIC_SPEC ("link_libgcc",		&link_libgcc_spec),
159738fd1498Szrj   INIT_STATIC_SPEC ("md_exec_prefix",		&md_exec_prefix),
159838fd1498Szrj   INIT_STATIC_SPEC ("md_startfile_prefix",	&md_startfile_prefix),
159938fd1498Szrj   INIT_STATIC_SPEC ("md_startfile_prefix_1",	&md_startfile_prefix_1),
160038fd1498Szrj   INIT_STATIC_SPEC ("startfile_prefix_spec",	&startfile_prefix_spec),
160138fd1498Szrj   INIT_STATIC_SPEC ("sysroot_spec",             &sysroot_spec),
160238fd1498Szrj   INIT_STATIC_SPEC ("sysroot_suffix_spec",	&sysroot_suffix_spec),
160338fd1498Szrj   INIT_STATIC_SPEC ("sysroot_hdrs_suffix_spec",	&sysroot_hdrs_suffix_spec),
160438fd1498Szrj   INIT_STATIC_SPEC ("self_spec",		&self_spec),
160538fd1498Szrj };
160638fd1498Szrj 
160738fd1498Szrj #ifdef EXTRA_SPECS		/* additional specs needed */
160838fd1498Szrj /* Structure to keep track of just the first two args of a spec_list.
160938fd1498Szrj    That is all that the EXTRA_SPECS macro gives us.  */
161038fd1498Szrj struct spec_list_1
161138fd1498Szrj {
161238fd1498Szrj   const char *const name;
161338fd1498Szrj   const char *const ptr;
161438fd1498Szrj };
161538fd1498Szrj 
161638fd1498Szrj static const struct spec_list_1 extra_specs_1[] = { EXTRA_SPECS };
161738fd1498Szrj static struct spec_list *extra_specs = (struct spec_list *) 0;
161838fd1498Szrj #endif
161938fd1498Szrj 
162038fd1498Szrj /* List of dynamically allocates specs that have been defined so far.  */
162138fd1498Szrj 
162238fd1498Szrj static struct spec_list *specs = (struct spec_list *) 0;
162338fd1498Szrj 
162438fd1498Szrj /* List of static spec functions.  */
162538fd1498Szrj 
162638fd1498Szrj static const struct spec_function static_spec_functions[] =
162738fd1498Szrj {
162838fd1498Szrj   { "getenv",                   getenv_spec_function },
162938fd1498Szrj   { "if-exists",		if_exists_spec_function },
163038fd1498Szrj   { "if-exists-else",		if_exists_else_spec_function },
163138fd1498Szrj   { "sanitize",			sanitize_spec_function },
163238fd1498Szrj   { "replace-outfile",		replace_outfile_spec_function },
163338fd1498Szrj   { "remove-outfile",		remove_outfile_spec_function },
163438fd1498Szrj   { "version-compare",		version_compare_spec_function },
163538fd1498Szrj   { "include",			include_spec_function },
163638fd1498Szrj   { "find-file",		find_file_spec_function },
163738fd1498Szrj   { "find-plugindir",		find_plugindir_spec_function },
163838fd1498Szrj   { "print-asm-header",		print_asm_header_spec_function },
163938fd1498Szrj   { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
164038fd1498Szrj   { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
164138fd1498Szrj   { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
164238fd1498Szrj   { "pass-through-libs",	pass_through_libs_spec_func },
164338fd1498Szrj   { "replace-extension",	replace_extension_spec_func },
164438fd1498Szrj   { "gt",			greater_than_spec_func },
164538fd1498Szrj   { "debug-level-gt",		debug_level_greater_than_spec_func },
164638fd1498Szrj #ifdef EXTRA_SPEC_FUNCTIONS
164738fd1498Szrj   EXTRA_SPEC_FUNCTIONS
164838fd1498Szrj #endif
164938fd1498Szrj   { 0, 0 }
165038fd1498Szrj };
165138fd1498Szrj 
165238fd1498Szrj static int processing_spec_function;
165338fd1498Szrj 
165438fd1498Szrj /* Add appropriate libgcc specs to OBSTACK, taking into account
165538fd1498Szrj    various permutations of -shared-libgcc, -shared, and such.  */
165638fd1498Szrj 
165738fd1498Szrj #if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC)
165838fd1498Szrj 
165938fd1498Szrj #ifndef USE_LD_AS_NEEDED
166038fd1498Szrj #define USE_LD_AS_NEEDED 0
166138fd1498Szrj #endif
166238fd1498Szrj 
166338fd1498Szrj static void
init_gcc_specs(struct obstack * obstack,const char * shared_name,const char * static_name,const char * eh_name)166438fd1498Szrj init_gcc_specs (struct obstack *obstack, const char *shared_name,
166538fd1498Szrj 		const char *static_name, const char *eh_name)
166638fd1498Szrj {
166738fd1498Szrj   char *buf;
166838fd1498Szrj 
166938fd1498Szrj #if USE_LD_AS_NEEDED
167038fd1498Szrj   buf = concat ("%{static|static-libgcc|static-pie:", static_name, " ", eh_name, "}"
167138fd1498Szrj 		"%{!static:%{!static-libgcc:%{!static-pie:"
167238fd1498Szrj 		"%{!shared-libgcc:",
167338fd1498Szrj 		static_name, " " LD_AS_NEEDED_OPTION " ",
167438fd1498Szrj 		shared_name, " " LD_NO_AS_NEEDED_OPTION
167538fd1498Szrj 		"}"
167638fd1498Szrj 		"%{shared-libgcc:",
167738fd1498Szrj 		shared_name, "%{!shared: ", static_name, "}"
167838fd1498Szrj 		"}}"
167938fd1498Szrj #else
168038fd1498Szrj   buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name, "}"
168138fd1498Szrj 		"%{!static:%{!static-libgcc:"
168238fd1498Szrj 		"%{!shared:"
168338fd1498Szrj 		"%{!shared-libgcc:", static_name, " ", eh_name, "}"
168438fd1498Szrj 		"%{shared-libgcc:", shared_name, " ", static_name, "}"
168538fd1498Szrj 		"}"
168638fd1498Szrj #ifdef LINK_EH_SPEC
168738fd1498Szrj 		"%{shared:"
168838fd1498Szrj 		"%{shared-libgcc:", shared_name, "}"
168938fd1498Szrj 		"%{!shared-libgcc:", static_name, "}"
169038fd1498Szrj 		"}"
169138fd1498Szrj #else
169238fd1498Szrj 		"%{shared:", shared_name, "}"
169338fd1498Szrj #endif
169438fd1498Szrj #endif
169538fd1498Szrj 		"}}", NULL);
169638fd1498Szrj 
169738fd1498Szrj   obstack_grow (obstack, buf, strlen (buf));
169838fd1498Szrj   free (buf);
169938fd1498Szrj }
170038fd1498Szrj #endif /* ENABLE_SHARED_LIBGCC */
170138fd1498Szrj 
170238fd1498Szrj /* Initialize the specs lookup routines.  */
170338fd1498Szrj 
170438fd1498Szrj static void
init_spec(void)170538fd1498Szrj init_spec (void)
170638fd1498Szrj {
170738fd1498Szrj   struct spec_list *next = (struct spec_list *) 0;
170838fd1498Szrj   struct spec_list *sl   = (struct spec_list *) 0;
170938fd1498Szrj   int i;
171038fd1498Szrj 
171138fd1498Szrj   if (specs)
171238fd1498Szrj     return;			/* Already initialized.  */
171338fd1498Szrj 
171438fd1498Szrj   if (verbose_flag)
171538fd1498Szrj     fnotice (stderr, "Using built-in specs.\n");
171638fd1498Szrj 
171738fd1498Szrj #ifdef EXTRA_SPECS
171838fd1498Szrj   extra_specs = XCNEWVEC (struct spec_list, ARRAY_SIZE (extra_specs_1));
171938fd1498Szrj 
172038fd1498Szrj   for (i = ARRAY_SIZE (extra_specs_1) - 1; i >= 0; i--)
172138fd1498Szrj     {
172238fd1498Szrj       sl = &extra_specs[i];
172338fd1498Szrj       sl->name = extra_specs_1[i].name;
172438fd1498Szrj       sl->ptr = extra_specs_1[i].ptr;
172538fd1498Szrj       sl->next = next;
172638fd1498Szrj       sl->name_len = strlen (sl->name);
172738fd1498Szrj       sl->ptr_spec = &sl->ptr;
172838fd1498Szrj       gcc_assert (sl->ptr_spec != NULL);
172938fd1498Szrj       sl->default_ptr = sl->ptr;
173038fd1498Szrj       next = sl;
173138fd1498Szrj     }
173238fd1498Szrj #endif
173338fd1498Szrj 
173438fd1498Szrj   for (i = ARRAY_SIZE (static_specs) - 1; i >= 0; i--)
173538fd1498Szrj     {
173638fd1498Szrj       sl = &static_specs[i];
173738fd1498Szrj       sl->next = next;
173838fd1498Szrj       next = sl;
173938fd1498Szrj     }
174038fd1498Szrj 
174138fd1498Szrj #if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC)
174238fd1498Szrj   /* ??? If neither -shared-libgcc nor --static-libgcc was
174338fd1498Szrj      seen, then we should be making an educated guess.  Some proposed
174438fd1498Szrj      heuristics for ELF include:
174538fd1498Szrj 
174638fd1498Szrj 	(1) If "-Wl,--export-dynamic", then it's a fair bet that the
174738fd1498Szrj 	    program will be doing dynamic loading, which will likely
174838fd1498Szrj 	    need the shared libgcc.
174938fd1498Szrj 
175038fd1498Szrj 	(2) If "-ldl", then it's also a fair bet that we're doing
175138fd1498Szrj 	    dynamic loading.
175238fd1498Szrj 
175338fd1498Szrj 	(3) For each ET_DYN we're linking against (either through -lfoo
175438fd1498Szrj 	    or /some/path/foo.so), check to see whether it or one of
175538fd1498Szrj 	    its dependencies depends on a shared libgcc.
175638fd1498Szrj 
175738fd1498Szrj 	(4) If "-shared"
175838fd1498Szrj 
175938fd1498Szrj 	    If the runtime is fixed to look for program headers instead
176038fd1498Szrj 	    of calling __register_frame_info at all, for each object,
176138fd1498Szrj 	    use the shared libgcc if any EH symbol referenced.
176238fd1498Szrj 
176338fd1498Szrj 	    If crtstuff is fixed to not invoke __register_frame_info
176438fd1498Szrj 	    automatically, for each object, use the shared libgcc if
176538fd1498Szrj 	    any non-empty unwind section found.
176638fd1498Szrj 
176738fd1498Szrj      Doing any of this probably requires invoking an external program to
176838fd1498Szrj      do the actual object file scanning.  */
176938fd1498Szrj   {
177038fd1498Szrj     const char *p = libgcc_spec;
177138fd1498Szrj     int in_sep = 1;
177238fd1498Szrj 
177338fd1498Szrj     /* Transform the extant libgcc_spec into one that uses the shared libgcc
177438fd1498Szrj        when given the proper command line arguments.  */
177538fd1498Szrj     while (*p)
177638fd1498Szrj       {
177738fd1498Szrj 	if (in_sep && *p == '-' && strncmp (p, "-lgcc", 5) == 0)
177838fd1498Szrj 	  {
177938fd1498Szrj 	    init_gcc_specs (&obstack,
178038fd1498Szrj 			    "-lgcc_s"
178138fd1498Szrj #ifdef USE_LIBUNWIND_EXCEPTIONS
178238fd1498Szrj 			    " -lunwind"
178338fd1498Szrj #endif
178438fd1498Szrj 			    ,
178538fd1498Szrj 			    "-lgcc",
178638fd1498Szrj 			    "-lgcc_eh"
178738fd1498Szrj #ifdef USE_LIBUNWIND_EXCEPTIONS
178838fd1498Szrj # ifdef HAVE_LD_STATIC_DYNAMIC
178938fd1498Szrj 			    " %{!static:%{!static-pie:" LD_STATIC_OPTION "}} -lunwind"
179038fd1498Szrj 			    " %{!static:%{!static-pie:" LD_DYNAMIC_OPTION "}}"
179138fd1498Szrj # else
179238fd1498Szrj 			    " -lunwind"
179338fd1498Szrj # endif
179438fd1498Szrj #endif
179538fd1498Szrj 			    );
179638fd1498Szrj 
179738fd1498Szrj 	    p += 5;
179838fd1498Szrj 	    in_sep = 0;
179938fd1498Szrj 	  }
180038fd1498Szrj 	else if (in_sep && *p == 'l' && strncmp (p, "libgcc.a%s", 10) == 0)
180138fd1498Szrj 	  {
180238fd1498Szrj 	    /* Ug.  We don't know shared library extensions.  Hope that
180338fd1498Szrj 	       systems that use this form don't do shared libraries.  */
180438fd1498Szrj 	    init_gcc_specs (&obstack,
180538fd1498Szrj 			    "-lgcc_s",
180638fd1498Szrj 			    "libgcc.a%s",
180738fd1498Szrj 			    "libgcc_eh.a%s"
180838fd1498Szrj #ifdef USE_LIBUNWIND_EXCEPTIONS
180938fd1498Szrj 			    " -lunwind"
181038fd1498Szrj #endif
181138fd1498Szrj 			    );
181238fd1498Szrj 	    p += 10;
181338fd1498Szrj 	    in_sep = 0;
181438fd1498Szrj 	  }
181538fd1498Szrj 	else
181638fd1498Szrj 	  {
181738fd1498Szrj 	    obstack_1grow (&obstack, *p);
181838fd1498Szrj 	    in_sep = (*p == ' ');
181938fd1498Szrj 	    p += 1;
182038fd1498Szrj 	  }
182138fd1498Szrj       }
182238fd1498Szrj 
182338fd1498Szrj     obstack_1grow (&obstack, '\0');
182438fd1498Szrj     libgcc_spec = XOBFINISH (&obstack, const char *);
182538fd1498Szrj   }
182638fd1498Szrj #endif
182738fd1498Szrj #ifdef USE_AS_TRADITIONAL_FORMAT
182838fd1498Szrj   /* Prepend "--traditional-format" to whatever asm_spec we had before.  */
182938fd1498Szrj   {
183038fd1498Szrj     static const char tf[] = "--traditional-format ";
183138fd1498Szrj     obstack_grow (&obstack, tf, sizeof (tf) - 1);
183238fd1498Szrj     obstack_grow0 (&obstack, asm_spec, strlen (asm_spec));
183338fd1498Szrj     asm_spec = XOBFINISH (&obstack, const char *);
183438fd1498Szrj   }
183538fd1498Szrj #endif
183638fd1498Szrj 
183738fd1498Szrj #if defined LINK_EH_SPEC || defined LINK_BUILDID_SPEC || \
183838fd1498Szrj     defined LINKER_HASH_STYLE
183938fd1498Szrj # ifdef LINK_BUILDID_SPEC
184038fd1498Szrj   /* Prepend LINK_BUILDID_SPEC to whatever link_spec we had before.  */
184138fd1498Szrj   obstack_grow (&obstack, LINK_BUILDID_SPEC, sizeof (LINK_BUILDID_SPEC) - 1);
184238fd1498Szrj # endif
184338fd1498Szrj # ifdef LINK_EH_SPEC
184438fd1498Szrj   /* Prepend LINK_EH_SPEC to whatever link_spec we had before.  */
184538fd1498Szrj   obstack_grow (&obstack, LINK_EH_SPEC, sizeof (LINK_EH_SPEC) - 1);
184638fd1498Szrj # endif
184738fd1498Szrj # ifdef LINKER_HASH_STYLE
184838fd1498Szrj   /* Prepend --hash-style=LINKER_HASH_STYLE to whatever link_spec we had
184938fd1498Szrj      before.  */
185038fd1498Szrj   {
185138fd1498Szrj     static const char hash_style[] = "--hash-style=";
185238fd1498Szrj     obstack_grow (&obstack, hash_style, sizeof (hash_style) - 1);
185338fd1498Szrj     obstack_grow (&obstack, LINKER_HASH_STYLE, sizeof (LINKER_HASH_STYLE) - 1);
185438fd1498Szrj     obstack_1grow (&obstack, ' ');
185538fd1498Szrj   }
185638fd1498Szrj # endif
185738fd1498Szrj   obstack_grow0 (&obstack, link_spec, strlen (link_spec));
185838fd1498Szrj   link_spec = XOBFINISH (&obstack, const char *);
185938fd1498Szrj #endif
186038fd1498Szrj 
186138fd1498Szrj   specs = sl;
186238fd1498Szrj }
186338fd1498Szrj 
186438fd1498Szrj /* Change the value of spec NAME to SPEC.  If SPEC is empty, then the spec is
186538fd1498Szrj    removed; If the spec starts with a + then SPEC is added to the end of the
186638fd1498Szrj    current spec.  */
186738fd1498Szrj 
186838fd1498Szrj static void
set_spec(const char * name,const char * spec,bool user_p)186938fd1498Szrj set_spec (const char *name, const char *spec, bool user_p)
187038fd1498Szrj {
187138fd1498Szrj   struct spec_list *sl;
187238fd1498Szrj   const char *old_spec;
187338fd1498Szrj   int name_len = strlen (name);
187438fd1498Szrj   int i;
187538fd1498Szrj 
187638fd1498Szrj   /* If this is the first call, initialize the statically allocated specs.  */
187738fd1498Szrj   if (!specs)
187838fd1498Szrj     {
187938fd1498Szrj       struct spec_list *next = (struct spec_list *) 0;
188038fd1498Szrj       for (i = ARRAY_SIZE (static_specs) - 1; i >= 0; i--)
188138fd1498Szrj 	{
188238fd1498Szrj 	  sl = &static_specs[i];
188338fd1498Szrj 	  sl->next = next;
188438fd1498Szrj 	  next = sl;
188538fd1498Szrj 	}
188638fd1498Szrj       specs = sl;
188738fd1498Szrj     }
188838fd1498Szrj 
188938fd1498Szrj   /* See if the spec already exists.  */
189038fd1498Szrj   for (sl = specs; sl; sl = sl->next)
189138fd1498Szrj     if (name_len == sl->name_len && !strcmp (sl->name, name))
189238fd1498Szrj       break;
189338fd1498Szrj 
189438fd1498Szrj   if (!sl)
189538fd1498Szrj     {
189638fd1498Szrj       /* Not found - make it.  */
189738fd1498Szrj       sl = XNEW (struct spec_list);
189838fd1498Szrj       sl->name = xstrdup (name);
189938fd1498Szrj       sl->name_len = name_len;
190038fd1498Szrj       sl->ptr_spec = &sl->ptr;
190138fd1498Szrj       sl->alloc_p = 0;
190238fd1498Szrj       *(sl->ptr_spec) = "";
190338fd1498Szrj       sl->next = specs;
190438fd1498Szrj       sl->default_ptr = NULL;
190538fd1498Szrj       specs = sl;
190638fd1498Szrj     }
190738fd1498Szrj 
190838fd1498Szrj   old_spec = *(sl->ptr_spec);
190938fd1498Szrj   *(sl->ptr_spec) = ((spec[0] == '+' && ISSPACE ((unsigned char)spec[1]))
191038fd1498Szrj 		     ? concat (old_spec, spec + 1, NULL)
191138fd1498Szrj 		     : xstrdup (spec));
191238fd1498Szrj 
191338fd1498Szrj #ifdef DEBUG_SPECS
191438fd1498Szrj   if (verbose_flag)
191538fd1498Szrj     fnotice (stderr, "Setting spec %s to '%s'\n\n", name, *(sl->ptr_spec));
191638fd1498Szrj #endif
191738fd1498Szrj 
191838fd1498Szrj   /* Free the old spec.  */
191938fd1498Szrj   if (old_spec && sl->alloc_p)
192038fd1498Szrj     free (CONST_CAST (char *, old_spec));
192138fd1498Szrj 
192238fd1498Szrj   sl->user_p = user_p;
192338fd1498Szrj   sl->alloc_p = true;
192438fd1498Szrj }
192538fd1498Szrj 
192638fd1498Szrj /* Accumulate a command (program name and args), and run it.  */
192738fd1498Szrj 
192838fd1498Szrj typedef const char *const_char_p; /* For DEF_VEC_P.  */
192938fd1498Szrj 
193038fd1498Szrj /* Vector of pointers to arguments in the current line of specifications.  */
193138fd1498Szrj 
193238fd1498Szrj static vec<const_char_p> argbuf;
193338fd1498Szrj 
193438fd1498Szrj /* Were the options -c, -S or -E passed.  */
193538fd1498Szrj static int have_c = 0;
193638fd1498Szrj 
193738fd1498Szrj /* Was the option -o passed.  */
193838fd1498Szrj static int have_o = 0;
193938fd1498Szrj 
194038fd1498Szrj /* Was the option -E passed.  */
194138fd1498Szrj static int have_E = 0;
194238fd1498Szrj 
194338fd1498Szrj /* Pointer to output file name passed in with -o. */
194438fd1498Szrj static const char *output_file = 0;
194538fd1498Szrj 
194638fd1498Szrj /* This is the list of suffixes and codes (%g/%u/%U/%j) and the associated
194738fd1498Szrj    temp file.  If the HOST_BIT_BUCKET is used for %j, no entry is made for
194838fd1498Szrj    it here.  */
194938fd1498Szrj 
195038fd1498Szrj static struct temp_name {
195138fd1498Szrj   const char *suffix;	/* suffix associated with the code.  */
195238fd1498Szrj   int length;		/* strlen (suffix).  */
195338fd1498Szrj   int unique;		/* Indicates whether %g or %u/%U was used.  */
195438fd1498Szrj   const char *filename;	/* associated filename.  */
195538fd1498Szrj   int filename_length;	/* strlen (filename).  */
195638fd1498Szrj   struct temp_name *next;
195738fd1498Szrj } *temp_names;
195838fd1498Szrj 
195938fd1498Szrj /* Number of commands executed so far.  */
196038fd1498Szrj 
196138fd1498Szrj static int execution_count;
196238fd1498Szrj 
196338fd1498Szrj /* Number of commands that exited with a signal.  */
196438fd1498Szrj 
196538fd1498Szrj static int signal_count;
196638fd1498Szrj 
196738fd1498Szrj /* Allocate the argument vector.  */
196838fd1498Szrj 
196938fd1498Szrj static void
alloc_args(void)197038fd1498Szrj alloc_args (void)
197138fd1498Szrj {
197238fd1498Szrj   argbuf.create (10);
197338fd1498Szrj }
197438fd1498Szrj 
197538fd1498Szrj /* Clear out the vector of arguments (after a command is executed).  */
197638fd1498Szrj 
197738fd1498Szrj static void
clear_args(void)197838fd1498Szrj clear_args (void)
197938fd1498Szrj {
198038fd1498Szrj   argbuf.truncate (0);
198138fd1498Szrj }
198238fd1498Szrj 
198338fd1498Szrj /* Add one argument to the vector at the end.
198438fd1498Szrj    This is done when a space is seen or at the end of the line.
198538fd1498Szrj    If DELETE_ALWAYS is nonzero, the arg is a filename
198638fd1498Szrj     and the file should be deleted eventually.
198738fd1498Szrj    If DELETE_FAILURE is nonzero, the arg is a filename
198838fd1498Szrj     and the file should be deleted if this compilation fails.  */
198938fd1498Szrj 
199038fd1498Szrj static void
store_arg(const char * arg,int delete_always,int delete_failure)199138fd1498Szrj store_arg (const char *arg, int delete_always, int delete_failure)
199238fd1498Szrj {
199338fd1498Szrj   argbuf.safe_push (arg);
199438fd1498Szrj 
199538fd1498Szrj   if (delete_always || delete_failure)
199638fd1498Szrj     {
199738fd1498Szrj       const char *p;
199838fd1498Szrj       /* If the temporary file we should delete is specified as
199938fd1498Szrj 	 part of a joined argument extract the filename.  */
200038fd1498Szrj       if (arg[0] == '-'
200138fd1498Szrj 	  && (p = strrchr (arg, '=')))
200238fd1498Szrj 	arg = p + 1;
200338fd1498Szrj       record_temp_file (arg, delete_always, delete_failure);
200438fd1498Szrj     }
200538fd1498Szrj }
200638fd1498Szrj 
200738fd1498Szrj /* Load specs from a file name named FILENAME, replacing occurrences of
200838fd1498Szrj    various different types of line-endings, \r\n, \n\r and just \r, with
200938fd1498Szrj    a single \n.  */
201038fd1498Szrj 
201138fd1498Szrj static char *
load_specs(const char * filename)201238fd1498Szrj load_specs (const char *filename)
201338fd1498Szrj {
201438fd1498Szrj   int desc;
201538fd1498Szrj   int readlen;
201638fd1498Szrj   struct stat statbuf;
201738fd1498Szrj   char *buffer;
201838fd1498Szrj   char *buffer_p;
201938fd1498Szrj   char *specs;
202038fd1498Szrj   char *specs_p;
202138fd1498Szrj 
202238fd1498Szrj   if (verbose_flag)
202338fd1498Szrj     fnotice (stderr, "Reading specs from %s\n", filename);
202438fd1498Szrj 
202538fd1498Szrj   /* Open and stat the file.  */
202638fd1498Szrj   desc = open (filename, O_RDONLY, 0);
202738fd1498Szrj   if (desc < 0)
202838fd1498Szrj     pfatal_with_name (filename);
202938fd1498Szrj   if (stat (filename, &statbuf) < 0)
203038fd1498Szrj     pfatal_with_name (filename);
203138fd1498Szrj 
203238fd1498Szrj   /* Read contents of file into BUFFER.  */
203338fd1498Szrj   buffer = XNEWVEC (char, statbuf.st_size + 1);
203438fd1498Szrj   readlen = read (desc, buffer, (unsigned) statbuf.st_size);
203538fd1498Szrj   if (readlen < 0)
203638fd1498Szrj     pfatal_with_name (filename);
203738fd1498Szrj   buffer[readlen] = 0;
203838fd1498Szrj   close (desc);
203938fd1498Szrj 
204038fd1498Szrj   specs = XNEWVEC (char, readlen + 1);
204138fd1498Szrj   specs_p = specs;
204238fd1498Szrj   for (buffer_p = buffer; buffer_p && *buffer_p; buffer_p++)
204338fd1498Szrj     {
204438fd1498Szrj       int skip = 0;
204538fd1498Szrj       char c = *buffer_p;
204638fd1498Szrj       if (c == '\r')
204738fd1498Szrj 	{
204838fd1498Szrj 	  if (buffer_p > buffer && *(buffer_p - 1) == '\n')	/* \n\r */
204938fd1498Szrj 	    skip = 1;
205038fd1498Szrj 	  else if (*(buffer_p + 1) == '\n')			/* \r\n */
205138fd1498Szrj 	    skip = 1;
205238fd1498Szrj 	  else							/* \r */
205338fd1498Szrj 	    c = '\n';
205438fd1498Szrj 	}
205538fd1498Szrj       if (! skip)
205638fd1498Szrj 	*specs_p++ = c;
205738fd1498Szrj     }
205838fd1498Szrj   *specs_p = '\0';
205938fd1498Szrj 
206038fd1498Szrj   free (buffer);
206138fd1498Szrj   return (specs);
206238fd1498Szrj }
206338fd1498Szrj 
206438fd1498Szrj /* Read compilation specs from a file named FILENAME,
206538fd1498Szrj    replacing the default ones.
206638fd1498Szrj 
206738fd1498Szrj    A suffix which starts with `*' is a definition for
206838fd1498Szrj    one of the machine-specific sub-specs.  The "suffix" should be
206938fd1498Szrj    *asm, *cc1, *cpp, *link, *startfile, etc.
207038fd1498Szrj    The corresponding spec is stored in asm_spec, etc.,
207138fd1498Szrj    rather than in the `compilers' vector.
207238fd1498Szrj 
207338fd1498Szrj    Anything invalid in the file is a fatal error.  */
207438fd1498Szrj 
207538fd1498Szrj static void
read_specs(const char * filename,bool main_p,bool user_p)207638fd1498Szrj read_specs (const char *filename, bool main_p, bool user_p)
207738fd1498Szrj {
207838fd1498Szrj   char *buffer;
207938fd1498Szrj   char *p;
208038fd1498Szrj 
208138fd1498Szrj   buffer = load_specs (filename);
208238fd1498Szrj 
208338fd1498Szrj   /* Scan BUFFER for specs, putting them in the vector.  */
208438fd1498Szrj   p = buffer;
208538fd1498Szrj   while (1)
208638fd1498Szrj     {
208738fd1498Szrj       char *suffix;
208838fd1498Szrj       char *spec;
208938fd1498Szrj       char *in, *out, *p1, *p2, *p3;
209038fd1498Szrj 
209138fd1498Szrj       /* Advance P in BUFFER to the next nonblank nocomment line.  */
209238fd1498Szrj       p = skip_whitespace (p);
209338fd1498Szrj       if (*p == 0)
209438fd1498Szrj 	break;
209538fd1498Szrj 
209638fd1498Szrj       /* Is this a special command that starts with '%'? */
209738fd1498Szrj       /* Don't allow this for the main specs file, since it would
209838fd1498Szrj 	 encourage people to overwrite it.  */
209938fd1498Szrj       if (*p == '%' && !main_p)
210038fd1498Szrj 	{
210138fd1498Szrj 	  p1 = p;
210238fd1498Szrj 	  while (*p && *p != '\n')
210338fd1498Szrj 	    p++;
210438fd1498Szrj 
210538fd1498Szrj 	  /* Skip '\n'.  */
210638fd1498Szrj 	  p++;
210738fd1498Szrj 
210838fd1498Szrj 	  if (!strncmp (p1, "%include", sizeof ("%include") - 1)
210938fd1498Szrj 	      && (p1[sizeof "%include" - 1] == ' '
211038fd1498Szrj 		  || p1[sizeof "%include" - 1] == '\t'))
211138fd1498Szrj 	    {
211238fd1498Szrj 	      char *new_filename;
211338fd1498Szrj 
211438fd1498Szrj 	      p1 += sizeof ("%include");
211538fd1498Szrj 	      while (*p1 == ' ' || *p1 == '\t')
211638fd1498Szrj 		p1++;
211738fd1498Szrj 
211838fd1498Szrj 	      if (*p1++ != '<' || p[-2] != '>')
211938fd1498Szrj 		fatal_error (input_location,
212038fd1498Szrj 			     "specs %%include syntax malformed after "
212138fd1498Szrj 			     "%ld characters",
212238fd1498Szrj 			     (long) (p1 - buffer + 1));
212338fd1498Szrj 
212438fd1498Szrj 	      p[-2] = '\0';
212538fd1498Szrj 	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
212638fd1498Szrj 	      read_specs (new_filename ? new_filename : p1, false, user_p);
212738fd1498Szrj 	      continue;
212838fd1498Szrj 	    }
212938fd1498Szrj 	  else if (!strncmp (p1, "%include_noerr", sizeof "%include_noerr" - 1)
213038fd1498Szrj 		   && (p1[sizeof "%include_noerr" - 1] == ' '
213138fd1498Szrj 		       || p1[sizeof "%include_noerr" - 1] == '\t'))
213238fd1498Szrj 	    {
213338fd1498Szrj 	      char *new_filename;
213438fd1498Szrj 
213538fd1498Szrj 	      p1 += sizeof "%include_noerr";
213638fd1498Szrj 	      while (*p1 == ' ' || *p1 == '\t')
213738fd1498Szrj 		p1++;
213838fd1498Szrj 
213938fd1498Szrj 	      if (*p1++ != '<' || p[-2] != '>')
214038fd1498Szrj 		fatal_error (input_location,
214138fd1498Szrj 			     "specs %%include syntax malformed after "
214238fd1498Szrj 			     "%ld characters",
214338fd1498Szrj 			     (long) (p1 - buffer + 1));
214438fd1498Szrj 
214538fd1498Szrj 	      p[-2] = '\0';
214638fd1498Szrj 	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
214738fd1498Szrj 	      if (new_filename)
214838fd1498Szrj 		read_specs (new_filename, false, user_p);
214938fd1498Szrj 	      else if (verbose_flag)
215038fd1498Szrj 		fnotice (stderr, "could not find specs file %s\n", p1);
215138fd1498Szrj 	      continue;
215238fd1498Szrj 	    }
215338fd1498Szrj 	  else if (!strncmp (p1, "%rename", sizeof "%rename" - 1)
215438fd1498Szrj 		   && (p1[sizeof "%rename" - 1] == ' '
215538fd1498Szrj 		       || p1[sizeof "%rename" - 1] == '\t'))
215638fd1498Szrj 	    {
215738fd1498Szrj 	      int name_len;
215838fd1498Szrj 	      struct spec_list *sl;
215938fd1498Szrj 	      struct spec_list *newsl;
216038fd1498Szrj 
216138fd1498Szrj 	      /* Get original name.  */
216238fd1498Szrj 	      p1 += sizeof "%rename";
216338fd1498Szrj 	      while (*p1 == ' ' || *p1 == '\t')
216438fd1498Szrj 		p1++;
216538fd1498Szrj 
216638fd1498Szrj 	      if (! ISALPHA ((unsigned char) *p1))
216738fd1498Szrj 		fatal_error (input_location,
216838fd1498Szrj 			     "specs %%rename syntax malformed after "
216938fd1498Szrj 			     "%ld characters",
217038fd1498Szrj 			     (long) (p1 - buffer));
217138fd1498Szrj 
217238fd1498Szrj 	      p2 = p1;
217338fd1498Szrj 	      while (*p2 && !ISSPACE ((unsigned char) *p2))
217438fd1498Szrj 		p2++;
217538fd1498Szrj 
217638fd1498Szrj 	      if (*p2 != ' ' && *p2 != '\t')
217738fd1498Szrj 		fatal_error (input_location,
217838fd1498Szrj 			     "specs %%rename syntax malformed after "
217938fd1498Szrj 			     "%ld characters",
218038fd1498Szrj 			     (long) (p2 - buffer));
218138fd1498Szrj 
218238fd1498Szrj 	      name_len = p2 - p1;
218338fd1498Szrj 	      *p2++ = '\0';
218438fd1498Szrj 	      while (*p2 == ' ' || *p2 == '\t')
218538fd1498Szrj 		p2++;
218638fd1498Szrj 
218738fd1498Szrj 	      if (! ISALPHA ((unsigned char) *p2))
218838fd1498Szrj 		fatal_error (input_location,
218938fd1498Szrj 			     "specs %%rename syntax malformed after "
219038fd1498Szrj 			     "%ld characters",
219138fd1498Szrj 			     (long) (p2 - buffer));
219238fd1498Szrj 
219338fd1498Szrj 	      /* Get new spec name.  */
219438fd1498Szrj 	      p3 = p2;
219538fd1498Szrj 	      while (*p3 && !ISSPACE ((unsigned char) *p3))
219638fd1498Szrj 		p3++;
219738fd1498Szrj 
219838fd1498Szrj 	      if (p3 != p - 1)
219938fd1498Szrj 		fatal_error (input_location,
220038fd1498Szrj 			     "specs %%rename syntax malformed after "
220138fd1498Szrj 			     "%ld characters",
220238fd1498Szrj 			     (long) (p3 - buffer));
220338fd1498Szrj 	      *p3 = '\0';
220438fd1498Szrj 
220538fd1498Szrj 	      for (sl = specs; sl; sl = sl->next)
220638fd1498Szrj 		if (name_len == sl->name_len && !strcmp (sl->name, p1))
220738fd1498Szrj 		  break;
220838fd1498Szrj 
220938fd1498Szrj 	      if (!sl)
221038fd1498Szrj 		fatal_error (input_location,
221138fd1498Szrj 			     "specs %s spec was not found to be renamed", p1);
221238fd1498Szrj 
221338fd1498Szrj 	      if (strcmp (p1, p2) == 0)
221438fd1498Szrj 		continue;
221538fd1498Szrj 
221638fd1498Szrj 	      for (newsl = specs; newsl; newsl = newsl->next)
221738fd1498Szrj 		if (strcmp (newsl->name, p2) == 0)
221838fd1498Szrj 		  fatal_error (input_location,
221938fd1498Szrj 			       "%s: attempt to rename spec %qs to "
222038fd1498Szrj 			       "already defined spec %qs",
222138fd1498Szrj 		    filename, p1, p2);
222238fd1498Szrj 
222338fd1498Szrj 	      if (verbose_flag)
222438fd1498Szrj 		{
222538fd1498Szrj 		  fnotice (stderr, "rename spec %s to %s\n", p1, p2);
222638fd1498Szrj #ifdef DEBUG_SPECS
222738fd1498Szrj 		  fnotice (stderr, "spec is '%s'\n\n", *(sl->ptr_spec));
222838fd1498Szrj #endif
222938fd1498Szrj 		}
223038fd1498Szrj 
223138fd1498Szrj 	      set_spec (p2, *(sl->ptr_spec), user_p);
223238fd1498Szrj 	      if (sl->alloc_p)
223338fd1498Szrj 		free (CONST_CAST (char *, *(sl->ptr_spec)));
223438fd1498Szrj 
223538fd1498Szrj 	      *(sl->ptr_spec) = "";
223638fd1498Szrj 	      sl->alloc_p = 0;
223738fd1498Szrj 	      continue;
223838fd1498Szrj 	    }
223938fd1498Szrj 	  else
224038fd1498Szrj 	    fatal_error (input_location,
224138fd1498Szrj 			 "specs unknown %% command after %ld characters",
224238fd1498Szrj 			 (long) (p1 - buffer));
224338fd1498Szrj 	}
224438fd1498Szrj 
224538fd1498Szrj       /* Find the colon that should end the suffix.  */
224638fd1498Szrj       p1 = p;
224738fd1498Szrj       while (*p1 && *p1 != ':' && *p1 != '\n')
224838fd1498Szrj 	p1++;
224938fd1498Szrj 
225038fd1498Szrj       /* The colon shouldn't be missing.  */
225138fd1498Szrj       if (*p1 != ':')
225238fd1498Szrj 	fatal_error (input_location,
225338fd1498Szrj 		     "specs file malformed after %ld characters",
225438fd1498Szrj 		     (long) (p1 - buffer));
225538fd1498Szrj 
225638fd1498Szrj       /* Skip back over trailing whitespace.  */
225738fd1498Szrj       p2 = p1;
225838fd1498Szrj       while (p2 > buffer && (p2[-1] == ' ' || p2[-1] == '\t'))
225938fd1498Szrj 	p2--;
226038fd1498Szrj 
226138fd1498Szrj       /* Copy the suffix to a string.  */
226238fd1498Szrj       suffix = save_string (p, p2 - p);
226338fd1498Szrj       /* Find the next line.  */
226438fd1498Szrj       p = skip_whitespace (p1 + 1);
226538fd1498Szrj       if (p[1] == 0)
226638fd1498Szrj 	fatal_error (input_location,
226738fd1498Szrj 		     "specs file malformed after %ld characters",
226838fd1498Szrj 		     (long) (p - buffer));
226938fd1498Szrj 
227038fd1498Szrj       p1 = p;
227138fd1498Szrj       /* Find next blank line or end of string.  */
227238fd1498Szrj       while (*p1 && !(*p1 == '\n' && (p1[1] == '\n' || p1[1] == '\0')))
227338fd1498Szrj 	p1++;
227438fd1498Szrj 
227538fd1498Szrj       /* Specs end at the blank line and do not include the newline.  */
227638fd1498Szrj       spec = save_string (p, p1 - p);
227738fd1498Szrj       p = p1;
227838fd1498Szrj 
227938fd1498Szrj       /* Delete backslash-newline sequences from the spec.  */
228038fd1498Szrj       in = spec;
228138fd1498Szrj       out = spec;
228238fd1498Szrj       while (*in != 0)
228338fd1498Szrj 	{
228438fd1498Szrj 	  if (in[0] == '\\' && in[1] == '\n')
228538fd1498Szrj 	    in += 2;
228638fd1498Szrj 	  else if (in[0] == '#')
228738fd1498Szrj 	    while (*in && *in != '\n')
228838fd1498Szrj 	      in++;
228938fd1498Szrj 
229038fd1498Szrj 	  else
229138fd1498Szrj 	    *out++ = *in++;
229238fd1498Szrj 	}
229338fd1498Szrj       *out = 0;
229438fd1498Szrj 
229538fd1498Szrj       if (suffix[0] == '*')
229638fd1498Szrj 	{
229738fd1498Szrj 	  if (! strcmp (suffix, "*link_command"))
229838fd1498Szrj 	    link_command_spec = spec;
229938fd1498Szrj 	  else
230038fd1498Szrj 	    {
230138fd1498Szrj 	      set_spec (suffix + 1, spec, user_p);
230238fd1498Szrj 	      free (spec);
230338fd1498Szrj 	    }
230438fd1498Szrj 	}
230538fd1498Szrj       else
230638fd1498Szrj 	{
230738fd1498Szrj 	  /* Add this pair to the vector.  */
230838fd1498Szrj 	  compilers
230938fd1498Szrj 	    = XRESIZEVEC (struct compiler, compilers, n_compilers + 2);
231038fd1498Szrj 
231138fd1498Szrj 	  compilers[n_compilers].suffix = suffix;
231238fd1498Szrj 	  compilers[n_compilers].spec = spec;
231338fd1498Szrj 	  n_compilers++;
231438fd1498Szrj 	  memset (&compilers[n_compilers], 0, sizeof compilers[n_compilers]);
231538fd1498Szrj 	}
231638fd1498Szrj 
231738fd1498Szrj       if (*suffix == 0)
231838fd1498Szrj 	link_command_spec = spec;
231938fd1498Szrj     }
232038fd1498Szrj 
232138fd1498Szrj   if (link_command_spec == 0)
232238fd1498Szrj     fatal_error (input_location, "spec file has no spec for linking");
232338fd1498Szrj 
232438fd1498Szrj   XDELETEVEC (buffer);
232538fd1498Szrj }
232638fd1498Szrj 
232738fd1498Szrj /* Record the names of temporary files we tell compilers to write,
232838fd1498Szrj    and delete them at the end of the run.  */
232938fd1498Szrj 
233038fd1498Szrj /* This is the common prefix we use to make temp file names.
233138fd1498Szrj    It is chosen once for each run of this program.
233238fd1498Szrj    It is substituted into a spec by %g or %j.
233338fd1498Szrj    Thus, all temp file names contain this prefix.
233438fd1498Szrj    In practice, all temp file names start with this prefix.
233538fd1498Szrj 
233638fd1498Szrj    This prefix comes from the envvar TMPDIR if it is defined;
233738fd1498Szrj    otherwise, from the P_tmpdir macro if that is defined;
233838fd1498Szrj    otherwise, in /usr/tmp or /tmp;
233938fd1498Szrj    or finally the current directory if all else fails.  */
234038fd1498Szrj 
234138fd1498Szrj static const char *temp_filename;
234238fd1498Szrj 
234338fd1498Szrj /* Length of the prefix.  */
234438fd1498Szrj 
234538fd1498Szrj static int temp_filename_length;
234638fd1498Szrj 
234738fd1498Szrj /* Define the list of temporary files to delete.  */
234838fd1498Szrj 
234938fd1498Szrj struct temp_file
235038fd1498Szrj {
235138fd1498Szrj   const char *name;
235238fd1498Szrj   struct temp_file *next;
235338fd1498Szrj };
235438fd1498Szrj 
235538fd1498Szrj /* Queue of files to delete on success or failure of compilation.  */
235638fd1498Szrj static struct temp_file *always_delete_queue;
235738fd1498Szrj /* Queue of files to delete on failure of compilation.  */
235838fd1498Szrj static struct temp_file *failure_delete_queue;
235938fd1498Szrj 
236038fd1498Szrj /* Record FILENAME as a file to be deleted automatically.
236138fd1498Szrj    ALWAYS_DELETE nonzero means delete it if all compilation succeeds;
236238fd1498Szrj    otherwise delete it in any case.
236338fd1498Szrj    FAIL_DELETE nonzero means delete it if a compilation step fails;
236438fd1498Szrj    otherwise delete it in any case.  */
236538fd1498Szrj 
236638fd1498Szrj void
record_temp_file(const char * filename,int always_delete,int fail_delete)236738fd1498Szrj record_temp_file (const char *filename, int always_delete, int fail_delete)
236838fd1498Szrj {
236938fd1498Szrj   char *const name = xstrdup (filename);
237038fd1498Szrj 
237138fd1498Szrj   if (always_delete)
237238fd1498Szrj     {
237338fd1498Szrj       struct temp_file *temp;
237438fd1498Szrj       for (temp = always_delete_queue; temp; temp = temp->next)
237538fd1498Szrj 	if (! filename_cmp (name, temp->name))
237638fd1498Szrj 	  {
237738fd1498Szrj 	    free (name);
237838fd1498Szrj 	    goto already1;
237938fd1498Szrj 	  }
238038fd1498Szrj 
238138fd1498Szrj       temp = XNEW (struct temp_file);
238238fd1498Szrj       temp->next = always_delete_queue;
238338fd1498Szrj       temp->name = name;
238438fd1498Szrj       always_delete_queue = temp;
238538fd1498Szrj 
238638fd1498Szrj     already1:;
238738fd1498Szrj     }
238838fd1498Szrj 
238938fd1498Szrj   if (fail_delete)
239038fd1498Szrj     {
239138fd1498Szrj       struct temp_file *temp;
239238fd1498Szrj       for (temp = failure_delete_queue; temp; temp = temp->next)
239338fd1498Szrj 	if (! filename_cmp (name, temp->name))
239438fd1498Szrj 	  {
239538fd1498Szrj 	    free (name);
239638fd1498Szrj 	    goto already2;
239738fd1498Szrj 	  }
239838fd1498Szrj 
239938fd1498Szrj       temp = XNEW (struct temp_file);
240038fd1498Szrj       temp->next = failure_delete_queue;
240138fd1498Szrj       temp->name = name;
240238fd1498Szrj       failure_delete_queue = temp;
240338fd1498Szrj 
240438fd1498Szrj     already2:;
240538fd1498Szrj     }
240638fd1498Szrj }
240738fd1498Szrj 
240838fd1498Szrj /* Delete all the temporary files whose names we previously recorded.  */
240938fd1498Szrj 
241038fd1498Szrj #ifndef DELETE_IF_ORDINARY
241138fd1498Szrj #define DELETE_IF_ORDINARY(NAME,ST,VERBOSE_FLAG)        \
241238fd1498Szrj do                                                      \
241338fd1498Szrj   {                                                     \
241438fd1498Szrj     if (stat (NAME, &ST) >= 0 && S_ISREG (ST.st_mode))  \
241538fd1498Szrj       if (unlink (NAME) < 0)                            \
241638fd1498Szrj 	if (VERBOSE_FLAG)                               \
241738fd1498Szrj 	  perror_with_name (NAME);                      \
241838fd1498Szrj   } while (0)
241938fd1498Szrj #endif
242038fd1498Szrj 
242138fd1498Szrj static void
delete_if_ordinary(const char * name)242238fd1498Szrj delete_if_ordinary (const char *name)
242338fd1498Szrj {
242438fd1498Szrj   struct stat st;
242538fd1498Szrj #ifdef DEBUG
242638fd1498Szrj   int i, c;
242738fd1498Szrj 
242838fd1498Szrj   printf ("Delete %s? (y or n) ", name);
242938fd1498Szrj   fflush (stdout);
243038fd1498Szrj   i = getchar ();
243138fd1498Szrj   if (i != '\n')
243238fd1498Szrj     while ((c = getchar ()) != '\n' && c != EOF)
243338fd1498Szrj       ;
243438fd1498Szrj 
243538fd1498Szrj   if (i == 'y' || i == 'Y')
243638fd1498Szrj #endif /* DEBUG */
243738fd1498Szrj   DELETE_IF_ORDINARY (name, st, verbose_flag);
243838fd1498Szrj }
243938fd1498Szrj 
244038fd1498Szrj static void
delete_temp_files(void)244138fd1498Szrj delete_temp_files (void)
244238fd1498Szrj {
244338fd1498Szrj   struct temp_file *temp;
244438fd1498Szrj 
244538fd1498Szrj   for (temp = always_delete_queue; temp; temp = temp->next)
244638fd1498Szrj     delete_if_ordinary (temp->name);
244738fd1498Szrj   always_delete_queue = 0;
244838fd1498Szrj }
244938fd1498Szrj 
245038fd1498Szrj /* Delete all the files to be deleted on error.  */
245138fd1498Szrj 
245238fd1498Szrj static void
delete_failure_queue(void)245338fd1498Szrj delete_failure_queue (void)
245438fd1498Szrj {
245538fd1498Szrj   struct temp_file *temp;
245638fd1498Szrj 
245738fd1498Szrj   for (temp = failure_delete_queue; temp; temp = temp->next)
245838fd1498Szrj     delete_if_ordinary (temp->name);
245938fd1498Szrj }
246038fd1498Szrj 
246138fd1498Szrj static void
clear_failure_queue(void)246238fd1498Szrj clear_failure_queue (void)
246338fd1498Szrj {
246438fd1498Szrj   failure_delete_queue = 0;
246538fd1498Szrj }
246638fd1498Szrj 
246738fd1498Szrj /* Call CALLBACK for each path in PATHS, breaking out early if CALLBACK
246838fd1498Szrj    returns non-NULL.
246938fd1498Szrj    If DO_MULTI is true iterate over the paths twice, first with multilib
247038fd1498Szrj    suffix then without, otherwise iterate over the paths once without
247138fd1498Szrj    adding a multilib suffix.  When DO_MULTI is true, some attempt is made
247238fd1498Szrj    to avoid visiting the same path twice, but we could do better.  For
247338fd1498Szrj    instance, /usr/lib/../lib is considered different from /usr/lib.
247438fd1498Szrj    At least EXTRA_SPACE chars past the end of the path passed to
247538fd1498Szrj    CALLBACK are available for use by the callback.
247638fd1498Szrj    CALLBACK_INFO allows extra parameters to be passed to CALLBACK.
247738fd1498Szrj 
247838fd1498Szrj    Returns the value returned by CALLBACK.  */
247938fd1498Szrj 
248038fd1498Szrj static void *
for_each_path(const struct path_prefix * paths,bool do_multi,size_t extra_space,void * (* callback)(char *,void *),void * callback_info)248138fd1498Szrj for_each_path (const struct path_prefix *paths,
248238fd1498Szrj 	       bool do_multi,
248338fd1498Szrj 	       size_t extra_space,
248438fd1498Szrj 	       void *(*callback) (char *, void *),
248538fd1498Szrj 	       void *callback_info)
248638fd1498Szrj {
248738fd1498Szrj   struct prefix_list *pl;
248838fd1498Szrj   const char *multi_dir = NULL;
248938fd1498Szrj   const char *multi_os_dir = NULL;
249038fd1498Szrj   const char *multiarch_suffix = NULL;
249138fd1498Szrj   const char *multi_suffix;
249238fd1498Szrj   const char *just_multi_suffix;
249338fd1498Szrj   char *path = NULL;
249438fd1498Szrj   void *ret = NULL;
249538fd1498Szrj   bool skip_multi_dir = false;
249638fd1498Szrj   bool skip_multi_os_dir = false;
249738fd1498Szrj 
249838fd1498Szrj   multi_suffix = machine_suffix;
249938fd1498Szrj   just_multi_suffix = just_machine_suffix;
250038fd1498Szrj   if (do_multi && multilib_dir && strcmp (multilib_dir, ".") != 0)
250138fd1498Szrj     {
250238fd1498Szrj       multi_dir = concat (multilib_dir, dir_separator_str, NULL);
250338fd1498Szrj       multi_suffix = concat (multi_suffix, multi_dir, NULL);
250438fd1498Szrj       just_multi_suffix = concat (just_multi_suffix, multi_dir, NULL);
250538fd1498Szrj     }
250638fd1498Szrj   if (do_multi && multilib_os_dir && strcmp (multilib_os_dir, ".") != 0)
250738fd1498Szrj     multi_os_dir = concat (multilib_os_dir, dir_separator_str, NULL);
250838fd1498Szrj   if (multiarch_dir)
250938fd1498Szrj     multiarch_suffix = concat (multiarch_dir, dir_separator_str, NULL);
251038fd1498Szrj 
251138fd1498Szrj   while (1)
251238fd1498Szrj     {
251338fd1498Szrj       size_t multi_dir_len = 0;
251438fd1498Szrj       size_t multi_os_dir_len = 0;
251538fd1498Szrj       size_t multiarch_len = 0;
251638fd1498Szrj       size_t suffix_len;
251738fd1498Szrj       size_t just_suffix_len;
251838fd1498Szrj       size_t len;
251938fd1498Szrj 
252038fd1498Szrj       if (multi_dir)
252138fd1498Szrj 	multi_dir_len = strlen (multi_dir);
252238fd1498Szrj       if (multi_os_dir)
252338fd1498Szrj 	multi_os_dir_len = strlen (multi_os_dir);
252438fd1498Szrj       if (multiarch_suffix)
252538fd1498Szrj 	multiarch_len = strlen (multiarch_suffix);
252638fd1498Szrj       suffix_len = strlen (multi_suffix);
252738fd1498Szrj       just_suffix_len = strlen (just_multi_suffix);
252838fd1498Szrj 
252938fd1498Szrj       if (path == NULL)
253038fd1498Szrj 	{
253138fd1498Szrj 	  len = paths->max_len + extra_space + 1;
253238fd1498Szrj 	  len += MAX (MAX (suffix_len, multi_os_dir_len), multiarch_len);
253338fd1498Szrj 	  path = XNEWVEC (char, len);
253438fd1498Szrj 	}
253538fd1498Szrj 
253638fd1498Szrj       for (pl = paths->plist; pl != 0; pl = pl->next)
253738fd1498Szrj 	{
253838fd1498Szrj 	  len = strlen (pl->prefix);
253938fd1498Szrj 	  memcpy (path, pl->prefix, len);
254038fd1498Szrj 
2541632577dbSzrj #if 0  /* DragonFly base: MACHINE/VERSION isn't used anywhere */
254238fd1498Szrj 	  /* Look first in MACHINE/VERSION subdirectory.  */
254338fd1498Szrj 	  if (!skip_multi_dir)
254438fd1498Szrj 	    {
254538fd1498Szrj 	      memcpy (path + len, multi_suffix, suffix_len + 1);
254638fd1498Szrj 	      ret = callback (path, callback_info);
254738fd1498Szrj 	      if (ret)
254838fd1498Szrj 		break;
254938fd1498Szrj 	    }
2550632577dbSzrj #endif
255138fd1498Szrj 
255238fd1498Szrj 	  /* Some paths are tried with just the machine (ie. target)
255338fd1498Szrj 	     subdir.  This is used for finding as, ld, etc.  */
255438fd1498Szrj 	  if (!skip_multi_dir
255538fd1498Szrj 	      && pl->require_machine_suffix == 2)
255638fd1498Szrj 	    {
255738fd1498Szrj 	      memcpy (path + len, just_multi_suffix, just_suffix_len + 1);
255838fd1498Szrj 	      ret = callback (path, callback_info);
255938fd1498Szrj 	      if (ret)
256038fd1498Szrj 		break;
256138fd1498Szrj 	    }
256238fd1498Szrj 
256338fd1498Szrj 	  /* Now try the multiarch path.  */
256438fd1498Szrj 	  if (!skip_multi_dir
256538fd1498Szrj 	      && !pl->require_machine_suffix && multiarch_dir)
256638fd1498Szrj 	    {
256738fd1498Szrj 	      memcpy (path + len, multiarch_suffix, multiarch_len + 1);
256838fd1498Szrj 	      ret = callback (path, callback_info);
256938fd1498Szrj 	      if (ret)
257038fd1498Szrj 		break;
257138fd1498Szrj 	    }
257238fd1498Szrj 
257338fd1498Szrj 	  /* Now try the base path.  */
257438fd1498Szrj 	  if (!pl->require_machine_suffix
257538fd1498Szrj 	      && !(pl->os_multilib ? skip_multi_os_dir : skip_multi_dir))
257638fd1498Szrj 	    {
257738fd1498Szrj 	      const char *this_multi;
257838fd1498Szrj 	      size_t this_multi_len;
257938fd1498Szrj 
258038fd1498Szrj 	      if (pl->os_multilib)
258138fd1498Szrj 		{
258238fd1498Szrj 		  this_multi = multi_os_dir;
258338fd1498Szrj 		  this_multi_len = multi_os_dir_len;
258438fd1498Szrj 		}
258538fd1498Szrj 	      else
258638fd1498Szrj 		{
258738fd1498Szrj 		  this_multi = multi_dir;
258838fd1498Szrj 		  this_multi_len = multi_dir_len;
258938fd1498Szrj 		}
259038fd1498Szrj 
259138fd1498Szrj 	      if (this_multi_len)
259238fd1498Szrj 		memcpy (path + len, this_multi, this_multi_len + 1);
259338fd1498Szrj 	      else
259438fd1498Szrj 		path[len] = '\0';
259538fd1498Szrj 
259638fd1498Szrj 	      ret = callback (path, callback_info);
259738fd1498Szrj 	      if (ret)
259838fd1498Szrj 		break;
259938fd1498Szrj 	    }
260038fd1498Szrj 	}
260138fd1498Szrj       if (pl)
260238fd1498Szrj 	break;
260338fd1498Szrj 
260438fd1498Szrj       if (multi_dir == NULL && multi_os_dir == NULL)
260538fd1498Szrj 	break;
260638fd1498Szrj 
260738fd1498Szrj       /* Run through the paths again, this time without multilibs.
260838fd1498Szrj 	 Don't repeat any we have already seen.  */
260938fd1498Szrj       if (multi_dir)
261038fd1498Szrj 	{
261138fd1498Szrj 	  free (CONST_CAST (char *, multi_dir));
261238fd1498Szrj 	  multi_dir = NULL;
261338fd1498Szrj 	  free (CONST_CAST (char *, multi_suffix));
261438fd1498Szrj 	  multi_suffix = machine_suffix;
261538fd1498Szrj 	  free (CONST_CAST (char *, just_multi_suffix));
261638fd1498Szrj 	  just_multi_suffix = just_machine_suffix;
261738fd1498Szrj 	}
261838fd1498Szrj       else
261938fd1498Szrj 	skip_multi_dir = true;
262038fd1498Szrj       if (multi_os_dir)
262138fd1498Szrj 	{
262238fd1498Szrj 	  free (CONST_CAST (char *, multi_os_dir));
262338fd1498Szrj 	  multi_os_dir = NULL;
262438fd1498Szrj 	}
262538fd1498Szrj       else
262638fd1498Szrj 	skip_multi_os_dir = true;
262738fd1498Szrj     }
262838fd1498Szrj 
262938fd1498Szrj   if (multi_dir)
263038fd1498Szrj     {
263138fd1498Szrj       free (CONST_CAST (char *, multi_dir));
263238fd1498Szrj       free (CONST_CAST (char *, multi_suffix));
263338fd1498Szrj       free (CONST_CAST (char *, just_multi_suffix));
263438fd1498Szrj     }
263538fd1498Szrj   if (multi_os_dir)
263638fd1498Szrj     free (CONST_CAST (char *, multi_os_dir));
263738fd1498Szrj   if (ret != path)
263838fd1498Szrj     free (path);
263938fd1498Szrj   return ret;
264038fd1498Szrj }
264138fd1498Szrj 
264238fd1498Szrj /* Callback for build_search_list.  Adds path to obstack being built.  */
264338fd1498Szrj 
264438fd1498Szrj struct add_to_obstack_info {
264538fd1498Szrj   struct obstack *ob;
264638fd1498Szrj   bool check_dir;
264738fd1498Szrj   bool first_time;
264838fd1498Szrj };
264938fd1498Szrj 
265038fd1498Szrj static void *
add_to_obstack(char * path,void * data)265138fd1498Szrj add_to_obstack (char *path, void *data)
265238fd1498Szrj {
265338fd1498Szrj   struct add_to_obstack_info *info = (struct add_to_obstack_info *) data;
265438fd1498Szrj 
265538fd1498Szrj   if (info->check_dir && !is_directory (path, false))
265638fd1498Szrj     return NULL;
265738fd1498Szrj 
265838fd1498Szrj   if (!info->first_time)
265938fd1498Szrj     obstack_1grow (info->ob, PATH_SEPARATOR);
266038fd1498Szrj 
266138fd1498Szrj   obstack_grow (info->ob, path, strlen (path));
266238fd1498Szrj 
266338fd1498Szrj   info->first_time = false;
266438fd1498Szrj   return NULL;
266538fd1498Szrj }
266638fd1498Szrj 
266738fd1498Szrj /* Add or change the value of an environment variable, outputting the
266838fd1498Szrj    change to standard error if in verbose mode.  */
266938fd1498Szrj static void
xputenv(const char * string)267038fd1498Szrj xputenv (const char *string)
267138fd1498Szrj {
267238fd1498Szrj   env.xput (string);
267338fd1498Szrj }
267438fd1498Szrj 
267538fd1498Szrj /* Build a list of search directories from PATHS.
267638fd1498Szrj    PREFIX is a string to prepend to the list.
267738fd1498Szrj    If CHECK_DIR_P is true we ensure the directory exists.
267838fd1498Szrj    If DO_MULTI is true, multilib paths are output first, then
267938fd1498Szrj    non-multilib paths.
268038fd1498Szrj    This is used mostly by putenv_from_prefixes so we use `collect_obstack'.
268138fd1498Szrj    It is also used by the --print-search-dirs flag.  */
268238fd1498Szrj 
268338fd1498Szrj static char *
build_search_list(const struct path_prefix * paths,const char * prefix,bool check_dir,bool do_multi)268438fd1498Szrj build_search_list (const struct path_prefix *paths, const char *prefix,
268538fd1498Szrj 		   bool check_dir, bool do_multi)
268638fd1498Szrj {
268738fd1498Szrj   struct add_to_obstack_info info;
268838fd1498Szrj 
268938fd1498Szrj   info.ob = &collect_obstack;
269038fd1498Szrj   info.check_dir = check_dir;
269138fd1498Szrj   info.first_time = true;
269238fd1498Szrj 
269338fd1498Szrj   obstack_grow (&collect_obstack, prefix, strlen (prefix));
269438fd1498Szrj   obstack_1grow (&collect_obstack, '=');
269538fd1498Szrj 
269638fd1498Szrj   for_each_path (paths, do_multi, 0, add_to_obstack, &info);
269738fd1498Szrj 
269838fd1498Szrj   obstack_1grow (&collect_obstack, '\0');
269938fd1498Szrj   return XOBFINISH (&collect_obstack, char *);
270038fd1498Szrj }
270138fd1498Szrj 
270238fd1498Szrj /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
270338fd1498Szrj    for collect.  */
270438fd1498Szrj 
270538fd1498Szrj static void
putenv_from_prefixes(const struct path_prefix * paths,const char * env_var,bool do_multi)270638fd1498Szrj putenv_from_prefixes (const struct path_prefix *paths, const char *env_var,
270738fd1498Szrj 		      bool do_multi)
270838fd1498Szrj {
270938fd1498Szrj   xputenv (build_search_list (paths, env_var, true, do_multi));
271038fd1498Szrj }
271138fd1498Szrj 
271238fd1498Szrj /* Check whether NAME can be accessed in MODE.  This is like access,
271338fd1498Szrj    except that it never considers directories to be executable.  */
271438fd1498Szrj 
271538fd1498Szrj static int
access_check(const char * name,int mode)271638fd1498Szrj access_check (const char *name, int mode)
271738fd1498Szrj {
271838fd1498Szrj   if (mode == X_OK)
271938fd1498Szrj     {
272038fd1498Szrj       struct stat st;
272138fd1498Szrj 
272238fd1498Szrj       if (stat (name, &st) < 0
272338fd1498Szrj 	  || S_ISDIR (st.st_mode))
272438fd1498Szrj 	return -1;
272538fd1498Szrj     }
272638fd1498Szrj 
272738fd1498Szrj   return access (name, mode);
272838fd1498Szrj }
272938fd1498Szrj 
273038fd1498Szrj /* Callback for find_a_file.  Appends the file name to the directory
273138fd1498Szrj    path.  If the resulting file exists in the right mode, return the
273238fd1498Szrj    full pathname to the file.  */
273338fd1498Szrj 
273438fd1498Szrj struct file_at_path_info {
273538fd1498Szrj   const char *name;
273638fd1498Szrj   const char *suffix;
273738fd1498Szrj   int name_len;
273838fd1498Szrj   int suffix_len;
273938fd1498Szrj   int mode;
274038fd1498Szrj };
274138fd1498Szrj 
274238fd1498Szrj static void *
file_at_path(char * path,void * data)274338fd1498Szrj file_at_path (char *path, void *data)
274438fd1498Szrj {
274538fd1498Szrj   struct file_at_path_info *info = (struct file_at_path_info *) data;
274638fd1498Szrj   size_t len = strlen (path);
274738fd1498Szrj 
274838fd1498Szrj   memcpy (path + len, info->name, info->name_len);
274938fd1498Szrj   len += info->name_len;
275038fd1498Szrj 
275138fd1498Szrj   /* Some systems have a suffix for executable files.
275238fd1498Szrj      So try appending that first.  */
275338fd1498Szrj   if (info->suffix_len)
275438fd1498Szrj     {
275538fd1498Szrj       memcpy (path + len, info->suffix, info->suffix_len + 1);
275638fd1498Szrj       if (access_check (path, info->mode) == 0)
275738fd1498Szrj 	return path;
275838fd1498Szrj     }
275938fd1498Szrj 
276038fd1498Szrj   path[len] = '\0';
276138fd1498Szrj   if (access_check (path, info->mode) == 0)
276238fd1498Szrj     return path;
276338fd1498Szrj 
276438fd1498Szrj   return NULL;
276538fd1498Szrj }
276638fd1498Szrj 
276738fd1498Szrj /* Search for NAME using the prefix list PREFIXES.  MODE is passed to
276838fd1498Szrj    access to check permissions.  If DO_MULTI is true, search multilib
276938fd1498Szrj    paths then non-multilib paths, otherwise do not search multilib paths.
277038fd1498Szrj    Return 0 if not found, otherwise return its name, allocated with malloc.  */
277138fd1498Szrj 
277238fd1498Szrj static char *
find_a_file(const struct path_prefix * pprefix,const char * name,int mode,bool do_multi)277338fd1498Szrj find_a_file (const struct path_prefix *pprefix, const char *name, int mode,
277438fd1498Szrj 	     bool do_multi)
277538fd1498Szrj {
277638fd1498Szrj   struct file_at_path_info info;
277738fd1498Szrj 
277838fd1498Szrj #ifdef DEFAULT_ASSEMBLER
277938fd1498Szrj   if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
278038fd1498Szrj     return xstrdup (DEFAULT_ASSEMBLER);
278138fd1498Szrj #endif
278238fd1498Szrj 
278338fd1498Szrj #ifdef DEFAULT_LINKER
278438fd1498Szrj   if (! strcmp (name, "ld") && access (DEFAULT_LINKER, mode) == 0)
278538fd1498Szrj     return xstrdup (DEFAULT_LINKER);
278638fd1498Szrj #endif
278738fd1498Szrj 
278838fd1498Szrj   /* Determine the filename to execute (special case for absolute paths).  */
278938fd1498Szrj 
279038fd1498Szrj   if (IS_ABSOLUTE_PATH (name))
279138fd1498Szrj     {
279238fd1498Szrj       if (access (name, mode) == 0)
279338fd1498Szrj 	return xstrdup (name);
279438fd1498Szrj 
279538fd1498Szrj       return NULL;
279638fd1498Szrj     }
279738fd1498Szrj 
279838fd1498Szrj   info.name = name;
279938fd1498Szrj   info.suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
280038fd1498Szrj   info.name_len = strlen (info.name);
280138fd1498Szrj   info.suffix_len = strlen (info.suffix);
280238fd1498Szrj   info.mode = mode;
280338fd1498Szrj 
280438fd1498Szrj   return (char*) for_each_path (pprefix, do_multi,
280538fd1498Szrj 				info.name_len + info.suffix_len,
280638fd1498Szrj 				file_at_path, &info);
280738fd1498Szrj }
280838fd1498Szrj 
280938fd1498Szrj /* Ranking of prefixes in the sort list. -B prefixes are put before
281038fd1498Szrj    all others.  */
281138fd1498Szrj 
281238fd1498Szrj enum path_prefix_priority
281338fd1498Szrj {
281438fd1498Szrj   PREFIX_PRIORITY_B_OPT,
281538fd1498Szrj   PREFIX_PRIORITY_LAST
281638fd1498Szrj };
281738fd1498Szrj 
281838fd1498Szrj /* Add an entry for PREFIX in PLIST.  The PLIST is kept in ascending
281938fd1498Szrj    order according to PRIORITY.  Within each PRIORITY, new entries are
282038fd1498Szrj    appended.
282138fd1498Szrj 
282238fd1498Szrj    If WARN is nonzero, we will warn if no file is found
282338fd1498Szrj    through this prefix.  WARN should point to an int
282438fd1498Szrj    which will be set to 1 if this entry is used.
282538fd1498Szrj 
282638fd1498Szrj    COMPONENT is the value to be passed to update_path.
282738fd1498Szrj 
282838fd1498Szrj    REQUIRE_MACHINE_SUFFIX is 1 if this prefix can't be used without
282938fd1498Szrj    the complete value of machine_suffix.
283038fd1498Szrj    2 means try both machine_suffix and just_machine_suffix.  */
283138fd1498Szrj 
283238fd1498Szrj static void
add_prefix(struct path_prefix * pprefix,const char * prefix,const char * component,int priority,int require_machine_suffix,int os_multilib)283338fd1498Szrj add_prefix (struct path_prefix *pprefix, const char *prefix,
283438fd1498Szrj 	    const char *component, /* enum prefix_priority */ int priority,
283538fd1498Szrj 	    int require_machine_suffix, int os_multilib)
283638fd1498Szrj {
283738fd1498Szrj   struct prefix_list *pl, **prev;
283838fd1498Szrj   int len;
283938fd1498Szrj 
284038fd1498Szrj   for (prev = &pprefix->plist;
284138fd1498Szrj        (*prev) != NULL && (*prev)->priority <= priority;
284238fd1498Szrj        prev = &(*prev)->next)
284338fd1498Szrj     ;
284438fd1498Szrj 
284538fd1498Szrj   /* Keep track of the longest prefix.  */
284638fd1498Szrj 
284738fd1498Szrj   prefix = update_path (prefix, component);
284838fd1498Szrj   len = strlen (prefix);
284938fd1498Szrj   if (len > pprefix->max_len)
285038fd1498Szrj     pprefix->max_len = len;
285138fd1498Szrj 
285238fd1498Szrj   pl = XNEW (struct prefix_list);
285338fd1498Szrj   pl->prefix = prefix;
285438fd1498Szrj   pl->require_machine_suffix = require_machine_suffix;
285538fd1498Szrj   pl->priority = priority;
285638fd1498Szrj   pl->os_multilib = os_multilib;
285738fd1498Szrj 
285838fd1498Szrj   /* Insert after PREV.  */
285938fd1498Szrj   pl->next = (*prev);
286038fd1498Szrj   (*prev) = pl;
286138fd1498Szrj }
286238fd1498Szrj 
286338fd1498Szrj /* Same as add_prefix, but prepending target_system_root to prefix.  */
286438fd1498Szrj /* The target_system_root prefix has been relocated by gcc_exec_prefix.  */
286538fd1498Szrj static void
add_sysrooted_prefix(struct path_prefix * pprefix,const char * prefix,const char * component,int priority,int require_machine_suffix,int os_multilib)286638fd1498Szrj add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix,
286738fd1498Szrj 		      const char *component,
286838fd1498Szrj 		      /* enum prefix_priority */ int priority,
286938fd1498Szrj 		      int require_machine_suffix, int os_multilib)
287038fd1498Szrj {
287138fd1498Szrj   if (!IS_ABSOLUTE_PATH (prefix))
287238fd1498Szrj     fatal_error (input_location, "system path %qs is not absolute", prefix);
287338fd1498Szrj 
287438fd1498Szrj   if (target_system_root)
287538fd1498Szrj     {
287638fd1498Szrj       char *sysroot_no_trailing_dir_separator = xstrdup (target_system_root);
287738fd1498Szrj       size_t sysroot_len = strlen (target_system_root);
287838fd1498Szrj 
287938fd1498Szrj       if (sysroot_len > 0
288038fd1498Szrj 	  && target_system_root[sysroot_len - 1] == DIR_SEPARATOR)
288138fd1498Szrj 	sysroot_no_trailing_dir_separator[sysroot_len - 1] = '\0';
288238fd1498Szrj 
288338fd1498Szrj       if (target_sysroot_suffix)
288438fd1498Szrj 	prefix = concat (sysroot_no_trailing_dir_separator,
288538fd1498Szrj 			 target_sysroot_suffix, prefix, NULL);
288638fd1498Szrj       else
288738fd1498Szrj 	prefix = concat (sysroot_no_trailing_dir_separator, prefix, NULL);
288838fd1498Szrj 
288938fd1498Szrj       free (sysroot_no_trailing_dir_separator);
289038fd1498Szrj 
289138fd1498Szrj       /* We have to override this because GCC's notion of sysroot
289238fd1498Szrj 	 moves along with GCC.  */
289338fd1498Szrj       component = "GCC";
289438fd1498Szrj     }
289538fd1498Szrj 
289638fd1498Szrj   add_prefix (pprefix, prefix, component, priority,
289738fd1498Szrj 	      require_machine_suffix, os_multilib);
289838fd1498Szrj }
289938fd1498Szrj 
290038fd1498Szrj /* Execute the command specified by the arguments on the current line of spec.
290138fd1498Szrj    When using pipes, this includes several piped-together commands
290238fd1498Szrj    with `|' between them.
290338fd1498Szrj 
290438fd1498Szrj    Return 0 if successful, -1 if failed.  */
290538fd1498Szrj 
290638fd1498Szrj static int
execute(void)290738fd1498Szrj execute (void)
290838fd1498Szrj {
290938fd1498Szrj   int i;
291038fd1498Szrj   int n_commands;		/* # of command.  */
291138fd1498Szrj   char *string;
291238fd1498Szrj   struct pex_obj *pex;
291338fd1498Szrj   struct command
291438fd1498Szrj   {
291538fd1498Szrj     const char *prog;		/* program name.  */
291638fd1498Szrj     const char **argv;		/* vector of args.  */
291738fd1498Szrj   };
291838fd1498Szrj   const char *arg;
291938fd1498Szrj 
292038fd1498Szrj   struct command *commands;	/* each command buffer with above info.  */
292138fd1498Szrj 
292238fd1498Szrj   gcc_assert (!processing_spec_function);
292338fd1498Szrj 
292438fd1498Szrj   if (wrapper_string)
292538fd1498Szrj     {
292638fd1498Szrj       string = find_a_file (&exec_prefixes,
292738fd1498Szrj 			    argbuf[0], X_OK, false);
292838fd1498Szrj       if (string)
292938fd1498Szrj 	argbuf[0] = string;
293038fd1498Szrj       insert_wrapper (wrapper_string);
293138fd1498Szrj     }
293238fd1498Szrj 
293338fd1498Szrj   /* Count # of piped commands.  */
293438fd1498Szrj   for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++)
293538fd1498Szrj     if (strcmp (arg, "|") == 0)
293638fd1498Szrj       n_commands++;
293738fd1498Szrj 
293838fd1498Szrj   /* Get storage for each command.  */
293938fd1498Szrj   commands = (struct command *) alloca (n_commands * sizeof (struct command));
294038fd1498Szrj 
294138fd1498Szrj   /* Split argbuf into its separate piped processes,
294238fd1498Szrj      and record info about each one.
294338fd1498Szrj      Also search for the programs that are to be run.  */
294438fd1498Szrj 
294538fd1498Szrj   argbuf.safe_push (0);
294638fd1498Szrj 
294738fd1498Szrj   commands[0].prog = argbuf[0]; /* first command.  */
294838fd1498Szrj   commands[0].argv = argbuf.address ();
294938fd1498Szrj 
295038fd1498Szrj   if (!wrapper_string)
295138fd1498Szrj     {
295238fd1498Szrj       string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false);
295338fd1498Szrj       commands[0].argv[0] = (string) ? string : commands[0].argv[0];
295438fd1498Szrj     }
295538fd1498Szrj 
295638fd1498Szrj   for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++)
295738fd1498Szrj     if (arg && strcmp (arg, "|") == 0)
295838fd1498Szrj       {				/* each command.  */
295938fd1498Szrj #if defined (__MSDOS__) || defined (OS2) || defined (VMS)
296038fd1498Szrj 	fatal_error (input_location, "-pipe not supported");
296138fd1498Szrj #endif
296238fd1498Szrj 	argbuf[i] = 0; /* Termination of
296338fd1498Szrj 						     command args.  */
296438fd1498Szrj 	commands[n_commands].prog = argbuf[i + 1];
296538fd1498Szrj 	commands[n_commands].argv
296638fd1498Szrj 	  = &(argbuf.address ())[i + 1];
296738fd1498Szrj 	string = find_a_file (&exec_prefixes, commands[n_commands].prog,
296838fd1498Szrj 			      X_OK, false);
296938fd1498Szrj 	if (string)
297038fd1498Szrj 	  commands[n_commands].argv[0] = string;
297138fd1498Szrj 	n_commands++;
297238fd1498Szrj       }
297338fd1498Szrj 
297438fd1498Szrj   /* If -v, print what we are about to do, and maybe query.  */
297538fd1498Szrj 
297638fd1498Szrj   if (verbose_flag)
297738fd1498Szrj     {
297838fd1498Szrj       /* For help listings, put a blank line between sub-processes.  */
297938fd1498Szrj       if (print_help_list)
298038fd1498Szrj 	fputc ('\n', stderr);
298138fd1498Szrj 
298238fd1498Szrj       /* Print each piped command as a separate line.  */
298338fd1498Szrj       for (i = 0; i < n_commands; i++)
298438fd1498Szrj 	{
298538fd1498Szrj 	  const char *const *j;
298638fd1498Szrj 
298738fd1498Szrj 	  if (verbose_only_flag)
298838fd1498Szrj 	    {
298938fd1498Szrj 	      for (j = commands[i].argv; *j; j++)
299038fd1498Szrj 		{
299138fd1498Szrj 		  const char *p;
299238fd1498Szrj 		  for (p = *j; *p; ++p)
299338fd1498Szrj 		    if (!ISALNUM ((unsigned char) *p)
299438fd1498Szrj 			&& *p != '_' && *p != '/' && *p != '-' && *p != '.')
299538fd1498Szrj 		      break;
299638fd1498Szrj 		  if (*p || !*j)
299738fd1498Szrj 		    {
299838fd1498Szrj 		      fprintf (stderr, " \"");
299938fd1498Szrj 		      for (p = *j; *p; ++p)
300038fd1498Szrj 			{
300138fd1498Szrj 			  if (*p == '"' || *p == '\\' || *p == '$')
300238fd1498Szrj 			    fputc ('\\', stderr);
300338fd1498Szrj 			  fputc (*p, stderr);
300438fd1498Szrj 			}
300538fd1498Szrj 		      fputc ('"', stderr);
300638fd1498Szrj 		    }
300738fd1498Szrj 		  /* If it's empty, print "".  */
300838fd1498Szrj 		  else if (!**j)
300938fd1498Szrj 		    fprintf (stderr, " \"\"");
301038fd1498Szrj 		  else
301138fd1498Szrj 		    fprintf (stderr, " %s", *j);
301238fd1498Szrj 		}
301338fd1498Szrj 	    }
301438fd1498Szrj 	  else
301538fd1498Szrj 	    for (j = commands[i].argv; *j; j++)
301638fd1498Szrj 	      /* If it's empty, print "".  */
301738fd1498Szrj 	      if (!**j)
301838fd1498Szrj 		fprintf (stderr, " \"\"");
301938fd1498Szrj 	      else
302038fd1498Szrj 		fprintf (stderr, " %s", *j);
302138fd1498Szrj 
302238fd1498Szrj 	  /* Print a pipe symbol after all but the last command.  */
302338fd1498Szrj 	  if (i + 1 != n_commands)
302438fd1498Szrj 	    fprintf (stderr, " |");
302538fd1498Szrj 	  fprintf (stderr, "\n");
302638fd1498Szrj 	}
302738fd1498Szrj       fflush (stderr);
302838fd1498Szrj       if (verbose_only_flag != 0)
302938fd1498Szrj         {
303038fd1498Szrj 	  /* verbose_only_flag should act as if the spec was
303138fd1498Szrj 	     executed, so increment execution_count before
303238fd1498Szrj 	     returning.  This prevents spurious warnings about
303338fd1498Szrj 	     unused linker input files, etc.  */
303438fd1498Szrj 	  execution_count++;
303538fd1498Szrj 	  return 0;
303638fd1498Szrj         }
303738fd1498Szrj #ifdef DEBUG
303838fd1498Szrj       fnotice (stderr, "\nGo ahead? (y or n) ");
303938fd1498Szrj       fflush (stderr);
304038fd1498Szrj       i = getchar ();
304138fd1498Szrj       if (i != '\n')
304238fd1498Szrj 	while (getchar () != '\n')
304338fd1498Szrj 	  ;
304438fd1498Szrj 
304538fd1498Szrj       if (i != 'y' && i != 'Y')
304638fd1498Szrj 	return 0;
304738fd1498Szrj #endif /* DEBUG */
304838fd1498Szrj     }
304938fd1498Szrj 
305038fd1498Szrj #ifdef ENABLE_VALGRIND_CHECKING
305138fd1498Szrj   /* Run the each command through valgrind.  To simplify prepending the
305238fd1498Szrj      path to valgrind and the option "-q" (for quiet operation unless
305338fd1498Szrj      something triggers), we allocate a separate argv array.  */
305438fd1498Szrj 
305538fd1498Szrj   for (i = 0; i < n_commands; i++)
305638fd1498Szrj     {
305738fd1498Szrj       const char **argv;
305838fd1498Szrj       int argc;
305938fd1498Szrj       int j;
306038fd1498Szrj 
306138fd1498Szrj       for (argc = 0; commands[i].argv[argc] != NULL; argc++)
306238fd1498Szrj 	;
306338fd1498Szrj 
306438fd1498Szrj       argv = XALLOCAVEC (const char *, argc + 3);
306538fd1498Szrj 
306638fd1498Szrj       argv[0] = VALGRIND_PATH;
306738fd1498Szrj       argv[1] = "-q";
306838fd1498Szrj       for (j = 2; j < argc + 2; j++)
306938fd1498Szrj 	argv[j] = commands[i].argv[j - 2];
307038fd1498Szrj       argv[j] = NULL;
307138fd1498Szrj 
307238fd1498Szrj       commands[i].argv = argv;
307338fd1498Szrj       commands[i].prog = argv[0];
307438fd1498Szrj     }
307538fd1498Szrj #endif
307638fd1498Szrj 
307738fd1498Szrj   /* Run each piped subprocess.  */
307838fd1498Szrj 
307938fd1498Szrj   pex = pex_init (PEX_USE_PIPES | ((report_times || report_times_to_file)
308038fd1498Szrj 				   ? PEX_RECORD_TIMES : 0),
308138fd1498Szrj 		  progname, temp_filename);
308238fd1498Szrj   if (pex == NULL)
308338fd1498Szrj     fatal_error (input_location, "pex_init failed: %m");
308438fd1498Szrj 
308538fd1498Szrj   for (i = 0; i < n_commands; i++)
308638fd1498Szrj     {
308738fd1498Szrj       const char *errmsg;
308838fd1498Szrj       int err;
308938fd1498Szrj       const char *string = commands[i].argv[0];
309038fd1498Szrj 
309138fd1498Szrj       errmsg = pex_run (pex,
309238fd1498Szrj 			((i + 1 == n_commands ? PEX_LAST : 0)
309338fd1498Szrj 			 | (string == commands[i].prog ? PEX_SEARCH : 0)),
309438fd1498Szrj 			string, CONST_CAST (char **, commands[i].argv),
309538fd1498Szrj 			NULL, NULL, &err);
309638fd1498Szrj       if (errmsg != NULL)
309738fd1498Szrj 	{
309838fd1498Szrj 	  if (err == 0)
309938fd1498Szrj 	    fatal_error (input_location, errmsg);
310038fd1498Szrj 	  else
310138fd1498Szrj 	    {
310238fd1498Szrj 	      errno = err;
310338fd1498Szrj 	      pfatal_with_name (errmsg);
310438fd1498Szrj 	    }
310538fd1498Szrj 	}
310638fd1498Szrj 
310738fd1498Szrj       if (i && string != commands[i].prog)
310838fd1498Szrj 	free (CONST_CAST (char *, string));
310938fd1498Szrj     }
311038fd1498Szrj 
311138fd1498Szrj   execution_count++;
311238fd1498Szrj 
311338fd1498Szrj   /* Wait for all the subprocesses to finish.  */
311438fd1498Szrj 
311538fd1498Szrj   {
311638fd1498Szrj     int *statuses;
311738fd1498Szrj     struct pex_time *times = NULL;
311838fd1498Szrj     int ret_code = 0;
311938fd1498Szrj 
312038fd1498Szrj     statuses = (int *) alloca (n_commands * sizeof (int));
312138fd1498Szrj     if (!pex_get_status (pex, n_commands, statuses))
312238fd1498Szrj       fatal_error (input_location, "failed to get exit status: %m");
312338fd1498Szrj 
312438fd1498Szrj     if (report_times || report_times_to_file)
312538fd1498Szrj       {
312638fd1498Szrj 	times = (struct pex_time *) alloca (n_commands * sizeof (struct pex_time));
312738fd1498Szrj 	if (!pex_get_times (pex, n_commands, times))
312838fd1498Szrj 	  fatal_error (input_location, "failed to get process times: %m");
312938fd1498Szrj       }
313038fd1498Szrj 
313138fd1498Szrj     pex_free (pex);
313238fd1498Szrj 
313338fd1498Szrj     for (i = 0; i < n_commands; ++i)
313438fd1498Szrj       {
313538fd1498Szrj 	int status = statuses[i];
313638fd1498Szrj 
313738fd1498Szrj 	if (WIFSIGNALED (status))
313838fd1498Szrj 	  switch (WTERMSIG (status))
313938fd1498Szrj 	    {
314038fd1498Szrj 	    case SIGINT:
314138fd1498Szrj 	    case SIGTERM:
314238fd1498Szrj 	      /* SIGQUIT and SIGKILL are not available on MinGW.  */
314338fd1498Szrj #ifdef SIGQUIT
314438fd1498Szrj 	    case SIGQUIT:
314538fd1498Szrj #endif
314638fd1498Szrj #ifdef SIGKILL
314738fd1498Szrj 	    case SIGKILL:
314838fd1498Szrj #endif
314938fd1498Szrj 	      /* The user (or environment) did something to the
315038fd1498Szrj 		 inferior.  Making this an ICE confuses the user into
315138fd1498Szrj 		 thinking there's a compiler bug.  Much more likely is
315238fd1498Szrj 		 the user or OOM killer nuked it.  */
315338fd1498Szrj 	      fatal_error (input_location,
315438fd1498Szrj 			   "%s signal terminated program %s",
315538fd1498Szrj 			   strsignal (WTERMSIG (status)),
315638fd1498Szrj 			   commands[i].prog);
315738fd1498Szrj 	      break;
315838fd1498Szrj 
315938fd1498Szrj #ifdef SIGPIPE
316038fd1498Szrj 	    case SIGPIPE:
316138fd1498Szrj 	      /* SIGPIPE is a special case.  It happens in -pipe mode
316238fd1498Szrj 		 when the compiler dies before the preprocessor is
316338fd1498Szrj 		 done, or the assembler dies before the compiler is
316438fd1498Szrj 		 done.  There's generally been an error already, and
316538fd1498Szrj 		 this is just fallout.  So don't generate another
316638fd1498Szrj 		 error unless we would otherwise have succeeded.  */
316738fd1498Szrj 	      if (signal_count || greatest_status >= MIN_FATAL_STATUS)
316838fd1498Szrj 		{
316938fd1498Szrj 		  signal_count++;
317038fd1498Szrj 		  ret_code = -1;
317138fd1498Szrj 		  break;
317238fd1498Szrj 		}
317338fd1498Szrj #endif
317438fd1498Szrj 	      /* FALLTHROUGH */
317538fd1498Szrj 
317638fd1498Szrj 	    default:
317738fd1498Szrj 	      /* The inferior failed to catch the signal.  */
317838fd1498Szrj 	      internal_error_no_backtrace ("%s signal terminated program %s",
317938fd1498Szrj 					   strsignal (WTERMSIG (status)),
318038fd1498Szrj 					   commands[i].prog);
318138fd1498Szrj 	    }
318238fd1498Szrj 	else if (WIFEXITED (status)
318338fd1498Szrj 		 && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
318438fd1498Szrj 	  {
318538fd1498Szrj 	    /* For ICEs in cc1, cc1obj, cc1plus see if it is
318638fd1498Szrj 	       reproducible or not.  */
318738fd1498Szrj 	    const char *p;
318838fd1498Szrj 	    if (flag_report_bug
318938fd1498Szrj 		&& WEXITSTATUS (status) == ICE_EXIT_CODE
319038fd1498Szrj 		&& i == 0
319138fd1498Szrj 		&& (p = strrchr (commands[0].argv[0], DIR_SEPARATOR))
319238fd1498Szrj 		&& ! strncmp (p + 1, "cc1", 3))
319338fd1498Szrj 	      try_generate_repro (commands[0].argv);
319438fd1498Szrj 	    if (WEXITSTATUS (status) > greatest_status)
319538fd1498Szrj 	      greatest_status = WEXITSTATUS (status);
319638fd1498Szrj 	    ret_code = -1;
319738fd1498Szrj 	  }
319838fd1498Szrj 
319938fd1498Szrj 	if (report_times || report_times_to_file)
320038fd1498Szrj 	  {
320138fd1498Szrj 	    struct pex_time *pt = &times[i];
320238fd1498Szrj 	    double ut, st;
320338fd1498Szrj 
320438fd1498Szrj 	    ut = ((double) pt->user_seconds
320538fd1498Szrj 		  + (double) pt->user_microseconds / 1.0e6);
320638fd1498Szrj 	    st = ((double) pt->system_seconds
320738fd1498Szrj 		  + (double) pt->system_microseconds / 1.0e6);
320838fd1498Szrj 
320938fd1498Szrj 	    if (ut + st != 0)
321038fd1498Szrj 	      {
321138fd1498Szrj 		if (report_times)
321238fd1498Szrj 		  fnotice (stderr, "# %s %.2f %.2f\n",
321338fd1498Szrj 			   commands[i].prog, ut, st);
321438fd1498Szrj 
321538fd1498Szrj 		if (report_times_to_file)
321638fd1498Szrj 		  {
321738fd1498Szrj 		    int c = 0;
321838fd1498Szrj 		    const char *const *j;
321938fd1498Szrj 
322038fd1498Szrj 		    fprintf (report_times_to_file, "%g %g", ut, st);
322138fd1498Szrj 
322238fd1498Szrj 		    for (j = &commands[i].prog; *j; j = &commands[i].argv[++c])
322338fd1498Szrj 		      {
322438fd1498Szrj 			const char *p;
322538fd1498Szrj 			for (p = *j; *p; ++p)
322638fd1498Szrj 			  if (*p == '"' || *p == '\\' || *p == '$'
322738fd1498Szrj 			      || ISSPACE (*p))
322838fd1498Szrj 			    break;
322938fd1498Szrj 
323038fd1498Szrj 			if (*p)
323138fd1498Szrj 			  {
323238fd1498Szrj 			    fprintf (report_times_to_file, " \"");
323338fd1498Szrj 			    for (p = *j; *p; ++p)
323438fd1498Szrj 			      {
323538fd1498Szrj 				if (*p == '"' || *p == '\\' || *p == '$')
323638fd1498Szrj 				  fputc ('\\', report_times_to_file);
323738fd1498Szrj 				fputc (*p, report_times_to_file);
323838fd1498Szrj 			      }
323938fd1498Szrj 			    fputc ('"', report_times_to_file);
324038fd1498Szrj 			  }
324138fd1498Szrj 			else
324238fd1498Szrj 			  fprintf (report_times_to_file, " %s", *j);
324338fd1498Szrj 		      }
324438fd1498Szrj 
324538fd1498Szrj 		    fputc ('\n', report_times_to_file);
324638fd1498Szrj 		  }
324738fd1498Szrj 	      }
324838fd1498Szrj 	  }
324938fd1498Szrj       }
325038fd1498Szrj 
325138fd1498Szrj    if (commands[0].argv[0] != commands[0].prog)
325238fd1498Szrj      free (CONST_CAST (char *, commands[0].argv[0]));
325338fd1498Szrj 
325438fd1498Szrj     return ret_code;
325538fd1498Szrj   }
325638fd1498Szrj }
325738fd1498Szrj 
325838fd1498Szrj /* Find all the switches given to us
325938fd1498Szrj    and make a vector describing them.
326038fd1498Szrj    The elements of the vector are strings, one per switch given.
326138fd1498Szrj    If a switch uses following arguments, then the `part1' field
326238fd1498Szrj    is the switch itself and the `args' field
326338fd1498Szrj    is a null-terminated vector containing the following arguments.
326438fd1498Szrj    Bits in the `live_cond' field are:
326538fd1498Szrj    SWITCH_LIVE to indicate this switch is true in a conditional spec.
326638fd1498Szrj    SWITCH_FALSE to indicate this switch is overridden by a later switch.
326738fd1498Szrj    SWITCH_IGNORE to indicate this switch should be ignored (used in %<S).
326838fd1498Szrj    SWITCH_IGNORE_PERMANENTLY to indicate this switch should be ignored.
326938fd1498Szrj    SWITCH_KEEP_FOR_GCC to indicate that this switch, otherwise ignored,
327038fd1498Szrj    should be included in COLLECT_GCC_OPTIONS.
327138fd1498Szrj    in all do_spec calls afterwards.  Used for %<S from self specs.
327238fd1498Szrj    The `known' field describes whether this is an internal switch.
327338fd1498Szrj    The `validated' field describes whether any spec has looked at this switch;
327438fd1498Szrj    if it remains false at the end of the run, the switch must be meaningless.
327538fd1498Szrj    The `ordering' field is used to temporarily mark switches that have to be
327638fd1498Szrj    kept in a specific order.  */
327738fd1498Szrj 
327838fd1498Szrj #define SWITCH_LIVE    			(1 << 0)
327938fd1498Szrj #define SWITCH_FALSE   			(1 << 1)
328038fd1498Szrj #define SWITCH_IGNORE			(1 << 2)
328138fd1498Szrj #define SWITCH_IGNORE_PERMANENTLY	(1 << 3)
328238fd1498Szrj #define SWITCH_KEEP_FOR_GCC		(1 << 4)
328338fd1498Szrj 
328438fd1498Szrj struct switchstr
328538fd1498Szrj {
328638fd1498Szrj   const char *part1;
328738fd1498Szrj   const char **args;
328838fd1498Szrj   unsigned int live_cond;
328938fd1498Szrj   bool known;
329038fd1498Szrj   bool validated;
329138fd1498Szrj   bool ordering;
329238fd1498Szrj };
329338fd1498Szrj 
329438fd1498Szrj static struct switchstr *switches;
329538fd1498Szrj 
329638fd1498Szrj static int n_switches;
329738fd1498Szrj 
329838fd1498Szrj static int n_switches_alloc;
329938fd1498Szrj 
330038fd1498Szrj /* Set to zero if -fcompare-debug is disabled, positive if it's
330138fd1498Szrj    enabled and we're running the first compilation, negative if it's
330238fd1498Szrj    enabled and we're running the second compilation.  For most of the
330338fd1498Szrj    time, it's in the range -1..1, but it can be temporarily set to 2
330438fd1498Szrj    or 3 to indicate that the -fcompare-debug flags didn't come from
330538fd1498Szrj    the command-line, but rather from the GCC_COMPARE_DEBUG environment
330638fd1498Szrj    variable, until a synthesized -fcompare-debug flag is added to the
330738fd1498Szrj    command line.  */
330838fd1498Szrj int compare_debug;
330938fd1498Szrj 
331038fd1498Szrj /* Set to nonzero if we've seen the -fcompare-debug-second flag.  */
331138fd1498Szrj int compare_debug_second;
331238fd1498Szrj 
331338fd1498Szrj /* Set to the flags that should be passed to the second compilation in
331438fd1498Szrj    a -fcompare-debug compilation.  */
331538fd1498Szrj const char *compare_debug_opt;
331638fd1498Szrj 
331738fd1498Szrj static struct switchstr *switches_debug_check[2];
331838fd1498Szrj 
331938fd1498Szrj static int n_switches_debug_check[2];
332038fd1498Szrj 
332138fd1498Szrj static int n_switches_alloc_debug_check[2];
332238fd1498Szrj 
332338fd1498Szrj static char *debug_check_temp_file[2];
332438fd1498Szrj 
332538fd1498Szrj /* Language is one of three things:
332638fd1498Szrj 
332738fd1498Szrj    1) The name of a real programming language.
332838fd1498Szrj    2) NULL, indicating that no one has figured out
332938fd1498Szrj    what it is yet.
333038fd1498Szrj    3) '*', indicating that the file should be passed
333138fd1498Szrj    to the linker.  */
333238fd1498Szrj struct infile
333338fd1498Szrj {
333438fd1498Szrj   const char *name;
333538fd1498Szrj   const char *language;
333638fd1498Szrj   struct compiler *incompiler;
333738fd1498Szrj   bool compiled;
333838fd1498Szrj   bool preprocessed;
333938fd1498Szrj };
334038fd1498Szrj 
334138fd1498Szrj /* Also a vector of input files specified.  */
334238fd1498Szrj 
334338fd1498Szrj static struct infile *infiles;
334438fd1498Szrj 
334538fd1498Szrj int n_infiles;
334638fd1498Szrj 
334738fd1498Szrj static int n_infiles_alloc;
334838fd1498Szrj 
334938fd1498Szrj /* True if undefined environment variables encountered during spec processing
335038fd1498Szrj    are ok to ignore, typically when we're running for --help or --version.  */
335138fd1498Szrj 
335238fd1498Szrj static bool spec_undefvar_allowed;
335338fd1498Szrj 
335438fd1498Szrj /* True if multiple input files are being compiled to a single
335538fd1498Szrj    assembly file.  */
335638fd1498Szrj 
335738fd1498Szrj static bool combine_inputs;
335838fd1498Szrj 
335938fd1498Szrj /* This counts the number of libraries added by lang_specific_driver, so that
336038fd1498Szrj    we can tell if there were any user supplied any files or libraries.  */
336138fd1498Szrj 
336238fd1498Szrj static int added_libraries;
336338fd1498Szrj 
336438fd1498Szrj /* And a vector of corresponding output files is made up later.  */
336538fd1498Szrj 
336638fd1498Szrj const char **outfiles;
336738fd1498Szrj 
336838fd1498Szrj #if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
336938fd1498Szrj 
337038fd1498Szrj /* Convert NAME to a new name if it is the standard suffix.  DO_EXE
337138fd1498Szrj    is true if we should look for an executable suffix.  DO_OBJ
337238fd1498Szrj    is true if we should look for an object suffix.  */
337338fd1498Szrj 
337438fd1498Szrj static const char *
convert_filename(const char * name,int do_exe ATTRIBUTE_UNUSED,int do_obj ATTRIBUTE_UNUSED)337538fd1498Szrj convert_filename (const char *name, int do_exe ATTRIBUTE_UNUSED,
337638fd1498Szrj 		  int do_obj ATTRIBUTE_UNUSED)
337738fd1498Szrj {
337838fd1498Szrj #if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
337938fd1498Szrj   int i;
338038fd1498Szrj #endif
338138fd1498Szrj   int len;
338238fd1498Szrj 
338338fd1498Szrj   if (name == NULL)
338438fd1498Szrj     return NULL;
338538fd1498Szrj 
338638fd1498Szrj   len = strlen (name);
338738fd1498Szrj 
338838fd1498Szrj #ifdef HAVE_TARGET_OBJECT_SUFFIX
338938fd1498Szrj   /* Convert x.o to x.obj if TARGET_OBJECT_SUFFIX is ".obj".  */
339038fd1498Szrj   if (do_obj && len > 2
339138fd1498Szrj       && name[len - 2] == '.'
339238fd1498Szrj       && name[len - 1] == 'o')
339338fd1498Szrj     {
339438fd1498Szrj       obstack_grow (&obstack, name, len - 2);
339538fd1498Szrj       obstack_grow0 (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX));
339638fd1498Szrj       name = XOBFINISH (&obstack, const char *);
339738fd1498Szrj     }
339838fd1498Szrj #endif
339938fd1498Szrj 
340038fd1498Szrj #if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
340138fd1498Szrj   /* If there is no filetype, make it the executable suffix (which includes
340238fd1498Szrj      the ".").  But don't get confused if we have just "-o".  */
340338fd1498Szrj   if (! do_exe || TARGET_EXECUTABLE_SUFFIX[0] == 0 || (len == 2 && name[0] == '-'))
340438fd1498Szrj     return name;
340538fd1498Szrj 
340638fd1498Szrj   for (i = len - 1; i >= 0; i--)
340738fd1498Szrj     if (IS_DIR_SEPARATOR (name[i]))
340838fd1498Szrj       break;
340938fd1498Szrj 
341038fd1498Szrj   for (i++; i < len; i++)
341138fd1498Szrj     if (name[i] == '.')
341238fd1498Szrj       return name;
341338fd1498Szrj 
341438fd1498Szrj   obstack_grow (&obstack, name, len);
341538fd1498Szrj   obstack_grow0 (&obstack, TARGET_EXECUTABLE_SUFFIX,
341638fd1498Szrj 		 strlen (TARGET_EXECUTABLE_SUFFIX));
341738fd1498Szrj   name = XOBFINISH (&obstack, const char *);
341838fd1498Szrj #endif
341938fd1498Szrj 
342038fd1498Szrj   return name;
342138fd1498Szrj }
342238fd1498Szrj #endif
342338fd1498Szrj 
342438fd1498Szrj /* Display the command line switches accepted by gcc.  */
342538fd1498Szrj static void
display_help(void)342638fd1498Szrj display_help (void)
342738fd1498Szrj {
342838fd1498Szrj   printf (_("Usage: %s [options] file...\n"), progname);
342938fd1498Szrj   fputs (_("Options:\n"), stdout);
343038fd1498Szrj 
343138fd1498Szrj   fputs (_("  -pass-exit-codes         Exit with highest error code from a phase.\n"), stdout);
343238fd1498Szrj   fputs (_("  --help                   Display this information.\n"), stdout);
343338fd1498Szrj   fputs (_("  --target-help            Display target specific command line options.\n"), stdout);
343438fd1498Szrj   fputs (_("  --help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...].\n"), stdout);
343538fd1498Szrj   fputs (_("                           Display specific types of command line options.\n"), stdout);
343638fd1498Szrj   if (! verbose_flag)
343738fd1498Szrj     fputs (_("  (Use '-v --help' to display command line options of sub-processes).\n"), stdout);
343838fd1498Szrj   fputs (_("  --version                Display compiler version information.\n"), stdout);
343938fd1498Szrj   fputs (_("  -dumpspecs               Display all of the built in spec strings.\n"), stdout);
344038fd1498Szrj   fputs (_("  -dumpversion             Display the version of the compiler.\n"), stdout);
344138fd1498Szrj   fputs (_("  -dumpmachine             Display the compiler's target processor.\n"), stdout);
344238fd1498Szrj   fputs (_("  -print-search-dirs       Display the directories in the compiler's search path.\n"), stdout);
344338fd1498Szrj   fputs (_("  -print-libgcc-file-name  Display the name of the compiler's companion library.\n"), stdout);
344438fd1498Szrj   fputs (_("  -print-file-name=<lib>   Display the full path to library <lib>.\n"), stdout);
344538fd1498Szrj   fputs (_("  -print-prog-name=<prog>  Display the full path to compiler component <prog>.\n"), stdout);
344638fd1498Szrj   fputs (_("\
344738fd1498Szrj   -print-multiarch         Display the target's normalized GNU triplet, used as\n\
344838fd1498Szrj                            a component in the library path.\n"), stdout);
344938fd1498Szrj   fputs (_("  -print-multi-directory   Display the root directory for versions of libgcc.\n"), stdout);
345038fd1498Szrj   fputs (_("\
345138fd1498Szrj   -print-multi-lib         Display the mapping between command line options and\n\
345238fd1498Szrj                            multiple library search directories.\n"), stdout);
345338fd1498Szrj   fputs (_("  -print-multi-os-directory Display the relative path to OS libraries.\n"), stdout);
345438fd1498Szrj   fputs (_("  -print-sysroot           Display the target libraries directory.\n"), stdout);
345538fd1498Szrj   fputs (_("  -print-sysroot-headers-suffix Display the sysroot suffix used to find headers.\n"), stdout);
345638fd1498Szrj   fputs (_("  -Wa,<options>            Pass comma-separated <options> on to the assembler.\n"), stdout);
345738fd1498Szrj   fputs (_("  -Wp,<options>            Pass comma-separated <options> on to the preprocessor.\n"), stdout);
345838fd1498Szrj   fputs (_("  -Wl,<options>            Pass comma-separated <options> on to the linker.\n"), stdout);
345938fd1498Szrj   fputs (_("  -Xassembler <arg>        Pass <arg> on to the assembler.\n"), stdout);
346038fd1498Szrj   fputs (_("  -Xpreprocessor <arg>     Pass <arg> on to the preprocessor.\n"), stdout);
346138fd1498Szrj   fputs (_("  -Xlinker <arg>           Pass <arg> on to the linker.\n"), stdout);
346238fd1498Szrj   fputs (_("  -save-temps              Do not delete intermediate files.\n"), stdout);
346338fd1498Szrj   fputs (_("  -save-temps=<arg>        Do not delete intermediate files.\n"), stdout);
346438fd1498Szrj   fputs (_("\
346538fd1498Szrj   -no-canonical-prefixes   Do not canonicalize paths when building relative\n\
346638fd1498Szrj                            prefixes to other gcc components.\n"), stdout);
346738fd1498Szrj   fputs (_("  -pipe                    Use pipes rather than intermediate files.\n"), stdout);
346838fd1498Szrj   fputs (_("  -time                    Time the execution of each subprocess.\n"), stdout);
346938fd1498Szrj   fputs (_("  -specs=<file>            Override built-in specs with the contents of <file>.\n"), stdout);
347038fd1498Szrj   fputs (_("  -std=<standard>          Assume that the input sources are for <standard>.\n"), stdout);
347138fd1498Szrj   fputs (_("\
347238fd1498Szrj   --sysroot=<directory>    Use <directory> as the root directory for headers\n\
347338fd1498Szrj                            and libraries.\n"), stdout);
347438fd1498Szrj   fputs (_("  -B <directory>           Add <directory> to the compiler's search paths.\n"), stdout);
347538fd1498Szrj   fputs (_("  -v                       Display the programs invoked by the compiler.\n"), stdout);
347638fd1498Szrj   fputs (_("  -###                     Like -v but options quoted and commands not executed.\n"), stdout);
347738fd1498Szrj   fputs (_("  -E                       Preprocess only; do not compile, assemble or link.\n"), stdout);
347838fd1498Szrj   fputs (_("  -S                       Compile only; do not assemble or link.\n"), stdout);
347938fd1498Szrj   fputs (_("  -c                       Compile and assemble, but do not link.\n"), stdout);
348038fd1498Szrj   fputs (_("  -o <file>                Place the output into <file>.\n"), stdout);
348138fd1498Szrj   fputs (_("  -pie                     Create a dynamically linked position independent\n\
348238fd1498Szrj                            executable.\n"), stdout);
348338fd1498Szrj   fputs (_("  -shared                  Create a shared library.\n"), stdout);
348438fd1498Szrj   fputs (_("\
348538fd1498Szrj   -x <language>            Specify the language of the following input files.\n\
348638fd1498Szrj                            Permissible languages include: c c++ assembler none\n\
348738fd1498Szrj                            'none' means revert to the default behavior of\n\
348838fd1498Szrj                            guessing the language based on the file's extension.\n\
348938fd1498Szrj "), stdout);
349038fd1498Szrj 
349138fd1498Szrj   printf (_("\
349238fd1498Szrj \nOptions starting with -g, -f, -m, -O, -W, or --param are automatically\n\
349338fd1498Szrj  passed on to the various sub-processes invoked by %s.  In order to pass\n\
349438fd1498Szrj  other options on to these processes the -W<letter> options must be used.\n\
349538fd1498Szrj "), progname);
349638fd1498Szrj 
349738fd1498Szrj   /* The rest of the options are displayed by invocations of the various
349838fd1498Szrj      sub-processes.  */
349938fd1498Szrj }
350038fd1498Szrj 
350138fd1498Szrj static void
add_preprocessor_option(const char * option,int len)350238fd1498Szrj add_preprocessor_option (const char *option, int len)
350338fd1498Szrj {
350438fd1498Szrj   preprocessor_options.safe_push (save_string (option, len));
350538fd1498Szrj }
350638fd1498Szrj 
350738fd1498Szrj static void
add_assembler_option(const char * option,int len)350838fd1498Szrj add_assembler_option (const char *option, int len)
350938fd1498Szrj {
351038fd1498Szrj   assembler_options.safe_push (save_string (option, len));
351138fd1498Szrj }
351238fd1498Szrj 
351338fd1498Szrj static void
add_linker_option(const char * option,int len)351438fd1498Szrj add_linker_option (const char *option, int len)
351538fd1498Szrj {
351638fd1498Szrj   linker_options.safe_push (save_string (option, len));
351738fd1498Szrj }
351838fd1498Szrj 
351938fd1498Szrj /* Allocate space for an input file in infiles.  */
352038fd1498Szrj 
352138fd1498Szrj static void
alloc_infile(void)352238fd1498Szrj alloc_infile (void)
352338fd1498Szrj {
352438fd1498Szrj   if (n_infiles_alloc == 0)
352538fd1498Szrj     {
352638fd1498Szrj       n_infiles_alloc = 16;
352738fd1498Szrj       infiles = XNEWVEC (struct infile, n_infiles_alloc);
352838fd1498Szrj     }
352938fd1498Szrj   else if (n_infiles_alloc == n_infiles)
353038fd1498Szrj     {
353138fd1498Szrj       n_infiles_alloc *= 2;
353238fd1498Szrj       infiles = XRESIZEVEC (struct infile, infiles, n_infiles_alloc);
353338fd1498Szrj     }
353438fd1498Szrj }
353538fd1498Szrj 
353638fd1498Szrj /* Store an input file with the given NAME and LANGUAGE in
353738fd1498Szrj    infiles.  */
353838fd1498Szrj 
353938fd1498Szrj static void
add_infile(const char * name,const char * language)354038fd1498Szrj add_infile (const char *name, const char *language)
354138fd1498Szrj {
354238fd1498Szrj   alloc_infile ();
354338fd1498Szrj   infiles[n_infiles].name = name;
354438fd1498Szrj   infiles[n_infiles++].language = language;
354538fd1498Szrj }
354638fd1498Szrj 
354738fd1498Szrj /* Allocate space for a switch in switches.  */
354838fd1498Szrj 
354938fd1498Szrj static void
alloc_switch(void)355038fd1498Szrj alloc_switch (void)
355138fd1498Szrj {
355238fd1498Szrj   if (n_switches_alloc == 0)
355338fd1498Szrj     {
355438fd1498Szrj       n_switches_alloc = 16;
355538fd1498Szrj       switches = XNEWVEC (struct switchstr, n_switches_alloc);
355638fd1498Szrj     }
355738fd1498Szrj   else if (n_switches_alloc == n_switches)
355838fd1498Szrj     {
355938fd1498Szrj       n_switches_alloc *= 2;
356038fd1498Szrj       switches = XRESIZEVEC (struct switchstr, switches, n_switches_alloc);
356138fd1498Szrj     }
356238fd1498Szrj }
356338fd1498Szrj 
356438fd1498Szrj /* Save an option OPT with N_ARGS arguments in array ARGS, marking it
356538fd1498Szrj    as validated if VALIDATED and KNOWN if it is an internal switch.  */
356638fd1498Szrj 
356738fd1498Szrj static void
save_switch(const char * opt,size_t n_args,const char * const * args,bool validated,bool known)356838fd1498Szrj save_switch (const char *opt, size_t n_args, const char *const *args,
356938fd1498Szrj 	     bool validated, bool known)
357038fd1498Szrj {
357138fd1498Szrj   alloc_switch ();
357238fd1498Szrj   switches[n_switches].part1 = opt + 1;
357338fd1498Szrj   if (n_args == 0)
357438fd1498Szrj     switches[n_switches].args = 0;
357538fd1498Szrj   else
357638fd1498Szrj     {
357738fd1498Szrj       switches[n_switches].args = XNEWVEC (const char *, n_args + 1);
357838fd1498Szrj       memcpy (switches[n_switches].args, args, n_args * sizeof (const char *));
357938fd1498Szrj       switches[n_switches].args[n_args] = NULL;
358038fd1498Szrj     }
358138fd1498Szrj 
358238fd1498Szrj   switches[n_switches].live_cond = 0;
358338fd1498Szrj   switches[n_switches].validated = validated;
358438fd1498Szrj   switches[n_switches].known = known;
358538fd1498Szrj   switches[n_switches].ordering = 0;
358638fd1498Szrj   n_switches++;
358738fd1498Szrj }
358838fd1498Szrj 
358938fd1498Szrj /* Set the SOURCE_DATE_EPOCH environment variable to the current time if it is
359038fd1498Szrj    not set already.  */
359138fd1498Szrj 
359238fd1498Szrj static void
set_source_date_epoch_envvar()359338fd1498Szrj set_source_date_epoch_envvar ()
359438fd1498Szrj {
359538fd1498Szrj   /* Array size is 21 = ceil(log_10(2^64)) + 1 to hold string representations
359638fd1498Szrj      of 64 bit integers.  */
359738fd1498Szrj   char source_date_epoch[21];
359838fd1498Szrj   time_t tt;
359938fd1498Szrj 
360038fd1498Szrj   errno = 0;
360138fd1498Szrj   tt = time (NULL);
360238fd1498Szrj   if (tt < (time_t) 0 || errno != 0)
360338fd1498Szrj     tt = (time_t) 0;
360438fd1498Szrj 
360538fd1498Szrj   snprintf (source_date_epoch, 21, "%llu", (unsigned long long) tt);
360638fd1498Szrj   /* Using setenv instead of xputenv because we want the variable to remain
360738fd1498Szrj      after finalizing so that it's still set in the second run when using
360838fd1498Szrj      -fcompare-debug.  */
360938fd1498Szrj   setenv ("SOURCE_DATE_EPOCH", source_date_epoch, 0);
361038fd1498Szrj }
361138fd1498Szrj 
361238fd1498Szrj /* Handle an option DECODED that is unknown to the option-processing
361338fd1498Szrj    machinery.  */
361438fd1498Szrj 
361538fd1498Szrj static bool
driver_unknown_option_callback(const struct cl_decoded_option * decoded)361638fd1498Szrj driver_unknown_option_callback (const struct cl_decoded_option *decoded)
361738fd1498Szrj {
361838fd1498Szrj   const char *opt = decoded->arg;
361938fd1498Szrj   if (opt[1] == 'W' && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-'
362038fd1498Szrj       && !(decoded->errors & CL_ERR_NEGATIVE))
362138fd1498Szrj     {
362238fd1498Szrj       /* Leave unknown -Wno-* options for the compiler proper, to be
362338fd1498Szrj 	 diagnosed only if there are warnings.  */
362438fd1498Szrj       save_switch (decoded->canonical_option[0],
362538fd1498Szrj 		   decoded->canonical_option_num_elements - 1,
362638fd1498Szrj 		   &decoded->canonical_option[1], false, true);
362738fd1498Szrj       return false;
362838fd1498Szrj     }
362938fd1498Szrj   if (decoded->opt_index == OPT_SPECIAL_unknown)
363038fd1498Szrj     {
363138fd1498Szrj       /* Give it a chance to define it a spec file.  */
363238fd1498Szrj       save_switch (decoded->canonical_option[0],
363338fd1498Szrj 		   decoded->canonical_option_num_elements - 1,
363438fd1498Szrj 		   &decoded->canonical_option[1], false, false);
363538fd1498Szrj       return false;
363638fd1498Szrj     }
363738fd1498Szrj   else
363838fd1498Szrj     return true;
363938fd1498Szrj }
364038fd1498Szrj 
364138fd1498Szrj /* Handle an option DECODED that is not marked as CL_DRIVER.
364238fd1498Szrj    LANG_MASK will always be CL_DRIVER.  */
364338fd1498Szrj 
364438fd1498Szrj static void
driver_wrong_lang_callback(const struct cl_decoded_option * decoded,unsigned int lang_mask ATTRIBUTE_UNUSED)364538fd1498Szrj driver_wrong_lang_callback (const struct cl_decoded_option *decoded,
364638fd1498Szrj 			    unsigned int lang_mask ATTRIBUTE_UNUSED)
364738fd1498Szrj {
364838fd1498Szrj   /* At this point, non-driver options are accepted (and expected to
364938fd1498Szrj      be passed down by specs) unless marked to be rejected by the
365038fd1498Szrj      driver.  Options to be rejected by the driver but accepted by the
365138fd1498Szrj      compilers proper are treated just like completely unknown
365238fd1498Szrj      options.  */
365338fd1498Szrj   const struct cl_option *option = &cl_options[decoded->opt_index];
365438fd1498Szrj 
365538fd1498Szrj   if (option->cl_reject_driver)
365638fd1498Szrj     error ("unrecognized command line option %qs",
365738fd1498Szrj 	   decoded->orig_option_with_args_text);
365838fd1498Szrj   else
365938fd1498Szrj     save_switch (decoded->canonical_option[0],
366038fd1498Szrj 		 decoded->canonical_option_num_elements - 1,
366138fd1498Szrj 		 &decoded->canonical_option[1], false, true);
366238fd1498Szrj }
366338fd1498Szrj 
366438fd1498Szrj static const char *spec_lang = 0;
366538fd1498Szrj static int last_language_n_infiles;
366638fd1498Szrj 
366738fd1498Szrj /* Parse -foffload option argument.  */
366838fd1498Szrj 
366938fd1498Szrj static void
handle_foffload_option(const char * arg)367038fd1498Szrj handle_foffload_option (const char *arg)
367138fd1498Szrj {
367238fd1498Szrj   const char *c, *cur, *n, *next, *end;
367338fd1498Szrj   char *target;
367438fd1498Szrj 
367538fd1498Szrj   /* If option argument starts with '-' then no target is specified and we
367638fd1498Szrj      do not need to parse it.  */
367738fd1498Szrj   if (arg[0] == '-')
367838fd1498Szrj     return;
367938fd1498Szrj 
368038fd1498Szrj   end = strchr (arg, '=');
368138fd1498Szrj   if (end == NULL)
368238fd1498Szrj     end = strchr (arg, '\0');
368338fd1498Szrj   cur = arg;
368438fd1498Szrj 
368538fd1498Szrj   while (cur < end)
368638fd1498Szrj     {
368738fd1498Szrj       next = strchr (cur, ',');
368838fd1498Szrj       if (next == NULL)
368938fd1498Szrj 	next = end;
369038fd1498Szrj       next = (next > end) ? end : next;
369138fd1498Szrj 
369238fd1498Szrj       target = XNEWVEC (char, next - cur + 1);
369338fd1498Szrj       memcpy (target, cur, next - cur);
369438fd1498Szrj       target[next - cur] = '\0';
369538fd1498Szrj 
369638fd1498Szrj       /* If 'disable' is passed to the option, stop parsing the option and clean
369738fd1498Szrj          the list of offload targets.  */
369838fd1498Szrj       if (strcmp (target, "disable") == 0)
369938fd1498Szrj 	{
370038fd1498Szrj 	  free (offload_targets);
370138fd1498Szrj 	  offload_targets = xstrdup ("");
370238fd1498Szrj 	  break;
370338fd1498Szrj 	}
370438fd1498Szrj 
370538fd1498Szrj       /* Check that GCC is configured to support the offload target.  */
370638fd1498Szrj       c = OFFLOAD_TARGETS;
370738fd1498Szrj       while (c)
370838fd1498Szrj 	{
370938fd1498Szrj 	  n = strchr (c, ',');
371038fd1498Szrj 	  if (n == NULL)
371138fd1498Szrj 	    n = strchr (c, '\0');
371238fd1498Szrj 
371338fd1498Szrj 	  if (next - cur == n - c && strncmp (target, c, n - c) == 0)
371438fd1498Szrj 	    break;
371538fd1498Szrj 
371638fd1498Szrj 	  c = *n ? n + 1 : NULL;
371738fd1498Szrj 	}
371838fd1498Szrj 
371938fd1498Szrj       if (!c)
372038fd1498Szrj 	fatal_error (input_location,
372138fd1498Szrj 		     "GCC is not configured to support %s as offload target",
372238fd1498Szrj 		     target);
372338fd1498Szrj 
372438fd1498Szrj       if (!offload_targets)
372538fd1498Szrj 	{
372638fd1498Szrj 	  offload_targets = target;
372738fd1498Szrj 	  target = NULL;
372838fd1498Szrj 	}
372938fd1498Szrj       else
373038fd1498Szrj 	{
373138fd1498Szrj 	  /* Check that the target hasn't already presented in the list.  */
373238fd1498Szrj 	  c = offload_targets;
373338fd1498Szrj 	  do
373438fd1498Szrj 	    {
373538fd1498Szrj 	      n = strchr (c, ':');
373638fd1498Szrj 	      if (n == NULL)
373738fd1498Szrj 		n = strchr (c, '\0');
373838fd1498Szrj 
373938fd1498Szrj 	      if (next - cur == n - c && strncmp (c, target, n - c) == 0)
374038fd1498Szrj 		break;
374138fd1498Szrj 
374238fd1498Szrj 	      c = n + 1;
374338fd1498Szrj 	    }
374438fd1498Szrj 	  while (*n);
374538fd1498Szrj 
374638fd1498Szrj 	  /* If duplicate is not found, append the target to the list.  */
374738fd1498Szrj 	  if (c > n)
374838fd1498Szrj 	    {
374938fd1498Szrj 	      size_t offload_targets_len = strlen (offload_targets);
375038fd1498Szrj 	      offload_targets
375138fd1498Szrj 		= XRESIZEVEC (char, offload_targets,
375238fd1498Szrj 			      offload_targets_len + 1 + next - cur + 1);
375338fd1498Szrj 	      offload_targets[offload_targets_len++] = ':';
375438fd1498Szrj 	      memcpy (offload_targets + offload_targets_len, target, next - cur + 1);
375538fd1498Szrj 	    }
375638fd1498Szrj 	}
375738fd1498Szrj 
375838fd1498Szrj       cur = next + 1;
375938fd1498Szrj       XDELETEVEC (target);
376038fd1498Szrj     }
376138fd1498Szrj }
376238fd1498Szrj 
376338fd1498Szrj /* Handle a driver option; arguments and return value as for
376438fd1498Szrj    handle_option.  */
376538fd1498Szrj 
376638fd1498Szrj static bool
driver_handle_option(struct gcc_options * opts,struct gcc_options * opts_set,const struct cl_decoded_option * decoded,unsigned int lang_mask ATTRIBUTE_UNUSED,int kind,location_t loc,const struct cl_option_handlers * handlers ATTRIBUTE_UNUSED,diagnostic_context * dc,void (*)(void))376738fd1498Szrj driver_handle_option (struct gcc_options *opts,
376838fd1498Szrj 		      struct gcc_options *opts_set,
376938fd1498Szrj 		      const struct cl_decoded_option *decoded,
377038fd1498Szrj 		      unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
377138fd1498Szrj 		      location_t loc,
377238fd1498Szrj 		      const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED,
377338fd1498Szrj 		      diagnostic_context *dc,
377438fd1498Szrj 		      void (*) (void))
377538fd1498Szrj {
377638fd1498Szrj   size_t opt_index = decoded->opt_index;
377738fd1498Szrj   const char *arg = decoded->arg;
377838fd1498Szrj   const char *compare_debug_replacement_opt;
377938fd1498Szrj   int value = decoded->value;
378038fd1498Szrj   bool validated = false;
378138fd1498Szrj   bool do_save = true;
378238fd1498Szrj 
378338fd1498Szrj   gcc_assert (opts == &global_options);
378438fd1498Szrj   gcc_assert (opts_set == &global_options_set);
378538fd1498Szrj   gcc_assert (kind == DK_UNSPECIFIED);
378638fd1498Szrj   gcc_assert (loc == UNKNOWN_LOCATION);
378738fd1498Szrj   gcc_assert (dc == global_dc);
378838fd1498Szrj 
378938fd1498Szrj   switch (opt_index)
379038fd1498Szrj     {
379138fd1498Szrj     case OPT_dumpspecs:
379238fd1498Szrj       {
379338fd1498Szrj 	struct spec_list *sl;
379438fd1498Szrj 	init_spec ();
379538fd1498Szrj 	for (sl = specs; sl; sl = sl->next)
379638fd1498Szrj 	  printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
379738fd1498Szrj 	if (link_command_spec)
379838fd1498Szrj 	  printf ("*link_command:\n%s\n\n", link_command_spec);
379938fd1498Szrj 	exit (0);
380038fd1498Szrj       }
380138fd1498Szrj 
380238fd1498Szrj     case OPT_dumpversion:
380338fd1498Szrj       printf ("%s\n", spec_version);
380438fd1498Szrj       exit (0);
380538fd1498Szrj 
380638fd1498Szrj     case OPT_dumpmachine:
380738fd1498Szrj       printf ("%s\n", spec_machine);
380838fd1498Szrj       exit (0);
380938fd1498Szrj 
381038fd1498Szrj     case OPT_dumpfullversion:
381138fd1498Szrj       printf ("%s\n", BASEVER);
381238fd1498Szrj       exit (0);
381338fd1498Szrj 
381438fd1498Szrj     case OPT__version:
381538fd1498Szrj       print_version = 1;
381638fd1498Szrj 
381738fd1498Szrj       /* CPP driver cannot obtain switch from cc1_options.  */
381838fd1498Szrj       if (is_cpp_driver)
381938fd1498Szrj 	add_preprocessor_option ("--version", strlen ("--version"));
382038fd1498Szrj       add_assembler_option ("--version", strlen ("--version"));
382138fd1498Szrj       add_linker_option ("--version", strlen ("--version"));
382238fd1498Szrj       break;
382338fd1498Szrj 
382438fd1498Szrj     case OPT__help:
382538fd1498Szrj       print_help_list = 1;
382638fd1498Szrj 
382738fd1498Szrj       /* CPP driver cannot obtain switch from cc1_options.  */
382838fd1498Szrj       if (is_cpp_driver)
382938fd1498Szrj 	add_preprocessor_option ("--help", 6);
383038fd1498Szrj       add_assembler_option ("--help", 6);
383138fd1498Szrj       add_linker_option ("--help", 6);
383238fd1498Szrj       break;
383338fd1498Szrj 
383438fd1498Szrj     case OPT__help_:
383538fd1498Szrj       print_subprocess_help = 2;
383638fd1498Szrj       break;
383738fd1498Szrj 
383838fd1498Szrj     case OPT__target_help:
383938fd1498Szrj       print_subprocess_help = 1;
384038fd1498Szrj 
384138fd1498Szrj       /* CPP driver cannot obtain switch from cc1_options.  */
384238fd1498Szrj       if (is_cpp_driver)
384338fd1498Szrj 	add_preprocessor_option ("--target-help", 13);
384438fd1498Szrj       add_assembler_option ("--target-help", 13);
384538fd1498Szrj       add_linker_option ("--target-help", 13);
384638fd1498Szrj       break;
384738fd1498Szrj 
384838fd1498Szrj     case OPT__no_sysroot_suffix:
384938fd1498Szrj     case OPT_pass_exit_codes:
385038fd1498Szrj     case OPT_print_search_dirs:
385138fd1498Szrj     case OPT_print_file_name_:
385238fd1498Szrj     case OPT_print_prog_name_:
385338fd1498Szrj     case OPT_print_multi_lib:
385438fd1498Szrj     case OPT_print_multi_directory:
385538fd1498Szrj     case OPT_print_sysroot:
385638fd1498Szrj     case OPT_print_multi_os_directory:
385738fd1498Szrj     case OPT_print_multiarch:
385838fd1498Szrj     case OPT_print_sysroot_headers_suffix:
385938fd1498Szrj     case OPT_time:
386038fd1498Szrj     case OPT_wrapper:
386138fd1498Szrj       /* These options set the variables specified in common.opt
386238fd1498Szrj 	 automatically, and do not need to be saved for spec
386338fd1498Szrj 	 processing.  */
386438fd1498Szrj       do_save = false;
386538fd1498Szrj       break;
386638fd1498Szrj 
386738fd1498Szrj     case OPT_print_libgcc_file_name:
386838fd1498Szrj       print_file_name = "libgcc.a";
386938fd1498Szrj       do_save = false;
387038fd1498Szrj       break;
387138fd1498Szrj 
387238fd1498Szrj     case OPT_fuse_ld_bfd:
387338fd1498Szrj        use_ld = ".bfd";
387438fd1498Szrj        break;
387538fd1498Szrj 
387638fd1498Szrj     case OPT_fuse_ld_gold:
387738fd1498Szrj        use_ld = ".gold";
387838fd1498Szrj        break;
387938fd1498Szrj 
388038fd1498Szrj     case OPT_fcompare_debug_second:
388138fd1498Szrj       compare_debug_second = 1;
388238fd1498Szrj       break;
388338fd1498Szrj 
388438fd1498Szrj     case OPT_fcompare_debug:
388538fd1498Szrj       switch (value)
388638fd1498Szrj 	{
388738fd1498Szrj 	case 0:
388838fd1498Szrj 	  compare_debug_replacement_opt = "-fcompare-debug=";
388938fd1498Szrj 	  arg = "";
389038fd1498Szrj 	  goto compare_debug_with_arg;
389138fd1498Szrj 
389238fd1498Szrj 	case 1:
389338fd1498Szrj 	  compare_debug_replacement_opt = "-fcompare-debug=-gtoggle";
389438fd1498Szrj 	  arg = "-gtoggle";
389538fd1498Szrj 	  goto compare_debug_with_arg;
389638fd1498Szrj 
389738fd1498Szrj 	default:
389838fd1498Szrj 	  gcc_unreachable ();
389938fd1498Szrj 	}
390038fd1498Szrj       break;
390138fd1498Szrj 
390238fd1498Szrj     case OPT_fcompare_debug_:
390338fd1498Szrj       compare_debug_replacement_opt = decoded->canonical_option[0];
390438fd1498Szrj     compare_debug_with_arg:
390538fd1498Szrj       gcc_assert (decoded->canonical_option_num_elements == 1);
390638fd1498Szrj       gcc_assert (arg != NULL);
390738fd1498Szrj       if (*arg)
390838fd1498Szrj 	compare_debug = 1;
390938fd1498Szrj       else
391038fd1498Szrj 	compare_debug = -1;
391138fd1498Szrj       if (compare_debug < 0)
391238fd1498Szrj 	compare_debug_opt = NULL;
391338fd1498Szrj       else
391438fd1498Szrj 	compare_debug_opt = arg;
391538fd1498Szrj       save_switch (compare_debug_replacement_opt, 0, NULL, validated, true);
391638fd1498Szrj       set_source_date_epoch_envvar ();
391738fd1498Szrj       return true;
391838fd1498Szrj 
391938fd1498Szrj     case OPT_fdiagnostics_color_:
392038fd1498Szrj       diagnostic_color_init (dc, value);
392138fd1498Szrj       break;
392238fd1498Szrj 
392338fd1498Szrj     case OPT_Wa_:
392438fd1498Szrj       {
392538fd1498Szrj 	int prev, j;
392638fd1498Szrj 	/* Pass the rest of this option to the assembler.  */
392738fd1498Szrj 
392838fd1498Szrj 	/* Split the argument at commas.  */
392938fd1498Szrj 	prev = 0;
393038fd1498Szrj 	for (j = 0; arg[j]; j++)
393138fd1498Szrj 	  if (arg[j] == ',')
393238fd1498Szrj 	    {
393338fd1498Szrj 	      add_assembler_option (arg + prev, j - prev);
393438fd1498Szrj 	      prev = j + 1;
393538fd1498Szrj 	    }
393638fd1498Szrj 
393738fd1498Szrj 	/* Record the part after the last comma.  */
393838fd1498Szrj 	add_assembler_option (arg + prev, j - prev);
393938fd1498Szrj       }
394038fd1498Szrj       do_save = false;
394138fd1498Szrj       break;
394238fd1498Szrj 
394338fd1498Szrj     case OPT_Wp_:
394438fd1498Szrj       {
394538fd1498Szrj 	int prev, j;
394638fd1498Szrj 	/* Pass the rest of this option to the preprocessor.  */
394738fd1498Szrj 
394838fd1498Szrj 	/* Split the argument at commas.  */
394938fd1498Szrj 	prev = 0;
395038fd1498Szrj 	for (j = 0; arg[j]; j++)
395138fd1498Szrj 	  if (arg[j] == ',')
395238fd1498Szrj 	    {
395338fd1498Szrj 	      add_preprocessor_option (arg + prev, j - prev);
395438fd1498Szrj 	      prev = j + 1;
395538fd1498Szrj 	    }
395638fd1498Szrj 
395738fd1498Szrj 	/* Record the part after the last comma.  */
395838fd1498Szrj 	add_preprocessor_option (arg + prev, j - prev);
395938fd1498Szrj       }
396038fd1498Szrj       do_save = false;
396138fd1498Szrj       break;
396238fd1498Szrj 
396338fd1498Szrj     case OPT_Wl_:
396438fd1498Szrj       {
396538fd1498Szrj 	int prev, j;
396638fd1498Szrj 	/* Split the argument at commas.  */
396738fd1498Szrj 	prev = 0;
396838fd1498Szrj 	for (j = 0; arg[j]; j++)
396938fd1498Szrj 	  if (arg[j] == ',')
397038fd1498Szrj 	    {
397138fd1498Szrj 	      add_infile (save_string (arg + prev, j - prev), "*");
397238fd1498Szrj 	      prev = j + 1;
397338fd1498Szrj 	    }
397438fd1498Szrj 	/* Record the part after the last comma.  */
397538fd1498Szrj 	add_infile (arg + prev, "*");
397638fd1498Szrj       }
397738fd1498Szrj       do_save = false;
397838fd1498Szrj       break;
397938fd1498Szrj 
398038fd1498Szrj     case OPT_Xlinker:
398138fd1498Szrj       add_infile (arg, "*");
398238fd1498Szrj       do_save = false;
398338fd1498Szrj       break;
398438fd1498Szrj 
398538fd1498Szrj     case OPT_Xpreprocessor:
398638fd1498Szrj       add_preprocessor_option (arg, strlen (arg));
398738fd1498Szrj       do_save = false;
398838fd1498Szrj       break;
398938fd1498Szrj 
399038fd1498Szrj     case OPT_Xassembler:
399138fd1498Szrj       add_assembler_option (arg, strlen (arg));
399238fd1498Szrj       do_save = false;
399338fd1498Szrj       break;
399438fd1498Szrj 
399538fd1498Szrj     case OPT_l:
399638fd1498Szrj       /* POSIX allows separation of -l and the lib arg; canonicalize
399738fd1498Szrj 	 by concatenating -l with its arg */
399838fd1498Szrj       add_infile (concat ("-l", arg, NULL), "*");
399938fd1498Szrj       do_save = false;
400038fd1498Szrj       break;
400138fd1498Szrj 
400238fd1498Szrj     case OPT_L:
400338fd1498Szrj       /* Similarly, canonicalize -L for linkers that may not accept
400438fd1498Szrj 	 separate arguments.  */
400538fd1498Szrj       save_switch (concat ("-L", arg, NULL), 0, NULL, validated, true);
400638fd1498Szrj       return true;
400738fd1498Szrj 
400838fd1498Szrj     case OPT_F:
400938fd1498Szrj       /* Likewise -F.  */
401038fd1498Szrj       save_switch (concat ("-F", arg, NULL), 0, NULL, validated, true);
401138fd1498Szrj       return true;
401238fd1498Szrj 
401338fd1498Szrj     case OPT_save_temps:
401438fd1498Szrj       save_temps_flag = SAVE_TEMPS_CWD;
401538fd1498Szrj       validated = true;
401638fd1498Szrj       break;
401738fd1498Szrj 
401838fd1498Szrj     case OPT_save_temps_:
401938fd1498Szrj       if (strcmp (arg, "cwd") == 0)
402038fd1498Szrj 	save_temps_flag = SAVE_TEMPS_CWD;
402138fd1498Szrj       else if (strcmp (arg, "obj") == 0
402238fd1498Szrj 	       || strcmp (arg, "object") == 0)
402338fd1498Szrj 	save_temps_flag = SAVE_TEMPS_OBJ;
4024*df642abcSzrj       else if (strcmp (arg, "objects") == 0)
4025*df642abcSzrj 	save_temps_flag = SAVE_TEMPS_OBJZ;
402638fd1498Szrj       else
402738fd1498Szrj 	fatal_error (input_location, "%qs is an unknown -save-temps option",
402838fd1498Szrj 		     decoded->orig_option_with_args_text);
402938fd1498Szrj       break;
403038fd1498Szrj 
403138fd1498Szrj     case OPT_no_canonical_prefixes:
403238fd1498Szrj       /* Already handled as a special case, so ignored here.  */
403338fd1498Szrj       do_save = false;
403438fd1498Szrj       break;
403538fd1498Szrj 
403638fd1498Szrj     case OPT_pipe:
403738fd1498Szrj       validated = true;
403838fd1498Szrj       /* These options set the variables specified in common.opt
403938fd1498Szrj 	 automatically, but do need to be saved for spec
404038fd1498Szrj 	 processing.  */
404138fd1498Szrj       break;
404238fd1498Szrj 
404338fd1498Szrj     case OPT_specs_:
404438fd1498Szrj       {
404538fd1498Szrj 	struct user_specs *user = XNEW (struct user_specs);
404638fd1498Szrj 
404738fd1498Szrj 	user->next = (struct user_specs *) 0;
404838fd1498Szrj 	user->filename = arg;
404938fd1498Szrj 	if (user_specs_tail)
405038fd1498Szrj 	  user_specs_tail->next = user;
405138fd1498Szrj 	else
405238fd1498Szrj 	  user_specs_head = user;
405338fd1498Szrj 	user_specs_tail = user;
405438fd1498Szrj       }
405538fd1498Szrj       validated = true;
405638fd1498Szrj       break;
405738fd1498Szrj 
405838fd1498Szrj     case OPT__sysroot_:
405938fd1498Szrj       target_system_root = arg;
406038fd1498Szrj       target_system_root_changed = 1;
406138fd1498Szrj       do_save = false;
406238fd1498Szrj       break;
406338fd1498Szrj 
406438fd1498Szrj     case OPT_time_:
406538fd1498Szrj       if (report_times_to_file)
406638fd1498Szrj 	fclose (report_times_to_file);
406738fd1498Szrj       report_times_to_file = fopen (arg, "a");
406838fd1498Szrj       do_save = false;
406938fd1498Szrj       break;
407038fd1498Szrj 
407138fd1498Szrj     case OPT____:
407238fd1498Szrj       /* "-###"
407338fd1498Szrj 	 This is similar to -v except that there is no execution
407438fd1498Szrj 	 of the commands and the echoed arguments are quoted.  It
407538fd1498Szrj 	 is intended for use in shell scripts to capture the
407638fd1498Szrj 	 driver-generated command line.  */
407738fd1498Szrj       verbose_only_flag++;
407838fd1498Szrj       verbose_flag = 1;
407938fd1498Szrj       do_save = false;
408038fd1498Szrj       break;
408138fd1498Szrj 
408238fd1498Szrj     case OPT_B:
408338fd1498Szrj       {
408438fd1498Szrj 	size_t len = strlen (arg);
408538fd1498Szrj 
408638fd1498Szrj 	/* Catch the case where the user has forgotten to append a
408738fd1498Szrj 	   directory separator to the path.  Note, they may be using
408838fd1498Szrj 	   -B to add an executable name prefix, eg "i386-elf-", in
408938fd1498Szrj 	   order to distinguish between multiple installations of
409038fd1498Szrj 	   GCC in the same directory.  Hence we must check to see
409138fd1498Szrj 	   if appending a directory separator actually makes a
409238fd1498Szrj 	   valid directory name.  */
409338fd1498Szrj 	if (!IS_DIR_SEPARATOR (arg[len - 1])
409438fd1498Szrj 	    && is_directory (arg, false))
409538fd1498Szrj 	  {
409638fd1498Szrj 	    char *tmp = XNEWVEC (char, len + 2);
409738fd1498Szrj 	    strcpy (tmp, arg);
409838fd1498Szrj 	    tmp[len] = DIR_SEPARATOR;
409938fd1498Szrj 	    tmp[++len] = 0;
410038fd1498Szrj 	    arg = tmp;
410138fd1498Szrj 	  }
410238fd1498Szrj 
410338fd1498Szrj 	add_prefix (&exec_prefixes, arg, NULL,
410438fd1498Szrj 		    PREFIX_PRIORITY_B_OPT, 0, 0);
410538fd1498Szrj 	add_prefix (&startfile_prefixes, arg, NULL,
410638fd1498Szrj 		    PREFIX_PRIORITY_B_OPT, 0, 0);
410738fd1498Szrj 	add_prefix (&include_prefixes, arg, NULL,
410838fd1498Szrj 		    PREFIX_PRIORITY_B_OPT, 0, 0);
410938fd1498Szrj       }
411038fd1498Szrj       validated = true;
411138fd1498Szrj       break;
411238fd1498Szrj 
411338fd1498Szrj     case OPT_E:
411438fd1498Szrj       have_E = true;
411538fd1498Szrj       break;
411638fd1498Szrj 
411738fd1498Szrj     case OPT_x:
411838fd1498Szrj       spec_lang = arg;
411938fd1498Szrj       if (!strcmp (spec_lang, "none"))
412038fd1498Szrj 	/* Suppress the warning if -xnone comes after the last input
412138fd1498Szrj 	   file, because alternate command interfaces like g++ might
412238fd1498Szrj 	   find it useful to place -xnone after each input file.  */
412338fd1498Szrj 	spec_lang = 0;
412438fd1498Szrj       else
412538fd1498Szrj 	last_language_n_infiles = n_infiles;
412638fd1498Szrj       do_save = false;
412738fd1498Szrj       break;
412838fd1498Szrj 
412938fd1498Szrj     case OPT_o:
413038fd1498Szrj       have_o = 1;
413138fd1498Szrj #if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
413238fd1498Szrj       arg = convert_filename (arg, ! have_c, 0);
413338fd1498Szrj #endif
413438fd1498Szrj       output_file = arg;
413538fd1498Szrj       /* Save the output name in case -save-temps=obj was used.  */
413638fd1498Szrj       save_temps_prefix = xstrdup (arg);
413738fd1498Szrj       /* On some systems, ld cannot handle "-o" without a space.  So
413838fd1498Szrj 	 split the option from its argument.  */
413938fd1498Szrj       save_switch ("-o", 1, &arg, validated, true);
414038fd1498Szrj       return true;
414138fd1498Szrj 
414238fd1498Szrj #ifdef ENABLE_DEFAULT_PIE
414338fd1498Szrj     case OPT_pie:
414438fd1498Szrj       /* -pie is turned on by default.  */
414538fd1498Szrj #endif
414638fd1498Szrj 
414738fd1498Szrj     case OPT_static_libgcc:
414838fd1498Szrj     case OPT_shared_libgcc:
414938fd1498Szrj     case OPT_static_libgfortran:
415038fd1498Szrj     case OPT_static_libstdc__:
415138fd1498Szrj       /* These are always valid, since gcc.c itself understands the
415238fd1498Szrj 	 first two, gfortranspec.c understands -static-libgfortran and
415338fd1498Szrj 	 g++spec.c understands -static-libstdc++ */
415438fd1498Szrj       validated = true;
415538fd1498Szrj       break;
415638fd1498Szrj 
415738fd1498Szrj     case OPT_fwpa:
415838fd1498Szrj       flag_wpa = "";
415938fd1498Szrj       break;
416038fd1498Szrj 
416138fd1498Szrj     case OPT_foffload_:
416238fd1498Szrj       handle_foffload_option (arg);
416338fd1498Szrj       break;
416438fd1498Szrj 
416538fd1498Szrj     default:
416638fd1498Szrj       /* Various driver options need no special processing at this
416738fd1498Szrj 	 point, having been handled in a prescan above or being
416838fd1498Szrj 	 handled by specs.  */
416938fd1498Szrj       break;
417038fd1498Szrj     }
417138fd1498Szrj 
417238fd1498Szrj   if (do_save)
417338fd1498Szrj     save_switch (decoded->canonical_option[0],
417438fd1498Szrj 		 decoded->canonical_option_num_elements - 1,
417538fd1498Szrj 		 &decoded->canonical_option[1], validated, true);
417638fd1498Szrj   return true;
417738fd1498Szrj }
417838fd1498Szrj 
417938fd1498Szrj /* Put the driver's standard set of option handlers in *HANDLERS.  */
418038fd1498Szrj 
418138fd1498Szrj static void
set_option_handlers(struct cl_option_handlers * handlers)418238fd1498Szrj set_option_handlers (struct cl_option_handlers *handlers)
418338fd1498Szrj {
418438fd1498Szrj   handlers->unknown_option_callback = driver_unknown_option_callback;
418538fd1498Szrj   handlers->wrong_lang_callback = driver_wrong_lang_callback;
418638fd1498Szrj   handlers->num_handlers = 3;
418738fd1498Szrj   handlers->handlers[0].handler = driver_handle_option;
418838fd1498Szrj   handlers->handlers[0].mask = CL_DRIVER;
418938fd1498Szrj   handlers->handlers[1].handler = common_handle_option;
419038fd1498Szrj   handlers->handlers[1].mask = CL_COMMON;
419138fd1498Szrj   handlers->handlers[2].handler = target_handle_option;
419238fd1498Szrj   handlers->handlers[2].mask = CL_TARGET;
419338fd1498Szrj }
419438fd1498Szrj 
419538fd1498Szrj /* Create the vector `switches' and its contents.
419638fd1498Szrj    Store its length in `n_switches'.  */
419738fd1498Szrj 
419838fd1498Szrj static void
process_command(unsigned int decoded_options_count,struct cl_decoded_option * decoded_options)419938fd1498Szrj process_command (unsigned int decoded_options_count,
420038fd1498Szrj 		 struct cl_decoded_option *decoded_options)
420138fd1498Szrj {
420238fd1498Szrj   const char *temp;
420338fd1498Szrj   char *temp1;
420438fd1498Szrj   char *tooldir_prefix, *tooldir_prefix2;
420538fd1498Szrj   char *(*get_relative_prefix) (const char *, const char *,
420638fd1498Szrj 				const char *) = NULL;
420738fd1498Szrj   struct cl_option_handlers handlers;
420838fd1498Szrj   unsigned int j;
420938fd1498Szrj 
421038fd1498Szrj   gcc_exec_prefix = env.get ("GCC_EXEC_PREFIX");
421138fd1498Szrj 
421238fd1498Szrj   n_switches = 0;
421338fd1498Szrj   n_infiles = 0;
421438fd1498Szrj   added_libraries = 0;
421538fd1498Szrj 
421638fd1498Szrj   /* Figure compiler version from version string.  */
421738fd1498Szrj 
421838fd1498Szrj   compiler_version = temp1 = xstrdup (version_string);
421938fd1498Szrj 
422038fd1498Szrj   for (; *temp1; ++temp1)
422138fd1498Szrj     {
422238fd1498Szrj       if (*temp1 == ' ')
422338fd1498Szrj 	{
422438fd1498Szrj 	  *temp1 = '\0';
422538fd1498Szrj 	  break;
422638fd1498Szrj 	}
422738fd1498Szrj     }
422838fd1498Szrj 
422938fd1498Szrj   /* Handle any -no-canonical-prefixes flag early, to assign the function
423038fd1498Szrj      that builds relative prefixes.  This function creates default search
423138fd1498Szrj      paths that are needed later in normal option handling.  */
423238fd1498Szrj 
423338fd1498Szrj   for (j = 1; j < decoded_options_count; j++)
423438fd1498Szrj     {
423538fd1498Szrj       if (decoded_options[j].opt_index == OPT_no_canonical_prefixes)
423638fd1498Szrj 	{
423738fd1498Szrj 	  get_relative_prefix = make_relative_prefix_ignore_links;
423838fd1498Szrj 	  break;
423938fd1498Szrj 	}
424038fd1498Szrj     }
424138fd1498Szrj   if (! get_relative_prefix)
424238fd1498Szrj     get_relative_prefix = make_relative_prefix;
424338fd1498Szrj 
424438fd1498Szrj   /* Set up the default search paths.  If there is no GCC_EXEC_PREFIX,
424538fd1498Szrj      see if we can create it from the pathname specified in
424638fd1498Szrj      decoded_options[0].arg.  */
424738fd1498Szrj 
424838fd1498Szrj   gcc_libexec_prefix = standard_libexec_prefix;
424938fd1498Szrj #ifndef VMS
425038fd1498Szrj   /* FIXME: make_relative_prefix doesn't yet work for VMS.  */
425138fd1498Szrj   if (!gcc_exec_prefix)
425238fd1498Szrj     {
4253632577dbSzrj #if 0  /* DragonFly base: Never use relative prefix (not bootstrapped) */
425438fd1498Szrj       gcc_exec_prefix = get_relative_prefix (decoded_options[0].arg,
425538fd1498Szrj 					     standard_bindir_prefix,
425638fd1498Szrj 					     standard_exec_prefix);
425738fd1498Szrj       gcc_libexec_prefix = get_relative_prefix (decoded_options[0].arg,
425838fd1498Szrj 					     standard_bindir_prefix,
425938fd1498Szrj 					     standard_libexec_prefix);
426038fd1498Szrj       if (gcc_exec_prefix)
426138fd1498Szrj 	xputenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL));
4262632577dbSzrj #endif
426338fd1498Szrj     }
426438fd1498Szrj   else
426538fd1498Szrj     {
426638fd1498Szrj       /* make_relative_prefix requires a program name, but
426738fd1498Szrj 	 GCC_EXEC_PREFIX is typically a directory name with a trailing
426838fd1498Szrj 	 / (which is ignored by make_relative_prefix), so append a
426938fd1498Szrj 	 program name.  */
427038fd1498Szrj       char *tmp_prefix = concat (gcc_exec_prefix, "gcc", NULL);
427138fd1498Szrj       gcc_libexec_prefix = get_relative_prefix (tmp_prefix,
427238fd1498Szrj 						standard_exec_prefix,
427338fd1498Szrj 						standard_libexec_prefix);
427438fd1498Szrj 
427538fd1498Szrj       /* The path is unrelocated, so fallback to the original setting.  */
427638fd1498Szrj       if (!gcc_libexec_prefix)
427738fd1498Szrj 	gcc_libexec_prefix = standard_libexec_prefix;
427838fd1498Szrj 
427938fd1498Szrj       free (tmp_prefix);
428038fd1498Szrj     }
428138fd1498Szrj #else
428238fd1498Szrj #endif
428338fd1498Szrj   /* From this point onward, gcc_exec_prefix is non-null if the toolchain
428438fd1498Szrj      is relocated. The toolchain was either relocated using GCC_EXEC_PREFIX
428538fd1498Szrj      or an automatically created GCC_EXEC_PREFIX from
428638fd1498Szrj      decoded_options[0].arg.  */
428738fd1498Szrj 
428838fd1498Szrj   /* Do language-specific adjustment/addition of flags.  */
428938fd1498Szrj   lang_specific_driver (&decoded_options, &decoded_options_count,
429038fd1498Szrj 			&added_libraries);
429138fd1498Szrj 
429238fd1498Szrj   if (gcc_exec_prefix)
429338fd1498Szrj     {
429438fd1498Szrj       int len = strlen (gcc_exec_prefix);
429538fd1498Szrj 
429638fd1498Szrj       if (len > (int) sizeof ("/lib/gcc/") - 1
429738fd1498Szrj 	  && (IS_DIR_SEPARATOR (gcc_exec_prefix[len-1])))
429838fd1498Szrj 	{
429938fd1498Szrj 	  temp = gcc_exec_prefix + len - sizeof ("/lib/gcc/") + 1;
430038fd1498Szrj 	  if (IS_DIR_SEPARATOR (*temp)
430138fd1498Szrj 	      && filename_ncmp (temp + 1, "lib", 3) == 0
430238fd1498Szrj 	      && IS_DIR_SEPARATOR (temp[4])
430338fd1498Szrj 	      && filename_ncmp (temp + 5, "gcc", 3) == 0)
430438fd1498Szrj 	    len -= sizeof ("/lib/gcc/") - 1;
430538fd1498Szrj 	}
430638fd1498Szrj 
4307632577dbSzrj #if 0  /* DragonFly base: Bad Paths */
430838fd1498Szrj       set_std_prefix (gcc_exec_prefix, len);
430938fd1498Szrj       add_prefix (&exec_prefixes, gcc_libexec_prefix, "GCC",
431038fd1498Szrj 		  PREFIX_PRIORITY_LAST, 0, 0);
431138fd1498Szrj       add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC",
431238fd1498Szrj 		  PREFIX_PRIORITY_LAST, 0, 0);
4313632577dbSzrj #endif
431438fd1498Szrj     }
431538fd1498Szrj 
431638fd1498Szrj   /* COMPILER_PATH and LIBRARY_PATH have values
431738fd1498Szrj      that are lists of directory names with colons.  */
431838fd1498Szrj 
431938fd1498Szrj   temp = env.get ("COMPILER_PATH");
432038fd1498Szrj   if (temp)
432138fd1498Szrj     {
432238fd1498Szrj       const char *startp, *endp;
432338fd1498Szrj       char *nstore = (char *) alloca (strlen (temp) + 3);
432438fd1498Szrj 
432538fd1498Szrj       startp = endp = temp;
432638fd1498Szrj       while (1)
432738fd1498Szrj 	{
432838fd1498Szrj 	  if (*endp == PATH_SEPARATOR || *endp == 0)
432938fd1498Szrj 	    {
433038fd1498Szrj 	      strncpy (nstore, startp, endp - startp);
433138fd1498Szrj 	      if (endp == startp)
433238fd1498Szrj 		strcpy (nstore, concat (".", dir_separator_str, NULL));
433338fd1498Szrj 	      else if (!IS_DIR_SEPARATOR (endp[-1]))
433438fd1498Szrj 		{
433538fd1498Szrj 		  nstore[endp - startp] = DIR_SEPARATOR;
433638fd1498Szrj 		  nstore[endp - startp + 1] = 0;
433738fd1498Szrj 		}
433838fd1498Szrj 	      else
433938fd1498Szrj 		nstore[endp - startp] = 0;
434038fd1498Szrj 	      add_prefix (&exec_prefixes, nstore, 0,
434138fd1498Szrj 			  PREFIX_PRIORITY_LAST, 0, 0);
434238fd1498Szrj 	      add_prefix (&include_prefixes, nstore, 0,
434338fd1498Szrj 			  PREFIX_PRIORITY_LAST, 0, 0);
434438fd1498Szrj 	      if (*endp == 0)
434538fd1498Szrj 		break;
434638fd1498Szrj 	      endp = startp = endp + 1;
434738fd1498Szrj 	    }
434838fd1498Szrj 	  else
434938fd1498Szrj 	    endp++;
435038fd1498Szrj 	}
435138fd1498Szrj     }
435238fd1498Szrj 
435338fd1498Szrj   temp = env.get (LIBRARY_PATH_ENV);
435438fd1498Szrj   if (temp && *cross_compile == '0')
435538fd1498Szrj     {
435638fd1498Szrj       const char *startp, *endp;
435738fd1498Szrj       char *nstore = (char *) alloca (strlen (temp) + 3);
435838fd1498Szrj 
435938fd1498Szrj       startp = endp = temp;
436038fd1498Szrj       while (1)
436138fd1498Szrj 	{
436238fd1498Szrj 	  if (*endp == PATH_SEPARATOR || *endp == 0)
436338fd1498Szrj 	    {
436438fd1498Szrj 	      strncpy (nstore, startp, endp - startp);
436538fd1498Szrj 	      if (endp == startp)
436638fd1498Szrj 		strcpy (nstore, concat (".", dir_separator_str, NULL));
436738fd1498Szrj 	      else if (!IS_DIR_SEPARATOR (endp[-1]))
436838fd1498Szrj 		{
436938fd1498Szrj 		  nstore[endp - startp] = DIR_SEPARATOR;
437038fd1498Szrj 		  nstore[endp - startp + 1] = 0;
437138fd1498Szrj 		}
437238fd1498Szrj 	      else
437338fd1498Szrj 		nstore[endp - startp] = 0;
437438fd1498Szrj 	      add_prefix (&startfile_prefixes, nstore, NULL,
437538fd1498Szrj 			  PREFIX_PRIORITY_LAST, 0, 1);
437638fd1498Szrj 	      if (*endp == 0)
437738fd1498Szrj 		break;
437838fd1498Szrj 	      endp = startp = endp + 1;
437938fd1498Szrj 	    }
438038fd1498Szrj 	  else
438138fd1498Szrj 	    endp++;
438238fd1498Szrj 	}
438338fd1498Szrj     }
438438fd1498Szrj 
438538fd1498Szrj   /* Use LPATH like LIBRARY_PATH (for the CMU build program).  */
438638fd1498Szrj   temp = env.get ("LPATH");
438738fd1498Szrj   if (temp && *cross_compile == '0')
438838fd1498Szrj     {
438938fd1498Szrj       const char *startp, *endp;
439038fd1498Szrj       char *nstore = (char *) alloca (strlen (temp) + 3);
439138fd1498Szrj 
439238fd1498Szrj       startp = endp = temp;
439338fd1498Szrj       while (1)
439438fd1498Szrj 	{
439538fd1498Szrj 	  if (*endp == PATH_SEPARATOR || *endp == 0)
439638fd1498Szrj 	    {
439738fd1498Szrj 	      strncpy (nstore, startp, endp - startp);
439838fd1498Szrj 	      if (endp == startp)
439938fd1498Szrj 		strcpy (nstore, concat (".", dir_separator_str, NULL));
440038fd1498Szrj 	      else if (!IS_DIR_SEPARATOR (endp[-1]))
440138fd1498Szrj 		{
440238fd1498Szrj 		  nstore[endp - startp] = DIR_SEPARATOR;
440338fd1498Szrj 		  nstore[endp - startp + 1] = 0;
440438fd1498Szrj 		}
440538fd1498Szrj 	      else
440638fd1498Szrj 		nstore[endp - startp] = 0;
440738fd1498Szrj 	      add_prefix (&startfile_prefixes, nstore, NULL,
440838fd1498Szrj 			  PREFIX_PRIORITY_LAST, 0, 1);
440938fd1498Szrj 	      if (*endp == 0)
441038fd1498Szrj 		break;
441138fd1498Szrj 	      endp = startp = endp + 1;
441238fd1498Szrj 	    }
441338fd1498Szrj 	  else
441438fd1498Szrj 	    endp++;
441538fd1498Szrj 	}
441638fd1498Szrj     }
441738fd1498Szrj 
441838fd1498Szrj   /* Process the options and store input files and switches in their
441938fd1498Szrj      vectors.  */
442038fd1498Szrj 
442138fd1498Szrj   last_language_n_infiles = -1;
442238fd1498Szrj 
442338fd1498Szrj   set_option_handlers (&handlers);
442438fd1498Szrj 
442538fd1498Szrj   for (j = 1; j < decoded_options_count; j++)
442638fd1498Szrj     {
442738fd1498Szrj       switch (decoded_options[j].opt_index)
442838fd1498Szrj 	{
442938fd1498Szrj 	case OPT_S:
443038fd1498Szrj 	case OPT_c:
443138fd1498Szrj 	case OPT_E:
443238fd1498Szrj 	  have_c = 1;
443338fd1498Szrj 	  break;
443438fd1498Szrj 	}
443538fd1498Szrj       if (have_c)
443638fd1498Szrj 	break;
443738fd1498Szrj     }
443838fd1498Szrj 
443938fd1498Szrj   for (j = 1; j < decoded_options_count; j++)
444038fd1498Szrj     {
444138fd1498Szrj       if (decoded_options[j].opt_index == OPT_SPECIAL_input_file)
444238fd1498Szrj 	{
444338fd1498Szrj 	  const char *arg = decoded_options[j].arg;
444438fd1498Szrj           const char *p = strrchr (arg, '@');
444538fd1498Szrj           char *fname;
444638fd1498Szrj 	  long offset;
444738fd1498Szrj 	  int consumed;
444838fd1498Szrj #ifdef HAVE_TARGET_OBJECT_SUFFIX
444938fd1498Szrj 	  arg = convert_filename (arg, 0, access (arg, F_OK));
445038fd1498Szrj #endif
445138fd1498Szrj 	  /* For LTO static archive support we handle input file
445238fd1498Szrj 	     specifications that are composed of a filename and
445338fd1498Szrj 	     an offset like FNAME@OFFSET.  */
445438fd1498Szrj 	  if (p
445538fd1498Szrj 	      && p != arg
445638fd1498Szrj 	      && sscanf (p, "@%li%n", &offset, &consumed) >= 1
445738fd1498Szrj 	      && strlen (p) == (unsigned int)consumed)
445838fd1498Szrj 	    {
445938fd1498Szrj               fname = (char *)xmalloc (p - arg + 1);
446038fd1498Szrj               memcpy (fname, arg, p - arg);
446138fd1498Szrj               fname[p - arg] = '\0';
446238fd1498Szrj 	      /* Only accept non-stdin and existing FNAME parts, otherwise
446338fd1498Szrj 		 try with the full name.  */
446438fd1498Szrj 	      if (strcmp (fname, "-") == 0 || access (fname, F_OK) < 0)
446538fd1498Szrj 		{
446638fd1498Szrj 		  free (fname);
446738fd1498Szrj 		  fname = xstrdup (arg);
446838fd1498Szrj 		}
446938fd1498Szrj 	    }
447038fd1498Szrj 	  else
447138fd1498Szrj 	    fname = xstrdup (arg);
447238fd1498Szrj 
447338fd1498Szrj           if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
447438fd1498Szrj 	    {
447538fd1498Szrj 	      if (fname[0] == '@' && access (fname + 1, F_OK) < 0)
447638fd1498Szrj 		perror_with_name (fname + 1);
447738fd1498Szrj 	      else
447838fd1498Szrj 		perror_with_name (fname);
447938fd1498Szrj 	    }
448038fd1498Szrj           else
448138fd1498Szrj 	    add_infile (arg, spec_lang);
448238fd1498Szrj 
448338fd1498Szrj           free (fname);
448438fd1498Szrj 	  continue;
448538fd1498Szrj 	}
448638fd1498Szrj 
448738fd1498Szrj       read_cmdline_option (&global_options, &global_options_set,
448838fd1498Szrj 			   decoded_options + j, UNKNOWN_LOCATION,
448938fd1498Szrj 			   CL_DRIVER, &handlers, global_dc);
449038fd1498Szrj     }
449138fd1498Szrj 
449238fd1498Szrj   /* If the user didn't specify any, default to all configured offload
449338fd1498Szrj      targets.  */
449438fd1498Szrj   if (ENABLE_OFFLOADING && offload_targets == NULL)
449538fd1498Szrj     handle_foffload_option (OFFLOAD_TARGETS);
449638fd1498Szrj 
449738fd1498Szrj   if (output_file
449838fd1498Szrj       && strcmp (output_file, "-") != 0
449938fd1498Szrj       && strcmp (output_file, HOST_BIT_BUCKET) != 0)
450038fd1498Szrj     {
450138fd1498Szrj       int i;
450238fd1498Szrj       for (i = 0; i < n_infiles; i++)
450338fd1498Szrj 	if ((!infiles[i].language || infiles[i].language[0] != '*')
450438fd1498Szrj 	    && canonical_filename_eq (infiles[i].name, output_file))
450538fd1498Szrj 	  fatal_error (input_location,
450638fd1498Szrj 		       "input file %qs is the same as output file",
450738fd1498Szrj 		       output_file);
450838fd1498Szrj     }
450938fd1498Szrj 
451038fd1498Szrj   if (output_file != NULL && output_file[0] == '\0')
451138fd1498Szrj     fatal_error (input_location, "output filename may not be empty");
451238fd1498Szrj 
451338fd1498Szrj   /* If -save-temps=obj and -o name, create the prefix to use for %b.
451438fd1498Szrj      Otherwise just make -save-temps=obj the same as -save-temps=cwd.  */
451538fd1498Szrj   if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL)
451638fd1498Szrj     {
451738fd1498Szrj       save_temps_length = strlen (save_temps_prefix);
451838fd1498Szrj       temp = strrchr (lbasename (save_temps_prefix), '.');
451938fd1498Szrj       if (temp)
452038fd1498Szrj 	{
452138fd1498Szrj 	  save_temps_length -= strlen (temp);
452238fd1498Szrj 	  save_temps_prefix[save_temps_length] = '\0';
452338fd1498Szrj 	}
452438fd1498Szrj 
452538fd1498Szrj     }
4526*df642abcSzrj   else if (save_temps_flag == SAVE_TEMPS_OBJZ && save_temps_prefix != NULL)
4527*df642abcSzrj     {
4528*df642abcSzrj       save_temps_length = strlen (save_temps_prefix);
4529*df642abcSzrj     }
453038fd1498Szrj   else if (save_temps_prefix != NULL)
453138fd1498Szrj     {
453238fd1498Szrj       free (save_temps_prefix);
453338fd1498Szrj       save_temps_prefix = NULL;
453438fd1498Szrj     }
453538fd1498Szrj 
453638fd1498Szrj   if (save_temps_flag && use_pipes)
453738fd1498Szrj     {
453838fd1498Szrj       /* -save-temps overrides -pipe, so that temp files are produced */
453938fd1498Szrj       if (save_temps_flag)
454038fd1498Szrj 	warning (0, "-pipe ignored because -save-temps specified");
454138fd1498Szrj       use_pipes = 0;
454238fd1498Szrj     }
454338fd1498Szrj 
454438fd1498Szrj   if (!compare_debug)
454538fd1498Szrj     {
454638fd1498Szrj       const char *gcd = env.get ("GCC_COMPARE_DEBUG");
454738fd1498Szrj 
454838fd1498Szrj       if (gcd && gcd[0] == '-')
454938fd1498Szrj 	{
455038fd1498Szrj 	  compare_debug = 2;
455138fd1498Szrj 	  compare_debug_opt = gcd;
455238fd1498Szrj 	}
455338fd1498Szrj       else if (gcd && *gcd && strcmp (gcd, "0"))
455438fd1498Szrj 	{
455538fd1498Szrj 	  compare_debug = 3;
455638fd1498Szrj 	  compare_debug_opt = "-gtoggle";
455738fd1498Szrj 	}
455838fd1498Szrj     }
455938fd1498Szrj   else if (compare_debug < 0)
456038fd1498Szrj     {
456138fd1498Szrj       compare_debug = 0;
456238fd1498Szrj       gcc_assert (!compare_debug_opt);
456338fd1498Szrj     }
456438fd1498Szrj 
456538fd1498Szrj   /* Set up the search paths.  We add directories that we expect to
456638fd1498Szrj      contain GNU Toolchain components before directories specified by
456738fd1498Szrj      the machine description so that we will find GNU components (like
456838fd1498Szrj      the GNU assembler) before those of the host system.  */
456938fd1498Szrj 
457038fd1498Szrj   /* If we don't know where the toolchain has been installed, use the
457138fd1498Szrj      configured-in locations.  */
457238fd1498Szrj   if (!gcc_exec_prefix)
457338fd1498Szrj     {
457438fd1498Szrj #ifndef OS2
4575632577dbSzrj #if 1  /* DragonFly base: All tools in the same common location */
4576632577dbSzrj       add_prefix (&exec_prefixes, standard_libexec_prefix, NULL,
4577632577dbSzrj 		  PREFIX_PRIORITY_LAST, 0, 0);
4578632577dbSzrj #endif
4579632577dbSzrj #if 0  /* DragonFly base: Bad paths */
458038fd1498Szrj       add_prefix (&exec_prefixes, standard_libexec_prefix, "GCC",
458138fd1498Szrj 		  PREFIX_PRIORITY_LAST, 1, 0);
458238fd1498Szrj       add_prefix (&exec_prefixes, standard_libexec_prefix, "BINUTILS",
458338fd1498Szrj 		  PREFIX_PRIORITY_LAST, 2, 0);
458438fd1498Szrj       add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS",
458538fd1498Szrj 		  PREFIX_PRIORITY_LAST, 2, 0);
458638fd1498Szrj #endif
4587632577dbSzrj #endif
4588632577dbSzrj #if 0  /* DragonFly base: Bad paths */
458938fd1498Szrj       add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS",
459038fd1498Szrj 		  PREFIX_PRIORITY_LAST, 1, 0);
4591632577dbSzrj #endif
459238fd1498Szrj     }
459338fd1498Szrj 
459438fd1498Szrj   gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix));
459538fd1498Szrj   tooldir_prefix2 = concat (tooldir_base_prefix, spec_machine,
459638fd1498Szrj 			    dir_separator_str, NULL);
459738fd1498Szrj 
459838fd1498Szrj   /* Look for tools relative to the location from which the driver is
459938fd1498Szrj      running, or, if that is not available, the configured prefix.  */
460038fd1498Szrj   tooldir_prefix
460138fd1498Szrj     = concat (gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix,
460238fd1498Szrj 	      spec_host_machine, dir_separator_str, spec_version,
460338fd1498Szrj 	      accel_dir_suffix, dir_separator_str, tooldir_prefix2, NULL);
460438fd1498Szrj   free (tooldir_prefix2);
460538fd1498Szrj 
4606632577dbSzrj #if 0  /* DragonFly base: Bad paths */
460738fd1498Szrj   add_prefix (&exec_prefixes,
460838fd1498Szrj 	      concat (tooldir_prefix, "bin", dir_separator_str, NULL),
460938fd1498Szrj 	      "BINUTILS", PREFIX_PRIORITY_LAST, 0, 0);
461038fd1498Szrj   add_prefix (&startfile_prefixes,
461138fd1498Szrj 	      concat (tooldir_prefix, "lib", dir_separator_str, NULL),
461238fd1498Szrj 	      "BINUTILS", PREFIX_PRIORITY_LAST, 0, 1);
4613632577dbSzrj #endif
461438fd1498Szrj   free (tooldir_prefix);
461538fd1498Szrj 
461638fd1498Szrj #if defined(TARGET_SYSTEM_ROOT_RELOCATABLE) && !defined(VMS)
461738fd1498Szrj   /* If the normal TARGET_SYSTEM_ROOT is inside of $exec_prefix,
461838fd1498Szrj      then consider it to relocate with the rest of the GCC installation
461938fd1498Szrj      if GCC_EXEC_PREFIX is set.
462038fd1498Szrj      ``make_relative_prefix'' is not compiled for VMS, so don't call it.  */
462138fd1498Szrj   if (target_system_root && !target_system_root_changed && gcc_exec_prefix)
462238fd1498Szrj     {
462338fd1498Szrj       char *tmp_prefix = get_relative_prefix (decoded_options[0].arg,
462438fd1498Szrj 					      standard_bindir_prefix,
462538fd1498Szrj 					      target_system_root);
462638fd1498Szrj       if (tmp_prefix && access_check (tmp_prefix, F_OK) == 0)
462738fd1498Szrj 	{
462838fd1498Szrj 	  target_system_root = tmp_prefix;
462938fd1498Szrj 	  target_system_root_changed = 1;
463038fd1498Szrj 	}
463138fd1498Szrj     }
463238fd1498Szrj #endif
463338fd1498Szrj 
463438fd1498Szrj   /* More prefixes are enabled in main, after we read the specs file
463538fd1498Szrj      and determine whether this is cross-compilation or not.  */
463638fd1498Szrj 
463738fd1498Szrj   if (n_infiles == last_language_n_infiles && spec_lang != 0)
463838fd1498Szrj     warning (0, "%<-x %s%> after last input file has no effect", spec_lang);
463938fd1498Szrj 
464038fd1498Szrj   /* Synthesize -fcompare-debug flag from the GCC_COMPARE_DEBUG
464138fd1498Szrj      environment variable.  */
464238fd1498Szrj   if (compare_debug == 2 || compare_debug == 3)
464338fd1498Szrj     {
464438fd1498Szrj       const char *opt = concat ("-fcompare-debug=", compare_debug_opt, NULL);
464538fd1498Szrj       save_switch (opt, 0, NULL, false, true);
464638fd1498Szrj       compare_debug = 1;
464738fd1498Szrj     }
464838fd1498Szrj 
464938fd1498Szrj   /* Ensure we only invoke each subprocess once.  */
465038fd1498Szrj   if (print_subprocess_help || print_help_list || print_version)
465138fd1498Szrj     {
465238fd1498Szrj       n_infiles = 0;
465338fd1498Szrj 
465438fd1498Szrj       /* Create a dummy input file, so that we can pass
465538fd1498Szrj 	 the help option on to the various sub-processes.  */
465638fd1498Szrj       add_infile ("help-dummy", "c");
465738fd1498Szrj     }
465838fd1498Szrj 
465938fd1498Szrj   /* Decide if undefined variable references are allowed in specs.  */
466038fd1498Szrj 
466138fd1498Szrj   /* -v alone is safe. --version and --help alone or together are safe.  Note
466238fd1498Szrj      that -v would make them unsafe, as they'd then be run for subprocesses as
466338fd1498Szrj      well, the location of which might depend on variables possibly coming
466438fd1498Szrj      from self-specs.  Note also that the command name is counted in
466538fd1498Szrj      decoded_options_count.  */
466638fd1498Szrj 
466738fd1498Szrj   unsigned help_version_count = 0;
466838fd1498Szrj 
466938fd1498Szrj   if (print_version)
467038fd1498Szrj     help_version_count++;
467138fd1498Szrj 
467238fd1498Szrj   if (print_help_list)
467338fd1498Szrj     help_version_count++;
467438fd1498Szrj 
467538fd1498Szrj   spec_undefvar_allowed =
467638fd1498Szrj     ((verbose_flag && decoded_options_count == 2)
467738fd1498Szrj      || help_version_count == decoded_options_count - 1);
467838fd1498Szrj 
467938fd1498Szrj   alloc_switch ();
468038fd1498Szrj   switches[n_switches].part1 = 0;
468138fd1498Szrj   alloc_infile ();
468238fd1498Szrj   infiles[n_infiles].name = 0;
468338fd1498Szrj }
468438fd1498Szrj 
468538fd1498Szrj /* Store switches not filtered out by %<S in spec in COLLECT_GCC_OPTIONS
468638fd1498Szrj    and place that in the environment.  */
468738fd1498Szrj 
468838fd1498Szrj static void
set_collect_gcc_options(void)468938fd1498Szrj set_collect_gcc_options (void)
469038fd1498Szrj {
469138fd1498Szrj   int i;
469238fd1498Szrj   int first_time;
469338fd1498Szrj 
469438fd1498Szrj   /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
469538fd1498Szrj      the compiler.  */
469638fd1498Szrj   obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
469738fd1498Szrj 		sizeof ("COLLECT_GCC_OPTIONS=") - 1);
469838fd1498Szrj 
469938fd1498Szrj   first_time = TRUE;
470038fd1498Szrj   for (i = 0; (int) i < n_switches; i++)
470138fd1498Szrj     {
470238fd1498Szrj       const char *const *args;
470338fd1498Szrj       const char *p, *q;
470438fd1498Szrj       if (!first_time)
470538fd1498Szrj 	obstack_grow (&collect_obstack, " ", 1);
470638fd1498Szrj 
470738fd1498Szrj       first_time = FALSE;
470838fd1498Szrj 
470938fd1498Szrj       /* Ignore elided switches.  */
471038fd1498Szrj       if ((switches[i].live_cond
471138fd1498Szrj 	   & (SWITCH_IGNORE | SWITCH_KEEP_FOR_GCC))
471238fd1498Szrj 	  == SWITCH_IGNORE)
471338fd1498Szrj 	continue;
471438fd1498Szrj 
471538fd1498Szrj       obstack_grow (&collect_obstack, "'-", 2);
471638fd1498Szrj       q = switches[i].part1;
471738fd1498Szrj       while ((p = strchr (q, '\'')))
471838fd1498Szrj 	{
471938fd1498Szrj 	  obstack_grow (&collect_obstack, q, p - q);
472038fd1498Szrj 	  obstack_grow (&collect_obstack, "'\\''", 4);
472138fd1498Szrj 	  q = ++p;
472238fd1498Szrj 	}
472338fd1498Szrj       obstack_grow (&collect_obstack, q, strlen (q));
472438fd1498Szrj       obstack_grow (&collect_obstack, "'", 1);
472538fd1498Szrj 
472638fd1498Szrj       for (args = switches[i].args; args && *args; args++)
472738fd1498Szrj 	{
472838fd1498Szrj 	  obstack_grow (&collect_obstack, " '", 2);
472938fd1498Szrj 	  q = *args;
473038fd1498Szrj 	  while ((p = strchr (q, '\'')))
473138fd1498Szrj 	    {
473238fd1498Szrj 	      obstack_grow (&collect_obstack, q, p - q);
473338fd1498Szrj 	      obstack_grow (&collect_obstack, "'\\''", 4);
473438fd1498Szrj 	      q = ++p;
473538fd1498Szrj 	    }
473638fd1498Szrj 	  obstack_grow (&collect_obstack, q, strlen (q));
473738fd1498Szrj 	  obstack_grow (&collect_obstack, "'", 1);
473838fd1498Szrj 	}
473938fd1498Szrj     }
474038fd1498Szrj   obstack_grow (&collect_obstack, "\0", 1);
474138fd1498Szrj   xputenv (XOBFINISH (&collect_obstack, char *));
474238fd1498Szrj }
474338fd1498Szrj 
474438fd1498Szrj /* Process a spec string, accumulating and running commands.  */
474538fd1498Szrj 
474638fd1498Szrj /* These variables describe the input file name.
474738fd1498Szrj    input_file_number is the index on outfiles of this file,
474838fd1498Szrj    so that the output file name can be stored for later use by %o.
474938fd1498Szrj    input_basename is the start of the part of the input file
475038fd1498Szrj    sans all directory names, and basename_length is the number
475138fd1498Szrj    of characters starting there excluding the suffix .c or whatever.  */
475238fd1498Szrj 
475338fd1498Szrj static const char *gcc_input_filename;
475438fd1498Szrj static int input_file_number;
475538fd1498Szrj size_t input_filename_length;
475638fd1498Szrj static int basename_length;
475738fd1498Szrj static int suffixed_basename_length;
475838fd1498Szrj static const char *input_basename;
475938fd1498Szrj static const char *input_suffix;
476038fd1498Szrj #ifndef HOST_LACKS_INODE_NUMBERS
476138fd1498Szrj static struct stat input_stat;
476238fd1498Szrj #endif
476338fd1498Szrj static int input_stat_set;
476438fd1498Szrj 
476538fd1498Szrj /* The compiler used to process the current input file.  */
476638fd1498Szrj static struct compiler *input_file_compiler;
476738fd1498Szrj 
476838fd1498Szrj /* These are variables used within do_spec and do_spec_1.  */
476938fd1498Szrj 
477038fd1498Szrj /* Nonzero if an arg has been started and not yet terminated
477138fd1498Szrj    (with space, tab or newline).  */
477238fd1498Szrj static int arg_going;
477338fd1498Szrj 
477438fd1498Szrj /* Nonzero means %d or %g has been seen; the next arg to be terminated
477538fd1498Szrj    is a temporary file name.  */
477638fd1498Szrj static int delete_this_arg;
477738fd1498Szrj 
477838fd1498Szrj /* Nonzero means %w has been seen; the next arg to be terminated
477938fd1498Szrj    is the output file name of this compilation.  */
478038fd1498Szrj static int this_is_output_file;
478138fd1498Szrj 
478238fd1498Szrj /* Nonzero means %s has been seen; the next arg to be terminated
478338fd1498Szrj    is the name of a library file and we should try the standard
478438fd1498Szrj    search dirs for it.  */
478538fd1498Szrj static int this_is_library_file;
478638fd1498Szrj 
478738fd1498Szrj /* Nonzero means %T has been seen; the next arg to be terminated
478838fd1498Szrj    is the name of a linker script and we should try all of the
478938fd1498Szrj    standard search dirs for it.  If it is found insert a --script
479038fd1498Szrj    command line switch and then substitute the full path in place,
479138fd1498Szrj    otherwise generate an error message.  */
479238fd1498Szrj static int this_is_linker_script;
479338fd1498Szrj 
479438fd1498Szrj /* Nonzero means that the input of this command is coming from a pipe.  */
479538fd1498Szrj static int input_from_pipe;
479638fd1498Szrj 
479738fd1498Szrj /* Nonnull means substitute this for any suffix when outputting a switches
479838fd1498Szrj    arguments.  */
479938fd1498Szrj static const char *suffix_subst;
480038fd1498Szrj 
480138fd1498Szrj /* If there is an argument being accumulated, terminate it and store it.  */
480238fd1498Szrj 
480338fd1498Szrj static void
end_going_arg(void)480438fd1498Szrj end_going_arg (void)
480538fd1498Szrj {
480638fd1498Szrj   if (arg_going)
480738fd1498Szrj     {
480838fd1498Szrj       const char *string;
480938fd1498Szrj 
481038fd1498Szrj       obstack_1grow (&obstack, 0);
481138fd1498Szrj       string = XOBFINISH (&obstack, const char *);
481238fd1498Szrj       if (this_is_library_file)
481338fd1498Szrj 	string = find_file (string);
481438fd1498Szrj       if (this_is_linker_script)
481538fd1498Szrj 	{
481638fd1498Szrj 	  char * full_script_path = find_a_file (&startfile_prefixes, string, R_OK, true);
481738fd1498Szrj 
481838fd1498Szrj 	  if (full_script_path == NULL)
481938fd1498Szrj 	    {
482038fd1498Szrj 	      error ("unable to locate default linker script %qs in the library search paths", string);
482138fd1498Szrj 	      /* Script was not found on search path.  */
482238fd1498Szrj 	      return;
482338fd1498Szrj 	    }
482438fd1498Szrj 	  store_arg ("--script", false, false);
482538fd1498Szrj 	  string = full_script_path;
482638fd1498Szrj 	}
482738fd1498Szrj       store_arg (string, delete_this_arg, this_is_output_file);
482838fd1498Szrj       if (this_is_output_file)
482938fd1498Szrj 	outfiles[input_file_number] = string;
483038fd1498Szrj       arg_going = 0;
483138fd1498Szrj     }
483238fd1498Szrj }
483338fd1498Szrj 
483438fd1498Szrj 
483538fd1498Szrj /* Parse the WRAPPER string which is a comma separated list of the command line
483638fd1498Szrj    and insert them into the beginning of argbuf.  */
483738fd1498Szrj 
483838fd1498Szrj static void
insert_wrapper(const char * wrapper)483938fd1498Szrj insert_wrapper (const char *wrapper)
484038fd1498Szrj {
484138fd1498Szrj   int n = 0;
484238fd1498Szrj   int i;
484338fd1498Szrj   char *buf = xstrdup (wrapper);
484438fd1498Szrj   char *p = buf;
484538fd1498Szrj   unsigned int old_length = argbuf.length ();
484638fd1498Szrj 
484738fd1498Szrj   do
484838fd1498Szrj     {
484938fd1498Szrj       n++;
485038fd1498Szrj       while (*p == ',')
485138fd1498Szrj         p++;
485238fd1498Szrj     }
485338fd1498Szrj   while ((p = strchr (p, ',')) != NULL);
485438fd1498Szrj 
485538fd1498Szrj   argbuf.safe_grow (old_length + n);
485638fd1498Szrj   memmove (argbuf.address () + n,
485738fd1498Szrj 	   argbuf.address (),
485838fd1498Szrj 	   old_length * sizeof (const_char_p));
485938fd1498Szrj 
486038fd1498Szrj   i = 0;
486138fd1498Szrj   p = buf;
486238fd1498Szrj   do
486338fd1498Szrj     {
486438fd1498Szrj       while (*p == ',')
486538fd1498Szrj         {
486638fd1498Szrj           *p = 0;
486738fd1498Szrj           p++;
486838fd1498Szrj         }
486938fd1498Szrj       argbuf[i] = p;
487038fd1498Szrj       i++;
487138fd1498Szrj     }
487238fd1498Szrj   while ((p = strchr (p, ',')) != NULL);
487338fd1498Szrj   gcc_assert (i == n);
487438fd1498Szrj }
487538fd1498Szrj 
487638fd1498Szrj /* Process the spec SPEC and run the commands specified therein.
487738fd1498Szrj    Returns 0 if the spec is successfully processed; -1 if failed.  */
487838fd1498Szrj 
487938fd1498Szrj int
do_spec(const char * spec)488038fd1498Szrj do_spec (const char *spec)
488138fd1498Szrj {
488238fd1498Szrj   int value;
488338fd1498Szrj 
488438fd1498Szrj   value = do_spec_2 (spec);
488538fd1498Szrj 
488638fd1498Szrj   /* Force out any unfinished command.
488738fd1498Szrj      If -pipe, this forces out the last command if it ended in `|'.  */
488838fd1498Szrj   if (value == 0)
488938fd1498Szrj     {
489038fd1498Szrj       if (argbuf.length () > 0
489138fd1498Szrj 	  && !strcmp (argbuf.last (), "|"))
489238fd1498Szrj 	argbuf.pop ();
489338fd1498Szrj 
489438fd1498Szrj       set_collect_gcc_options ();
489538fd1498Szrj 
489638fd1498Szrj       if (argbuf.length () > 0)
489738fd1498Szrj 	value = execute ();
489838fd1498Szrj     }
489938fd1498Szrj 
490038fd1498Szrj   return value;
490138fd1498Szrj }
490238fd1498Szrj 
490338fd1498Szrj static int
do_spec_2(const char * spec)490438fd1498Szrj do_spec_2 (const char *spec)
490538fd1498Szrj {
490638fd1498Szrj   int result;
490738fd1498Szrj 
490838fd1498Szrj   clear_args ();
490938fd1498Szrj   arg_going = 0;
491038fd1498Szrj   delete_this_arg = 0;
491138fd1498Szrj   this_is_output_file = 0;
491238fd1498Szrj   this_is_library_file = 0;
491338fd1498Szrj   this_is_linker_script = 0;
491438fd1498Szrj   input_from_pipe = 0;
491538fd1498Szrj   suffix_subst = NULL;
491638fd1498Szrj 
491738fd1498Szrj   result = do_spec_1 (spec, 0, NULL);
491838fd1498Szrj 
491938fd1498Szrj   end_going_arg ();
492038fd1498Szrj 
492138fd1498Szrj   return result;
492238fd1498Szrj }
492338fd1498Szrj 
492438fd1498Szrj 
492538fd1498Szrj /* Process the given spec string and add any new options to the end
492638fd1498Szrj    of the switches/n_switches array.  */
492738fd1498Szrj 
492838fd1498Szrj static void
do_option_spec(const char * name,const char * spec)492938fd1498Szrj do_option_spec (const char *name, const char *spec)
493038fd1498Szrj {
493138fd1498Szrj   unsigned int i, value_count, value_len;
493238fd1498Szrj   const char *p, *q, *value;
493338fd1498Szrj   char *tmp_spec, *tmp_spec_p;
493438fd1498Szrj 
493538fd1498Szrj   if (configure_default_options[0].name == NULL)
493638fd1498Szrj     return;
493738fd1498Szrj 
493838fd1498Szrj   for (i = 0; i < ARRAY_SIZE (configure_default_options); i++)
493938fd1498Szrj     if (strcmp (configure_default_options[i].name, name) == 0)
494038fd1498Szrj       break;
494138fd1498Szrj   if (i == ARRAY_SIZE (configure_default_options))
494238fd1498Szrj     return;
494338fd1498Szrj 
494438fd1498Szrj   value = configure_default_options[i].value;
494538fd1498Szrj   value_len = strlen (value);
494638fd1498Szrj 
494738fd1498Szrj   /* Compute the size of the final spec.  */
494838fd1498Szrj   value_count = 0;
494938fd1498Szrj   p = spec;
495038fd1498Szrj   while ((p = strstr (p, "%(VALUE)")) != NULL)
495138fd1498Szrj     {
495238fd1498Szrj       p ++;
495338fd1498Szrj       value_count ++;
495438fd1498Szrj     }
495538fd1498Szrj 
495638fd1498Szrj   /* Replace each %(VALUE) by the specified value.  */
495738fd1498Szrj   tmp_spec = (char *) alloca (strlen (spec) + 1
495838fd1498Szrj 		     + value_count * (value_len - strlen ("%(VALUE)")));
495938fd1498Szrj   tmp_spec_p = tmp_spec;
496038fd1498Szrj   q = spec;
496138fd1498Szrj   while ((p = strstr (q, "%(VALUE)")) != NULL)
496238fd1498Szrj     {
496338fd1498Szrj       memcpy (tmp_spec_p, q, p - q);
496438fd1498Szrj       tmp_spec_p = tmp_spec_p + (p - q);
496538fd1498Szrj       memcpy (tmp_spec_p, value, value_len);
496638fd1498Szrj       tmp_spec_p += value_len;
496738fd1498Szrj       q = p + strlen ("%(VALUE)");
496838fd1498Szrj     }
496938fd1498Szrj   strcpy (tmp_spec_p, q);
497038fd1498Szrj 
497138fd1498Szrj   do_self_spec (tmp_spec);
497238fd1498Szrj }
497338fd1498Szrj 
497438fd1498Szrj /* Process the given spec string and add any new options to the end
497538fd1498Szrj    of the switches/n_switches array.  */
497638fd1498Szrj 
497738fd1498Szrj static void
do_self_spec(const char * spec)497838fd1498Szrj do_self_spec (const char *spec)
497938fd1498Szrj {
498038fd1498Szrj   int i;
498138fd1498Szrj 
498238fd1498Szrj   do_spec_2 (spec);
498338fd1498Szrj   do_spec_1 (" ", 0, NULL);
498438fd1498Szrj 
498538fd1498Szrj   /* Mark %<S switches processed by do_self_spec to be ignored permanently.
498638fd1498Szrj      do_self_specs adds the replacements to switches array, so it shouldn't
498738fd1498Szrj      be processed afterwards.  */
498838fd1498Szrj   for (i = 0; i < n_switches; i++)
498938fd1498Szrj     if ((switches[i].live_cond & SWITCH_IGNORE))
499038fd1498Szrj       switches[i].live_cond |= SWITCH_IGNORE_PERMANENTLY;
499138fd1498Szrj 
499238fd1498Szrj   if (argbuf.length () > 0)
499338fd1498Szrj     {
499438fd1498Szrj       const char **argbuf_copy;
499538fd1498Szrj       struct cl_decoded_option *decoded_options;
499638fd1498Szrj       struct cl_option_handlers handlers;
499738fd1498Szrj       unsigned int decoded_options_count;
499838fd1498Szrj       unsigned int j;
499938fd1498Szrj 
500038fd1498Szrj       /* Create a copy of argbuf with a dummy argv[0] entry for
500138fd1498Szrj 	 decode_cmdline_options_to_array.  */
500238fd1498Szrj       argbuf_copy = XNEWVEC (const char *,
500338fd1498Szrj 			     argbuf.length () + 1);
500438fd1498Szrj       argbuf_copy[0] = "";
500538fd1498Szrj       memcpy (argbuf_copy + 1, argbuf.address (),
500638fd1498Szrj 	      argbuf.length () * sizeof (const char *));
500738fd1498Szrj 
500838fd1498Szrj       decode_cmdline_options_to_array (argbuf.length () + 1,
500938fd1498Szrj 				       argbuf_copy,
501038fd1498Szrj 				       CL_DRIVER, &decoded_options,
501138fd1498Szrj 				       &decoded_options_count);
501238fd1498Szrj       free (argbuf_copy);
501338fd1498Szrj 
501438fd1498Szrj       set_option_handlers (&handlers);
501538fd1498Szrj 
501638fd1498Szrj       for (j = 1; j < decoded_options_count; j++)
501738fd1498Szrj 	{
501838fd1498Szrj 	  switch (decoded_options[j].opt_index)
501938fd1498Szrj 	    {
502038fd1498Szrj 	    case OPT_SPECIAL_input_file:
502138fd1498Szrj 	      /* Specs should only generate options, not input
502238fd1498Szrj 		 files.  */
502338fd1498Szrj 	      if (strcmp (decoded_options[j].arg, "-") != 0)
502438fd1498Szrj 		fatal_error (input_location,
502538fd1498Szrj 			     "switch %qs does not start with %<-%>",
502638fd1498Szrj 			     decoded_options[j].arg);
502738fd1498Szrj 	      else
502838fd1498Szrj 		fatal_error (input_location,
502938fd1498Szrj 			     "spec-generated switch is just %<-%>");
503038fd1498Szrj 	      break;
503138fd1498Szrj 
503238fd1498Szrj 	    case OPT_fcompare_debug_second:
503338fd1498Szrj 	    case OPT_fcompare_debug:
503438fd1498Szrj 	    case OPT_fcompare_debug_:
503538fd1498Szrj 	    case OPT_o:
503638fd1498Szrj 	      /* Avoid duplicate processing of some options from
503738fd1498Szrj 		 compare-debug specs; just save them here.  */
503838fd1498Szrj 	      save_switch (decoded_options[j].canonical_option[0],
503938fd1498Szrj 			   (decoded_options[j].canonical_option_num_elements
504038fd1498Szrj 			    - 1),
504138fd1498Szrj 			   &decoded_options[j].canonical_option[1], false, true);
504238fd1498Szrj 	      break;
504338fd1498Szrj 
504438fd1498Szrj 	    default:
504538fd1498Szrj 	      read_cmdline_option (&global_options, &global_options_set,
504638fd1498Szrj 				   decoded_options + j, UNKNOWN_LOCATION,
504738fd1498Szrj 				   CL_DRIVER, &handlers, global_dc);
504838fd1498Szrj 	      break;
504938fd1498Szrj 	    }
505038fd1498Szrj 	}
505138fd1498Szrj 
505238fd1498Szrj       free (decoded_options);
505338fd1498Szrj 
505438fd1498Szrj       alloc_switch ();
505538fd1498Szrj       switches[n_switches].part1 = 0;
505638fd1498Szrj     }
505738fd1498Szrj }
505838fd1498Szrj 
505938fd1498Szrj /* Callback for processing %D and %I specs.  */
506038fd1498Szrj 
506138fd1498Szrj struct spec_path_info {
506238fd1498Szrj   const char *option;
506338fd1498Szrj   const char *append;
506438fd1498Szrj   size_t append_len;
506538fd1498Szrj   bool omit_relative;
506638fd1498Szrj   bool separate_options;
506738fd1498Szrj };
506838fd1498Szrj 
506938fd1498Szrj static void *
spec_path(char * path,void * data)507038fd1498Szrj spec_path (char *path, void *data)
507138fd1498Szrj {
507238fd1498Szrj   struct spec_path_info *info = (struct spec_path_info *) data;
507338fd1498Szrj   size_t len = 0;
507438fd1498Szrj   char save = 0;
507538fd1498Szrj 
507638fd1498Szrj   if (info->omit_relative && !IS_ABSOLUTE_PATH (path))
507738fd1498Szrj     return NULL;
507838fd1498Szrj 
507938fd1498Szrj   if (info->append_len != 0)
508038fd1498Szrj     {
508138fd1498Szrj       len = strlen (path);
508238fd1498Szrj       memcpy (path + len, info->append, info->append_len + 1);
508338fd1498Szrj     }
508438fd1498Szrj 
508538fd1498Szrj   if (!is_directory (path, true))
508638fd1498Szrj     return NULL;
508738fd1498Szrj 
508838fd1498Szrj   do_spec_1 (info->option, 1, NULL);
508938fd1498Szrj   if (info->separate_options)
509038fd1498Szrj     do_spec_1 (" ", 0, NULL);
509138fd1498Szrj 
509238fd1498Szrj   if (info->append_len == 0)
509338fd1498Szrj     {
509438fd1498Szrj       len = strlen (path);
509538fd1498Szrj       save = path[len - 1];
509638fd1498Szrj       if (IS_DIR_SEPARATOR (path[len - 1]))
509738fd1498Szrj 	path[len - 1] = '\0';
509838fd1498Szrj     }
509938fd1498Szrj 
510038fd1498Szrj   do_spec_1 (path, 1, NULL);
510138fd1498Szrj   do_spec_1 (" ", 0, NULL);
510238fd1498Szrj 
510338fd1498Szrj   /* Must not damage the original path.  */
510438fd1498Szrj   if (info->append_len == 0)
510538fd1498Szrj     path[len - 1] = save;
510638fd1498Szrj 
510738fd1498Szrj   return NULL;
510838fd1498Szrj }
510938fd1498Szrj 
511038fd1498Szrj /* Create a temporary FILE with the contents of ARGV. Add @FILE to the
511138fd1498Szrj    argument list. */
511238fd1498Szrj 
511338fd1498Szrj static void
create_at_file(char ** argv)511438fd1498Szrj create_at_file (char **argv)
511538fd1498Szrj {
511638fd1498Szrj   char *temp_file = make_temp_file ("");
511738fd1498Szrj   char *at_argument = concat ("@", temp_file, NULL);
511838fd1498Szrj   FILE *f = fopen (temp_file, "w");
511938fd1498Szrj   int status;
512038fd1498Szrj 
512138fd1498Szrj   if (f == NULL)
512238fd1498Szrj     fatal_error (input_location, "could not open temporary response file %s",
512338fd1498Szrj 		 temp_file);
512438fd1498Szrj 
512538fd1498Szrj   status = writeargv (argv, f);
512638fd1498Szrj 
512738fd1498Szrj   if (status)
512838fd1498Szrj     fatal_error (input_location,
512938fd1498Szrj 		 "could not write to temporary response file %s",
513038fd1498Szrj 		 temp_file);
513138fd1498Szrj 
513238fd1498Szrj   status = fclose (f);
513338fd1498Szrj 
513438fd1498Szrj   if (EOF == status)
513538fd1498Szrj     fatal_error (input_location, "could not close temporary response file %s",
513638fd1498Szrj 		 temp_file);
513738fd1498Szrj 
513838fd1498Szrj   store_arg (at_argument, 0, 0);
513938fd1498Szrj 
514038fd1498Szrj   record_temp_file (temp_file, !save_temps_flag, !save_temps_flag);
514138fd1498Szrj }
514238fd1498Szrj 
514338fd1498Szrj /* True if we should compile INFILE. */
514438fd1498Szrj 
514538fd1498Szrj static bool
compile_input_file_p(struct infile * infile)514638fd1498Szrj compile_input_file_p (struct infile *infile)
514738fd1498Szrj {
514838fd1498Szrj   if ((!infile->language) || (infile->language[0] != '*'))
514938fd1498Szrj     if (infile->incompiler == input_file_compiler)
515038fd1498Szrj       return true;
515138fd1498Szrj   return false;
515238fd1498Szrj }
515338fd1498Szrj 
515438fd1498Szrj /* Process each member of VEC as a spec.  */
515538fd1498Szrj 
515638fd1498Szrj static void
do_specs_vec(vec<char_p> vec)515738fd1498Szrj do_specs_vec (vec<char_p> vec)
515838fd1498Szrj {
515938fd1498Szrj   unsigned ix;
516038fd1498Szrj   char *opt;
516138fd1498Szrj 
516238fd1498Szrj   FOR_EACH_VEC_ELT (vec, ix, opt)
516338fd1498Szrj     {
516438fd1498Szrj       do_spec_1 (opt, 1, NULL);
516538fd1498Szrj       /* Make each accumulated option a separate argument.  */
516638fd1498Szrj       do_spec_1 (" ", 0, NULL);
516738fd1498Szrj     }
516838fd1498Szrj }
516938fd1498Szrj 
517038fd1498Szrj /* Process the sub-spec SPEC as a portion of a larger spec.
517138fd1498Szrj    This is like processing a whole spec except that we do
517238fd1498Szrj    not initialize at the beginning and we do not supply a
517338fd1498Szrj    newline by default at the end.
517438fd1498Szrj    INSWITCH nonzero means don't process %-sequences in SPEC;
517538fd1498Szrj    in this case, % is treated as an ordinary character.
517638fd1498Szrj    This is used while substituting switches.
517738fd1498Szrj    INSWITCH nonzero also causes SPC not to terminate an argument.
517838fd1498Szrj 
517938fd1498Szrj    Value is zero unless a line was finished
518038fd1498Szrj    and the command on that line reported an error.  */
518138fd1498Szrj 
518238fd1498Szrj static int
do_spec_1(const char * spec,int inswitch,const char * soft_matched_part)518338fd1498Szrj do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
518438fd1498Szrj {
518538fd1498Szrj   const char *p = spec;
518638fd1498Szrj   int c;
518738fd1498Szrj   int i;
518838fd1498Szrj   int value;
518938fd1498Szrj 
519038fd1498Szrj   /* If it's an empty string argument to a switch, keep it as is.  */
519138fd1498Szrj   if (inswitch && !*p)
519238fd1498Szrj     arg_going = 1;
519338fd1498Szrj 
519438fd1498Szrj   while ((c = *p++))
519538fd1498Szrj     /* If substituting a switch, treat all chars like letters.
519638fd1498Szrj        Otherwise, NL, SPC, TAB and % are special.  */
519738fd1498Szrj     switch (inswitch ? 'a' : c)
519838fd1498Szrj       {
519938fd1498Szrj       case '\n':
520038fd1498Szrj 	end_going_arg ();
520138fd1498Szrj 
520238fd1498Szrj 	if (argbuf.length () > 0
520338fd1498Szrj 	    && !strcmp (argbuf.last (), "|"))
520438fd1498Szrj 	  {
520538fd1498Szrj 	    /* A `|' before the newline means use a pipe here,
520638fd1498Szrj 	       but only if -pipe was specified.
520738fd1498Szrj 	       Otherwise, execute now and don't pass the `|' as an arg.  */
520838fd1498Szrj 	    if (use_pipes)
520938fd1498Szrj 	      {
521038fd1498Szrj 		input_from_pipe = 1;
521138fd1498Szrj 		break;
521238fd1498Szrj 	      }
521338fd1498Szrj 	    else
521438fd1498Szrj 	      argbuf.pop ();
521538fd1498Szrj 	  }
521638fd1498Szrj 
521738fd1498Szrj 	set_collect_gcc_options ();
521838fd1498Szrj 
521938fd1498Szrj 	if (argbuf.length () > 0)
522038fd1498Szrj 	  {
522138fd1498Szrj 	    value = execute ();
522238fd1498Szrj 	    if (value)
522338fd1498Szrj 	      return value;
522438fd1498Szrj 	  }
522538fd1498Szrj 	/* Reinitialize for a new command, and for a new argument.  */
522638fd1498Szrj 	clear_args ();
522738fd1498Szrj 	arg_going = 0;
522838fd1498Szrj 	delete_this_arg = 0;
522938fd1498Szrj 	this_is_output_file = 0;
523038fd1498Szrj 	this_is_library_file = 0;
523138fd1498Szrj 	this_is_linker_script = 0;
523238fd1498Szrj 	input_from_pipe = 0;
523338fd1498Szrj 	break;
523438fd1498Szrj 
523538fd1498Szrj       case '|':
523638fd1498Szrj 	end_going_arg ();
523738fd1498Szrj 
523838fd1498Szrj 	/* Use pipe */
523938fd1498Szrj 	obstack_1grow (&obstack, c);
524038fd1498Szrj 	arg_going = 1;
524138fd1498Szrj 	break;
524238fd1498Szrj 
524338fd1498Szrj       case '\t':
524438fd1498Szrj       case ' ':
524538fd1498Szrj 	end_going_arg ();
524638fd1498Szrj 
524738fd1498Szrj 	/* Reinitialize for a new argument.  */
524838fd1498Szrj 	delete_this_arg = 0;
524938fd1498Szrj 	this_is_output_file = 0;
525038fd1498Szrj 	this_is_library_file = 0;
525138fd1498Szrj 	this_is_linker_script = 0;
525238fd1498Szrj 	break;
525338fd1498Szrj 
525438fd1498Szrj       case '%':
525538fd1498Szrj 	switch (c = *p++)
525638fd1498Szrj 	  {
525738fd1498Szrj 	  case 0:
525838fd1498Szrj 	    fatal_error (input_location, "spec %qs invalid", spec);
525938fd1498Szrj 
526038fd1498Szrj 	  case 'b':
526138fd1498Szrj 	    if (save_temps_length)
526238fd1498Szrj 	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
526338fd1498Szrj 	    else
526438fd1498Szrj 	      obstack_grow (&obstack, input_basename, basename_length);
526538fd1498Szrj 	    if (compare_debug < 0)
526638fd1498Szrj 	      obstack_grow (&obstack, ".gk", 3);
526738fd1498Szrj 	    arg_going = 1;
526838fd1498Szrj 	    break;
526938fd1498Szrj 
527038fd1498Szrj 	  case 'B':
527138fd1498Szrj 	    if (save_temps_length)
527238fd1498Szrj 	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
527338fd1498Szrj 	    else
527438fd1498Szrj 	      obstack_grow (&obstack, input_basename, suffixed_basename_length);
527538fd1498Szrj 	    if (compare_debug < 0)
527638fd1498Szrj 	      obstack_grow (&obstack, ".gk", 3);
527738fd1498Szrj 	    arg_going = 1;
527838fd1498Szrj 	    break;
527938fd1498Szrj 
528038fd1498Szrj 	  case 'd':
528138fd1498Szrj 	    delete_this_arg = 2;
528238fd1498Szrj 	    break;
528338fd1498Szrj 
528438fd1498Szrj 	  /* Dump out the directories specified with LIBRARY_PATH,
528538fd1498Szrj 	     followed by the absolute directories
528638fd1498Szrj 	     that we search for startfiles.  */
528738fd1498Szrj 	  case 'D':
528838fd1498Szrj 	    {
528938fd1498Szrj 	      struct spec_path_info info;
529038fd1498Szrj 
529138fd1498Szrj 	      info.option = "-L";
529238fd1498Szrj 	      info.append_len = 0;
529338fd1498Szrj #ifdef RELATIVE_PREFIX_NOT_LINKDIR
529438fd1498Szrj 	      /* Used on systems which record the specified -L dirs
529538fd1498Szrj 		 and use them to search for dynamic linking.
529638fd1498Szrj 		 Relative directories always come from -B,
529738fd1498Szrj 		 and it is better not to use them for searching
529838fd1498Szrj 		 at run time.  In particular, stage1 loses.  */
529938fd1498Szrj 	      info.omit_relative = true;
530038fd1498Szrj #else
530138fd1498Szrj 	      info.omit_relative = false;
530238fd1498Szrj #endif
530338fd1498Szrj 	      info.separate_options = false;
530438fd1498Szrj 
530538fd1498Szrj 	      for_each_path (&startfile_prefixes, true, 0, spec_path, &info);
530638fd1498Szrj 	    }
530738fd1498Szrj 	    break;
530838fd1498Szrj 
530938fd1498Szrj 	  case 'e':
531038fd1498Szrj 	    /* %efoo means report an error with `foo' as error message
531138fd1498Szrj 	       and don't execute any more commands for this file.  */
531238fd1498Szrj 	    {
531338fd1498Szrj 	      const char *q = p;
531438fd1498Szrj 	      char *buf;
531538fd1498Szrj 	      while (*p != 0 && *p != '\n')
531638fd1498Szrj 		p++;
531738fd1498Szrj 	      buf = (char *) alloca (p - q + 1);
531838fd1498Szrj 	      strncpy (buf, q, p - q);
531938fd1498Szrj 	      buf[p - q] = 0;
532038fd1498Szrj 	      error ("%s", _(buf));
532138fd1498Szrj 	      return -1;
532238fd1498Szrj 	    }
532338fd1498Szrj 	    break;
532438fd1498Szrj 	  case 'n':
532538fd1498Szrj 	    /* %nfoo means report a notice with `foo' on stderr.  */
532638fd1498Szrj 	    {
532738fd1498Szrj 	      const char *q = p;
532838fd1498Szrj 	      char *buf;
532938fd1498Szrj 	      while (*p != 0 && *p != '\n')
533038fd1498Szrj 		p++;
533138fd1498Szrj 	      buf = (char *) alloca (p - q + 1);
533238fd1498Szrj 	      strncpy (buf, q, p - q);
533338fd1498Szrj 	      buf[p - q] = 0;
533438fd1498Szrj 	      inform (UNKNOWN_LOCATION, "%s", _(buf));
533538fd1498Szrj 	      if (*p)
533638fd1498Szrj 		p++;
533738fd1498Szrj 	    }
533838fd1498Szrj 	    break;
533938fd1498Szrj 
534038fd1498Szrj 	  case 'j':
534138fd1498Szrj 	    {
534238fd1498Szrj 	      struct stat st;
534338fd1498Szrj 
534438fd1498Szrj 	      /* If save_temps_flag is off, and the HOST_BIT_BUCKET is
534538fd1498Szrj 		 defined, and it is not a directory, and it is
534638fd1498Szrj 		 writable, use it.  Otherwise, treat this like any
534738fd1498Szrj 		 other temporary file.  */
534838fd1498Szrj 
534938fd1498Szrj 	      if ((!save_temps_flag)
535038fd1498Szrj 		  && (stat (HOST_BIT_BUCKET, &st) == 0) && (!S_ISDIR (st.st_mode))
535138fd1498Szrj 		  && (access (HOST_BIT_BUCKET, W_OK) == 0))
535238fd1498Szrj 		{
535338fd1498Szrj 		  obstack_grow (&obstack, HOST_BIT_BUCKET,
535438fd1498Szrj 				strlen (HOST_BIT_BUCKET));
535538fd1498Szrj 		  delete_this_arg = 0;
535638fd1498Szrj 		  arg_going = 1;
535738fd1498Szrj 		  break;
535838fd1498Szrj 		}
535938fd1498Szrj 	    }
536038fd1498Szrj 	    goto create_temp_file;
536138fd1498Szrj 	  case '|':
536238fd1498Szrj 	    if (use_pipes)
536338fd1498Szrj 	      {
536438fd1498Szrj 		obstack_1grow (&obstack, '-');
536538fd1498Szrj 		delete_this_arg = 0;
536638fd1498Szrj 		arg_going = 1;
536738fd1498Szrj 
536838fd1498Szrj 		/* consume suffix */
536938fd1498Szrj 		while (*p == '.' || ISALNUM ((unsigned char) *p))
537038fd1498Szrj 		  p++;
537138fd1498Szrj 		if (p[0] == '%' && p[1] == 'O')
537238fd1498Szrj 		  p += 2;
537338fd1498Szrj 
537438fd1498Szrj 		break;
537538fd1498Szrj 	      }
537638fd1498Szrj 	    goto create_temp_file;
537738fd1498Szrj 	  case 'm':
537838fd1498Szrj 	    if (use_pipes)
537938fd1498Szrj 	      {
538038fd1498Szrj 		/* consume suffix */
538138fd1498Szrj 		while (*p == '.' || ISALNUM ((unsigned char) *p))
538238fd1498Szrj 		  p++;
538338fd1498Szrj 		if (p[0] == '%' && p[1] == 'O')
538438fd1498Szrj 		  p += 2;
538538fd1498Szrj 
538638fd1498Szrj 		break;
538738fd1498Szrj 	      }
538838fd1498Szrj 	    goto create_temp_file;
538938fd1498Szrj 	  case 'g':
539038fd1498Szrj 	  case 'u':
539138fd1498Szrj 	  case 'U':
539238fd1498Szrj 	  create_temp_file:
539338fd1498Szrj 	      {
539438fd1498Szrj 		struct temp_name *t;
539538fd1498Szrj 		int suffix_length;
539638fd1498Szrj 		const char *suffix = p;
539738fd1498Szrj 		char *saved_suffix = NULL;
539838fd1498Szrj 
539938fd1498Szrj 		while (*p == '.' || ISALNUM ((unsigned char) *p))
540038fd1498Szrj 		  p++;
540138fd1498Szrj 		suffix_length = p - suffix;
540238fd1498Szrj 		if (p[0] == '%' && p[1] == 'O')
540338fd1498Szrj 		  {
540438fd1498Szrj 		    p += 2;
540538fd1498Szrj 		    /* We don't support extra suffix characters after %O.  */
540638fd1498Szrj 		    if (*p == '.' || ISALNUM ((unsigned char) *p))
540738fd1498Szrj 		      fatal_error (input_location,
540838fd1498Szrj 				   "spec %qs has invalid %<%%0%c%>", spec, *p);
540938fd1498Szrj 		    if (suffix_length == 0)
541038fd1498Szrj 		      suffix = TARGET_OBJECT_SUFFIX;
541138fd1498Szrj 		    else
541238fd1498Szrj 		      {
541338fd1498Szrj 			saved_suffix
541438fd1498Szrj 			  = XNEWVEC (char, suffix_length
541538fd1498Szrj 				     + strlen (TARGET_OBJECT_SUFFIX) + 1);
541638fd1498Szrj 			strncpy (saved_suffix, suffix, suffix_length);
541738fd1498Szrj 			strcpy (saved_suffix + suffix_length,
541838fd1498Szrj 				TARGET_OBJECT_SUFFIX);
541938fd1498Szrj 		      }
542038fd1498Szrj 		    suffix_length += strlen (TARGET_OBJECT_SUFFIX);
542138fd1498Szrj 		  }
542238fd1498Szrj 
542338fd1498Szrj 		if (compare_debug < 0)
542438fd1498Szrj 		  {
542538fd1498Szrj 		    suffix = concat (".gk", suffix, NULL);
542638fd1498Szrj 		    suffix_length += 3;
542738fd1498Szrj 		  }
542838fd1498Szrj 
542938fd1498Szrj 		/* If -save-temps=obj and -o were specified, use that for the
543038fd1498Szrj 		   temp file.  */
543138fd1498Szrj 		if (save_temps_length)
543238fd1498Szrj 		  {
543338fd1498Szrj 		    char *tmp;
543438fd1498Szrj 		    temp_filename_length
543538fd1498Szrj 		      = save_temps_length + suffix_length + 1;
543638fd1498Szrj 		    tmp = (char *) alloca (temp_filename_length);
543738fd1498Szrj 		    memcpy (tmp, save_temps_prefix, save_temps_length);
543838fd1498Szrj 		    memcpy (tmp + save_temps_length, suffix, suffix_length);
543938fd1498Szrj 		    tmp[save_temps_length + suffix_length] = '\0';
544038fd1498Szrj 		    temp_filename = save_string (tmp, save_temps_length
544138fd1498Szrj 						      + suffix_length);
544238fd1498Szrj 		    obstack_grow (&obstack, temp_filename,
544338fd1498Szrj 				  temp_filename_length);
544438fd1498Szrj 		    arg_going = 1;
544538fd1498Szrj 		    delete_this_arg = 0;
544638fd1498Szrj 		    break;
544738fd1498Szrj 		  }
544838fd1498Szrj 
544938fd1498Szrj 		/* If the gcc_input_filename has the same suffix specified
545038fd1498Szrj 		   for the %g, %u, or %U, and -save-temps is specified,
545138fd1498Szrj 		   we could end up using that file as an intermediate
545238fd1498Szrj 		   thus clobbering the user's source file (.e.g.,
545338fd1498Szrj 		   gcc -save-temps foo.s would clobber foo.s with the
545438fd1498Szrj 		   output of cpp0).  So check for this condition and
545538fd1498Szrj 		   generate a temp file as the intermediate.  */
545638fd1498Szrj 
545738fd1498Szrj 		if (save_temps_flag)
545838fd1498Szrj 		  {
545938fd1498Szrj 		    char *tmp;
546038fd1498Szrj 		    temp_filename_length = basename_length + suffix_length + 1;
546138fd1498Szrj 		    tmp = (char *) alloca (temp_filename_length);
546238fd1498Szrj 		    memcpy (tmp, input_basename, basename_length);
546338fd1498Szrj 		    memcpy (tmp + basename_length, suffix, suffix_length);
546438fd1498Szrj 		    tmp[basename_length + suffix_length] = '\0';
546538fd1498Szrj 		    temp_filename = tmp;
546638fd1498Szrj 
546738fd1498Szrj 		    if (filename_cmp (temp_filename, gcc_input_filename) != 0)
546838fd1498Szrj 		      {
546938fd1498Szrj #ifndef HOST_LACKS_INODE_NUMBERS
547038fd1498Szrj 			struct stat st_temp;
547138fd1498Szrj 
547238fd1498Szrj 			/* Note, set_input() resets input_stat_set to 0.  */
547338fd1498Szrj 			if (input_stat_set == 0)
547438fd1498Szrj 			  {
547538fd1498Szrj 			    input_stat_set = stat (gcc_input_filename,
547638fd1498Szrj 						   &input_stat);
547738fd1498Szrj 			    if (input_stat_set >= 0)
547838fd1498Szrj 			      input_stat_set = 1;
547938fd1498Szrj 			  }
548038fd1498Szrj 
548138fd1498Szrj 			/* If we have the stat for the gcc_input_filename
548238fd1498Szrj 			   and we can do the stat for the temp_filename
548338fd1498Szrj 			   then the they could still refer to the same
548438fd1498Szrj 			   file if st_dev/st_ino's are the same.  */
548538fd1498Szrj 			if (input_stat_set != 1
548638fd1498Szrj 			    || stat (temp_filename, &st_temp) < 0
548738fd1498Szrj 			    || input_stat.st_dev != st_temp.st_dev
548838fd1498Szrj 			    || input_stat.st_ino != st_temp.st_ino)
548938fd1498Szrj #else
549038fd1498Szrj 			/* Just compare canonical pathnames.  */
549138fd1498Szrj 			char* input_realname = lrealpath (gcc_input_filename);
549238fd1498Szrj 			char* temp_realname = lrealpath (temp_filename);
549338fd1498Szrj 			bool files_differ = filename_cmp (input_realname, temp_realname);
549438fd1498Szrj 			free (input_realname);
549538fd1498Szrj 			free (temp_realname);
549638fd1498Szrj 			if (files_differ)
549738fd1498Szrj #endif
549838fd1498Szrj 			  {
549938fd1498Szrj 			    temp_filename
550038fd1498Szrj 			      = save_string (temp_filename,
550138fd1498Szrj 					     temp_filename_length - 1);
550238fd1498Szrj 			    obstack_grow (&obstack, temp_filename,
550338fd1498Szrj 						    temp_filename_length);
550438fd1498Szrj 			    arg_going = 1;
550538fd1498Szrj 			    delete_this_arg = 0;
550638fd1498Szrj 			    break;
550738fd1498Szrj 			  }
550838fd1498Szrj 		      }
550938fd1498Szrj 		  }
551038fd1498Szrj 
551138fd1498Szrj 		/* See if we already have an association of %g/%u/%U and
551238fd1498Szrj 		   suffix.  */
551338fd1498Szrj 		for (t = temp_names; t; t = t->next)
551438fd1498Szrj 		  if (t->length == suffix_length
551538fd1498Szrj 		      && strncmp (t->suffix, suffix, suffix_length) == 0
551638fd1498Szrj 		      && t->unique == (c == 'u' || c == 'U' || c == 'j'))
551738fd1498Szrj 		    break;
551838fd1498Szrj 
551938fd1498Szrj 		/* Make a new association if needed.  %u and %j
552038fd1498Szrj 		   require one.  */
552138fd1498Szrj 		if (t == 0 || c == 'u' || c == 'j')
552238fd1498Szrj 		  {
552338fd1498Szrj 		    if (t == 0)
552438fd1498Szrj 		      {
552538fd1498Szrj 			t = XNEW (struct temp_name);
552638fd1498Szrj 			t->next = temp_names;
552738fd1498Szrj 			temp_names = t;
552838fd1498Szrj 		      }
552938fd1498Szrj 		    t->length = suffix_length;
553038fd1498Szrj 		    if (saved_suffix)
553138fd1498Szrj 		      {
553238fd1498Szrj 			t->suffix = saved_suffix;
553338fd1498Szrj 			saved_suffix = NULL;
553438fd1498Szrj 		      }
553538fd1498Szrj 		    else
553638fd1498Szrj 		      t->suffix = save_string (suffix, suffix_length);
553738fd1498Szrj 		    t->unique = (c == 'u' || c == 'U' || c == 'j');
553838fd1498Szrj 		    temp_filename = make_temp_file (t->suffix);
553938fd1498Szrj 		    temp_filename_length = strlen (temp_filename);
554038fd1498Szrj 		    t->filename = temp_filename;
554138fd1498Szrj 		    t->filename_length = temp_filename_length;
554238fd1498Szrj 		  }
554338fd1498Szrj 
554438fd1498Szrj 		free (saved_suffix);
554538fd1498Szrj 
554638fd1498Szrj 		obstack_grow (&obstack, t->filename, t->filename_length);
554738fd1498Szrj 		delete_this_arg = 1;
554838fd1498Szrj 	      }
554938fd1498Szrj 	    arg_going = 1;
555038fd1498Szrj 	    break;
555138fd1498Szrj 
555238fd1498Szrj 	  case 'i':
555338fd1498Szrj 	    if (combine_inputs)
555438fd1498Szrj 	      {
555538fd1498Szrj 		if (at_file_supplied)
555638fd1498Szrj 		  {
555738fd1498Szrj 		    /* We are going to expand `%i' to `@FILE', where FILE
555838fd1498Szrj 		       is a newly-created temporary filename.  The filenames
555938fd1498Szrj 		       that would usually be expanded in place of %o will be
556038fd1498Szrj 		       written to the temporary file.  */
556138fd1498Szrj 		    char **argv;
556238fd1498Szrj 		    int n_files = 0;
556338fd1498Szrj 		    int j;
556438fd1498Szrj 
556538fd1498Szrj 		    for (i = 0; i < n_infiles; i++)
556638fd1498Szrj 		      if (compile_input_file_p (&infiles[i]))
556738fd1498Szrj 			n_files++;
556838fd1498Szrj 
556938fd1498Szrj 		    argv = (char **) alloca (sizeof (char *) * (n_files + 1));
557038fd1498Szrj 
557138fd1498Szrj 		    /* Copy the strings over.  */
557238fd1498Szrj 		    for (i = 0, j = 0; i < n_infiles; i++)
557338fd1498Szrj 		      if (compile_input_file_p (&infiles[i]))
557438fd1498Szrj 			{
557538fd1498Szrj 			  argv[j] = CONST_CAST (char *, infiles[i].name);
557638fd1498Szrj 			  infiles[i].compiled = true;
557738fd1498Szrj 			  j++;
557838fd1498Szrj 			}
557938fd1498Szrj 		    argv[j] = NULL;
558038fd1498Szrj 
558138fd1498Szrj 		    create_at_file (argv);
558238fd1498Szrj 		  }
558338fd1498Szrj 		else
558438fd1498Szrj 		  for (i = 0; (int) i < n_infiles; i++)
558538fd1498Szrj 		    if (compile_input_file_p (&infiles[i]))
558638fd1498Szrj 		      {
558738fd1498Szrj 			store_arg (infiles[i].name, 0, 0);
558838fd1498Szrj 			infiles[i].compiled = true;
558938fd1498Szrj 		      }
559038fd1498Szrj 	      }
559138fd1498Szrj 	    else
559238fd1498Szrj 	      {
559338fd1498Szrj 		obstack_grow (&obstack, gcc_input_filename,
559438fd1498Szrj 			      input_filename_length);
559538fd1498Szrj 		arg_going = 1;
559638fd1498Szrj 	      }
559738fd1498Szrj 	    break;
559838fd1498Szrj 
559938fd1498Szrj 	  case 'I':
560038fd1498Szrj 	    {
560138fd1498Szrj 	      struct spec_path_info info;
560238fd1498Szrj 
560338fd1498Szrj 	      if (multilib_dir)
560438fd1498Szrj 		{
560538fd1498Szrj 		  do_spec_1 ("-imultilib", 1, NULL);
560638fd1498Szrj 		  /* Make this a separate argument.  */
560738fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
560838fd1498Szrj 		  do_spec_1 (multilib_dir, 1, NULL);
560938fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
561038fd1498Szrj 		}
561138fd1498Szrj 
561238fd1498Szrj 	      if (multiarch_dir)
561338fd1498Szrj 		{
561438fd1498Szrj 		  do_spec_1 ("-imultiarch", 1, NULL);
561538fd1498Szrj 		  /* Make this a separate argument.  */
561638fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
561738fd1498Szrj 		  do_spec_1 (multiarch_dir, 1, NULL);
561838fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
561938fd1498Szrj 		}
562038fd1498Szrj 
562138fd1498Szrj 	      if (gcc_exec_prefix)
562238fd1498Szrj 		{
562338fd1498Szrj 		  do_spec_1 ("-iprefix", 1, NULL);
562438fd1498Szrj 		  /* Make this a separate argument.  */
562538fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
562638fd1498Szrj 		  do_spec_1 (gcc_exec_prefix, 1, NULL);
562738fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
562838fd1498Szrj 		}
562938fd1498Szrj 
563038fd1498Szrj 	      if (target_system_root_changed ||
563138fd1498Szrj 		  (target_system_root && target_sysroot_hdrs_suffix))
563238fd1498Szrj 		{
563338fd1498Szrj 		  do_spec_1 ("-isysroot", 1, NULL);
563438fd1498Szrj 		  /* Make this a separate argument.  */
563538fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
563638fd1498Szrj 		  do_spec_1 (target_system_root, 1, NULL);
563738fd1498Szrj 		  if (target_sysroot_hdrs_suffix)
563838fd1498Szrj 		    do_spec_1 (target_sysroot_hdrs_suffix, 1, NULL);
563938fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
564038fd1498Szrj 		}
564138fd1498Szrj 
564238fd1498Szrj 	      info.option = "-isystem";
564338fd1498Szrj 	      info.append = "include";
564438fd1498Szrj 	      info.append_len = strlen (info.append);
564538fd1498Szrj 	      info.omit_relative = false;
564638fd1498Szrj 	      info.separate_options = true;
564738fd1498Szrj 
564838fd1498Szrj 	      for_each_path (&include_prefixes, false, info.append_len,
564938fd1498Szrj 			     spec_path, &info);
565038fd1498Szrj 
565138fd1498Szrj 	      info.append = "include-fixed";
565238fd1498Szrj 	      if (*sysroot_hdrs_suffix_spec)
565338fd1498Szrj 		info.append = concat (info.append, dir_separator_str,
565438fd1498Szrj 				      multilib_dir, NULL);
565538fd1498Szrj 	      info.append_len = strlen (info.append);
565638fd1498Szrj 	      for_each_path (&include_prefixes, false, info.append_len,
565738fd1498Szrj 			     spec_path, &info);
565838fd1498Szrj 	    }
565938fd1498Szrj 	    break;
566038fd1498Szrj 
566138fd1498Szrj 	  case 'o':
566238fd1498Szrj 	    {
566338fd1498Szrj 	      int max = n_infiles;
566438fd1498Szrj 	      max += lang_specific_extra_outfiles;
566538fd1498Szrj 
566638fd1498Szrj               if (HAVE_GNU_LD && at_file_supplied)
566738fd1498Szrj                 {
566838fd1498Szrj                   /* We are going to expand `%o' to `@FILE', where FILE
566938fd1498Szrj                      is a newly-created temporary filename.  The filenames
567038fd1498Szrj                      that would usually be expanded in place of %o will be
567138fd1498Szrj                      written to the temporary file.  */
567238fd1498Szrj 
567338fd1498Szrj                   char **argv;
567438fd1498Szrj                   int n_files, j;
567538fd1498Szrj 
567638fd1498Szrj                   /* Convert OUTFILES into a form suitable for writeargv.  */
567738fd1498Szrj 
567838fd1498Szrj                   /* Determine how many are non-NULL.  */
567938fd1498Szrj                   for (n_files = 0, i = 0; i < max; i++)
568038fd1498Szrj                     n_files += outfiles[i] != NULL;
568138fd1498Szrj 
568238fd1498Szrj                   argv = (char **) alloca (sizeof (char *) * (n_files + 1));
568338fd1498Szrj 
568438fd1498Szrj                   /* Copy the strings over.  */
568538fd1498Szrj                   for (i = 0, j = 0; i < max; i++)
568638fd1498Szrj                     if (outfiles[i])
568738fd1498Szrj                       {
568838fd1498Szrj                         argv[j] = CONST_CAST (char *, outfiles[i]);
568938fd1498Szrj                         j++;
569038fd1498Szrj                       }
569138fd1498Szrj                   argv[j] = NULL;
569238fd1498Szrj 
569338fd1498Szrj 		  create_at_file (argv);
569438fd1498Szrj                 }
569538fd1498Szrj               else
569638fd1498Szrj                 for (i = 0; i < max; i++)
569738fd1498Szrj 	          if (outfiles[i])
569838fd1498Szrj 		    store_arg (outfiles[i], 0, 0);
569938fd1498Szrj 	      break;
570038fd1498Szrj 	    }
570138fd1498Szrj 
570238fd1498Szrj 	  case 'O':
570338fd1498Szrj 	    obstack_grow (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX));
570438fd1498Szrj 	    arg_going = 1;
570538fd1498Szrj 	    break;
570638fd1498Szrj 
570738fd1498Szrj 	  case 's':
570838fd1498Szrj 	    this_is_library_file = 1;
570938fd1498Szrj 	    break;
571038fd1498Szrj 
571138fd1498Szrj 	  case 'T':
571238fd1498Szrj 	    this_is_linker_script = 1;
571338fd1498Szrj 	    break;
571438fd1498Szrj 
571538fd1498Szrj 	  case 'V':
571638fd1498Szrj 	    outfiles[input_file_number] = NULL;
571738fd1498Szrj 	    break;
571838fd1498Szrj 
571938fd1498Szrj 	  case 'w':
572038fd1498Szrj 	    this_is_output_file = 1;
572138fd1498Szrj 	    break;
572238fd1498Szrj 
572338fd1498Szrj 	  case 'W':
572438fd1498Szrj 	    {
572538fd1498Szrj 	      unsigned int cur_index = argbuf.length ();
572638fd1498Szrj 	      /* Handle the {...} following the %W.  */
572738fd1498Szrj 	      if (*p != '{')
572838fd1498Szrj 		fatal_error (input_location,
572938fd1498Szrj 			     "spec %qs has invalid %<%%W%c%>", spec, *p);
573038fd1498Szrj 	      p = handle_braces (p + 1);
573138fd1498Szrj 	      if (p == 0)
573238fd1498Szrj 		return -1;
573338fd1498Szrj 	      end_going_arg ();
573438fd1498Szrj 	      /* If any args were output, mark the last one for deletion
573538fd1498Szrj 		 on failure.  */
573638fd1498Szrj 	      if (argbuf.length () != cur_index)
573738fd1498Szrj 		record_temp_file (argbuf.last (), 0, 1);
573838fd1498Szrj 	      break;
573938fd1498Szrj 	    }
574038fd1498Szrj 
574138fd1498Szrj 	  /* %x{OPTION} records OPTION for %X to output.  */
574238fd1498Szrj 	  case 'x':
574338fd1498Szrj 	    {
574438fd1498Szrj 	      const char *p1 = p;
574538fd1498Szrj 	      char *string;
574638fd1498Szrj 	      char *opt;
574738fd1498Szrj 	      unsigned ix;
574838fd1498Szrj 
574938fd1498Szrj 	      /* Skip past the option value and make a copy.  */
575038fd1498Szrj 	      if (*p != '{')
575138fd1498Szrj 		fatal_error (input_location,
575238fd1498Szrj 			     "spec %qs has invalid %<%%x%c%>", spec, *p);
575338fd1498Szrj 	      while (*p++ != '}')
575438fd1498Szrj 		;
575538fd1498Szrj 	      string = save_string (p1 + 1, p - p1 - 2);
575638fd1498Szrj 
575738fd1498Szrj 	      /* See if we already recorded this option.  */
575838fd1498Szrj 	      FOR_EACH_VEC_ELT (linker_options, ix, opt)
575938fd1498Szrj 		if (! strcmp (string, opt))
576038fd1498Szrj 		  {
576138fd1498Szrj 		    free (string);
576238fd1498Szrj 		    return 0;
576338fd1498Szrj 		  }
576438fd1498Szrj 
576538fd1498Szrj 	      /* This option is new; add it.  */
576638fd1498Szrj 	      add_linker_option (string, strlen (string));
576738fd1498Szrj 	      free (string);
576838fd1498Szrj 	    }
576938fd1498Szrj 	    break;
577038fd1498Szrj 
577138fd1498Szrj 	  /* Dump out the options accumulated previously using %x.  */
577238fd1498Szrj 	  case 'X':
577338fd1498Szrj 	    do_specs_vec (linker_options);
577438fd1498Szrj 	    break;
577538fd1498Szrj 
577638fd1498Szrj 	  /* Dump out the options accumulated previously using -Wa,.  */
577738fd1498Szrj 	  case 'Y':
577838fd1498Szrj 	    do_specs_vec (assembler_options);
577938fd1498Szrj 	    break;
578038fd1498Szrj 
578138fd1498Szrj 	  /* Dump out the options accumulated previously using -Wp,.  */
578238fd1498Szrj 	  case 'Z':
578338fd1498Szrj 	    do_specs_vec (preprocessor_options);
578438fd1498Szrj 	    break;
578538fd1498Szrj 
578638fd1498Szrj 	    /* Here are digits and numbers that just process
578738fd1498Szrj 	       a certain constant string as a spec.  */
578838fd1498Szrj 
578938fd1498Szrj 	  case '1':
579038fd1498Szrj 	    value = do_spec_1 (cc1_spec, 0, NULL);
579138fd1498Szrj 	    if (value != 0)
579238fd1498Szrj 	      return value;
579338fd1498Szrj 	    break;
579438fd1498Szrj 
579538fd1498Szrj 	  case '2':
579638fd1498Szrj 	    value = do_spec_1 (cc1plus_spec, 0, NULL);
579738fd1498Szrj 	    if (value != 0)
579838fd1498Szrj 	      return value;
579938fd1498Szrj 	    break;
580038fd1498Szrj 
580138fd1498Szrj 	  case 'a':
580238fd1498Szrj 	    value = do_spec_1 (asm_spec, 0, NULL);
580338fd1498Szrj 	    if (value != 0)
580438fd1498Szrj 	      return value;
580538fd1498Szrj 	    break;
580638fd1498Szrj 
580738fd1498Szrj 	  case 'A':
580838fd1498Szrj 	    value = do_spec_1 (asm_final_spec, 0, NULL);
580938fd1498Szrj 	    if (value != 0)
581038fd1498Szrj 	      return value;
581138fd1498Szrj 	    break;
581238fd1498Szrj 
581338fd1498Szrj 	  case 'C':
581438fd1498Szrj 	    {
581538fd1498Szrj 	      const char *const spec
581638fd1498Szrj 		= (input_file_compiler->cpp_spec
581738fd1498Szrj 		   ? input_file_compiler->cpp_spec
581838fd1498Szrj 		   : cpp_spec);
581938fd1498Szrj 	      value = do_spec_1 (spec, 0, NULL);
582038fd1498Szrj 	      if (value != 0)
582138fd1498Szrj 		return value;
582238fd1498Szrj 	    }
582338fd1498Szrj 	    break;
582438fd1498Szrj 
582538fd1498Szrj 	  case 'E':
582638fd1498Szrj 	    value = do_spec_1 (endfile_spec, 0, NULL);
582738fd1498Szrj 	    if (value != 0)
582838fd1498Szrj 	      return value;
582938fd1498Szrj 	    break;
583038fd1498Szrj 
583138fd1498Szrj 	  case 'l':
583238fd1498Szrj 	    value = do_spec_1 (link_spec, 0, NULL);
583338fd1498Szrj 	    if (value != 0)
583438fd1498Szrj 	      return value;
583538fd1498Szrj 	    break;
583638fd1498Szrj 
583738fd1498Szrj 	  case 'L':
583838fd1498Szrj 	    value = do_spec_1 (lib_spec, 0, NULL);
583938fd1498Szrj 	    if (value != 0)
584038fd1498Szrj 	      return value;
584138fd1498Szrj 	    break;
584238fd1498Szrj 
584338fd1498Szrj 	  case 'M':
584438fd1498Szrj 	    if (multilib_os_dir == NULL)
584538fd1498Szrj 	      obstack_1grow (&obstack, '.');
584638fd1498Szrj 	    else
584738fd1498Szrj 	      obstack_grow (&obstack, multilib_os_dir,
584838fd1498Szrj 			    strlen (multilib_os_dir));
584938fd1498Szrj 	    break;
585038fd1498Szrj 
585138fd1498Szrj 	  case 'G':
585238fd1498Szrj 	    value = do_spec_1 (libgcc_spec, 0, NULL);
585338fd1498Szrj 	    if (value != 0)
585438fd1498Szrj 	      return value;
585538fd1498Szrj 	    break;
585638fd1498Szrj 
585738fd1498Szrj 	  case 'R':
585838fd1498Szrj 	    /* We assume there is a directory
585938fd1498Szrj 	       separator at the end of this string.  */
586038fd1498Szrj 	    if (target_system_root)
586138fd1498Szrj 	      {
586238fd1498Szrj 	        obstack_grow (&obstack, target_system_root,
586338fd1498Szrj 			      strlen (target_system_root));
586438fd1498Szrj 		if (target_sysroot_suffix)
586538fd1498Szrj 		  obstack_grow (&obstack, target_sysroot_suffix,
586638fd1498Szrj 				strlen (target_sysroot_suffix));
586738fd1498Szrj 	      }
586838fd1498Szrj 	    break;
586938fd1498Szrj 
587038fd1498Szrj 	  case 'S':
587138fd1498Szrj 	    value = do_spec_1 (startfile_spec, 0, NULL);
587238fd1498Szrj 	    if (value != 0)
587338fd1498Szrj 	      return value;
587438fd1498Szrj 	    break;
587538fd1498Szrj 
587638fd1498Szrj 	    /* Here we define characters other than letters and digits.  */
587738fd1498Szrj 
587838fd1498Szrj 	  case '{':
587938fd1498Szrj 	    p = handle_braces (p);
588038fd1498Szrj 	    if (p == 0)
588138fd1498Szrj 	      return -1;
588238fd1498Szrj 	    break;
588338fd1498Szrj 
588438fd1498Szrj 	  case ':':
588538fd1498Szrj 	    p = handle_spec_function (p, NULL);
588638fd1498Szrj 	    if (p == 0)
588738fd1498Szrj 	      return -1;
588838fd1498Szrj 	    break;
588938fd1498Szrj 
589038fd1498Szrj 	  case '%':
589138fd1498Szrj 	    obstack_1grow (&obstack, '%');
589238fd1498Szrj 	    break;
589338fd1498Szrj 
589438fd1498Szrj 	  case '.':
589538fd1498Szrj 	    {
589638fd1498Szrj 	      unsigned len = 0;
589738fd1498Szrj 
589838fd1498Szrj 	      while (p[len] && p[len] != ' ' && p[len] != '%')
589938fd1498Szrj 		len++;
590038fd1498Szrj 	      suffix_subst = save_string (p - 1, len + 1);
590138fd1498Szrj 	      p += len;
590238fd1498Szrj 	    }
590338fd1498Szrj 	   break;
590438fd1498Szrj 
590538fd1498Szrj 	   /* Henceforth ignore the option(s) matching the pattern
590638fd1498Szrj 	      after the %<.  */
590738fd1498Szrj 	  case '<':
590838fd1498Szrj 	  case '>':
590938fd1498Szrj 	    {
591038fd1498Szrj 	      unsigned len = 0;
591138fd1498Szrj 	      int have_wildcard = 0;
591238fd1498Szrj 	      int i;
591338fd1498Szrj 	      int switch_option;
591438fd1498Szrj 
591538fd1498Szrj 	      if (c == '>')
591638fd1498Szrj 		switch_option = SWITCH_IGNORE | SWITCH_KEEP_FOR_GCC;
591738fd1498Szrj 	      else
591838fd1498Szrj 		switch_option = SWITCH_IGNORE;
591938fd1498Szrj 
592038fd1498Szrj 	      while (p[len] && p[len] != ' ' && p[len] != '\t')
592138fd1498Szrj 		len++;
592238fd1498Szrj 
592338fd1498Szrj 	      if (p[len-1] == '*')
592438fd1498Szrj 		have_wildcard = 1;
592538fd1498Szrj 
592638fd1498Szrj 	      for (i = 0; i < n_switches; i++)
592738fd1498Szrj 		if (!strncmp (switches[i].part1, p, len - have_wildcard)
592838fd1498Szrj 		    && (have_wildcard || switches[i].part1[len] == '\0'))
592938fd1498Szrj 		  {
593038fd1498Szrj 		    switches[i].live_cond |= switch_option;
593138fd1498Szrj 		    /* User switch be validated from validate_all_switches.
593238fd1498Szrj 		       when the definition is seen from the spec file.
593338fd1498Szrj 		       If not defined anywhere, will be rejected.  */
593438fd1498Szrj 		    if (switches[i].known)
593538fd1498Szrj 		      switches[i].validated = true;
593638fd1498Szrj 		  }
593738fd1498Szrj 
593838fd1498Szrj 	      p += len;
593938fd1498Szrj 	    }
594038fd1498Szrj 	    break;
594138fd1498Szrj 
594238fd1498Szrj 	  case '*':
594338fd1498Szrj 	    if (soft_matched_part)
594438fd1498Szrj 	      {
594538fd1498Szrj 		if (soft_matched_part[0])
594638fd1498Szrj 		  do_spec_1 (soft_matched_part, 1, NULL);
594738fd1498Szrj 		/* Only insert a space after the substitution if it is at the
594838fd1498Szrj 		   end of the current sequence.  So if:
594938fd1498Szrj 
595038fd1498Szrj 		     "%{foo=*:bar%*}%{foo=*:one%*two}"
595138fd1498Szrj 
595238fd1498Szrj 		   matches -foo=hello then it will produce:
595338fd1498Szrj 
595438fd1498Szrj 		     barhello onehellotwo
595538fd1498Szrj 		*/
595638fd1498Szrj 		if (*p == 0 || *p == '}')
595738fd1498Szrj 		  do_spec_1 (" ", 0, NULL);
595838fd1498Szrj 	      }
595938fd1498Szrj 	    else
596038fd1498Szrj 	      /* Catch the case where a spec string contains something like
596138fd1498Szrj 		 '%{foo:%*}'.  i.e. there is no * in the pattern on the left
596238fd1498Szrj 		 hand side of the :.  */
596338fd1498Szrj 	      error ("spec failure: %<%%*%> has not been initialized by pattern match");
596438fd1498Szrj 	    break;
596538fd1498Szrj 
596638fd1498Szrj 	    /* Process a string found as the value of a spec given by name.
596738fd1498Szrj 	       This feature allows individual machine descriptions
596838fd1498Szrj 	       to add and use their own specs.  */
596938fd1498Szrj 	  case '(':
597038fd1498Szrj 	    {
597138fd1498Szrj 	      const char *name = p;
597238fd1498Szrj 	      struct spec_list *sl;
597338fd1498Szrj 	      int len;
597438fd1498Szrj 
597538fd1498Szrj 	      /* The string after the S/P is the name of a spec that is to be
597638fd1498Szrj 		 processed.  */
597738fd1498Szrj 	      while (*p && *p != ')')
597838fd1498Szrj 		p++;
597938fd1498Szrj 
598038fd1498Szrj 	      /* See if it's in the list.  */
598138fd1498Szrj 	      for (len = p - name, sl = specs; sl; sl = sl->next)
598238fd1498Szrj 		if (sl->name_len == len && !strncmp (sl->name, name, len))
598338fd1498Szrj 		  {
598438fd1498Szrj 		    name = *(sl->ptr_spec);
598538fd1498Szrj #ifdef DEBUG_SPECS
598638fd1498Szrj 		    fnotice (stderr, "Processing spec (%s), which is '%s'\n",
598738fd1498Szrj 			     sl->name, name);
598838fd1498Szrj #endif
598938fd1498Szrj 		    break;
599038fd1498Szrj 		  }
599138fd1498Szrj 
599238fd1498Szrj 	      if (sl)
599338fd1498Szrj 		{
599438fd1498Szrj 		  value = do_spec_1 (name, 0, NULL);
599538fd1498Szrj 		  if (value != 0)
599638fd1498Szrj 		    return value;
599738fd1498Szrj 		}
599838fd1498Szrj 
599938fd1498Szrj 	      /* Discard the closing paren.  */
600038fd1498Szrj 	      if (*p)
600138fd1498Szrj 		p++;
600238fd1498Szrj 	    }
600338fd1498Szrj 	    break;
600438fd1498Szrj 
600538fd1498Szrj 	  default:
600638fd1498Szrj 	    error ("spec failure: unrecognized spec option %qc", c);
600738fd1498Szrj 	    break;
600838fd1498Szrj 	  }
600938fd1498Szrj 	break;
601038fd1498Szrj 
601138fd1498Szrj       case '\\':
601238fd1498Szrj 	/* Backslash: treat next character as ordinary.  */
601338fd1498Szrj 	c = *p++;
601438fd1498Szrj 
601538fd1498Szrj 	/* Fall through.  */
601638fd1498Szrj       default:
601738fd1498Szrj 	/* Ordinary character: put it into the current argument.  */
601838fd1498Szrj 	obstack_1grow (&obstack, c);
601938fd1498Szrj 	arg_going = 1;
602038fd1498Szrj       }
602138fd1498Szrj 
602238fd1498Szrj   /* End of string.  If we are processing a spec function, we need to
602338fd1498Szrj      end any pending argument.  */
602438fd1498Szrj   if (processing_spec_function)
602538fd1498Szrj     end_going_arg ();
602638fd1498Szrj 
602738fd1498Szrj   return 0;
602838fd1498Szrj }
602938fd1498Szrj 
603038fd1498Szrj /* Look up a spec function.  */
603138fd1498Szrj 
603238fd1498Szrj static const struct spec_function *
lookup_spec_function(const char * name)603338fd1498Szrj lookup_spec_function (const char *name)
603438fd1498Szrj {
603538fd1498Szrj   const struct spec_function *sf;
603638fd1498Szrj 
603738fd1498Szrj   for (sf = static_spec_functions; sf->name != NULL; sf++)
603838fd1498Szrj     if (strcmp (sf->name, name) == 0)
603938fd1498Szrj       return sf;
604038fd1498Szrj 
604138fd1498Szrj   return NULL;
604238fd1498Szrj }
604338fd1498Szrj 
604438fd1498Szrj /* Evaluate a spec function.  */
604538fd1498Szrj 
604638fd1498Szrj static const char *
eval_spec_function(const char * func,const char * args)604738fd1498Szrj eval_spec_function (const char *func, const char *args)
604838fd1498Szrj {
604938fd1498Szrj   const struct spec_function *sf;
605038fd1498Szrj   const char *funcval;
605138fd1498Szrj 
605238fd1498Szrj   /* Saved spec processing context.  */
605338fd1498Szrj   vec<const_char_p> save_argbuf;
605438fd1498Szrj 
605538fd1498Szrj   int save_arg_going;
605638fd1498Szrj   int save_delete_this_arg;
605738fd1498Szrj   int save_this_is_output_file;
605838fd1498Szrj   int save_this_is_library_file;
605938fd1498Szrj   int save_input_from_pipe;
606038fd1498Szrj   int save_this_is_linker_script;
606138fd1498Szrj   const char *save_suffix_subst;
606238fd1498Szrj 
606338fd1498Szrj   int save_growing_size;
606438fd1498Szrj   void *save_growing_value = NULL;
606538fd1498Szrj 
606638fd1498Szrj   sf = lookup_spec_function (func);
606738fd1498Szrj   if (sf == NULL)
606838fd1498Szrj     fatal_error (input_location, "unknown spec function %qs", func);
606938fd1498Szrj 
607038fd1498Szrj   /* Push the spec processing context.  */
607138fd1498Szrj   save_argbuf = argbuf;
607238fd1498Szrj 
607338fd1498Szrj   save_arg_going = arg_going;
607438fd1498Szrj   save_delete_this_arg = delete_this_arg;
607538fd1498Szrj   save_this_is_output_file = this_is_output_file;
607638fd1498Szrj   save_this_is_library_file = this_is_library_file;
607738fd1498Szrj   save_this_is_linker_script = this_is_linker_script;
607838fd1498Szrj   save_input_from_pipe = input_from_pipe;
607938fd1498Szrj   save_suffix_subst = suffix_subst;
608038fd1498Szrj 
608138fd1498Szrj   /* If we have some object growing now, finalize it so the args and function
608238fd1498Szrj      eval proceed from a cleared context.  This is needed to prevent the first
608338fd1498Szrj      constructed arg from mistakenly including the growing value.  We'll push
608438fd1498Szrj      this value back on the obstack once the function evaluation is done, to
608538fd1498Szrj      restore a consistent processing context for our caller.  This is fine as
608638fd1498Szrj      the address of growing objects isn't guaranteed to remain stable until
608738fd1498Szrj      they are finalized, and we expect this situation to be rare enough for
608838fd1498Szrj      the extra copy not to be an issue.  */
608938fd1498Szrj   save_growing_size = obstack_object_size (&obstack);
609038fd1498Szrj   if (save_growing_size > 0)
609138fd1498Szrj     save_growing_value = obstack_finish (&obstack);
609238fd1498Szrj 
609338fd1498Szrj   /* Create a new spec processing context, and build the function
609438fd1498Szrj      arguments.  */
609538fd1498Szrj 
609638fd1498Szrj   alloc_args ();
609738fd1498Szrj   if (do_spec_2 (args) < 0)
609838fd1498Szrj     fatal_error (input_location, "error in args to spec function %qs", func);
609938fd1498Szrj 
610038fd1498Szrj   /* argbuf_index is an index for the next argument to be inserted, and
610138fd1498Szrj      so contains the count of the args already inserted.  */
610238fd1498Szrj 
610338fd1498Szrj   funcval = (*sf->func) (argbuf.length (),
610438fd1498Szrj 			 argbuf.address ());
610538fd1498Szrj 
610638fd1498Szrj   /* Pop the spec processing context.  */
610738fd1498Szrj   argbuf.release ();
610838fd1498Szrj   argbuf = save_argbuf;
610938fd1498Szrj 
611038fd1498Szrj   arg_going = save_arg_going;
611138fd1498Szrj   delete_this_arg = save_delete_this_arg;
611238fd1498Szrj   this_is_output_file = save_this_is_output_file;
611338fd1498Szrj   this_is_library_file = save_this_is_library_file;
611438fd1498Szrj   this_is_linker_script = save_this_is_linker_script;
611538fd1498Szrj   input_from_pipe = save_input_from_pipe;
611638fd1498Szrj   suffix_subst = save_suffix_subst;
611738fd1498Szrj 
611838fd1498Szrj   if (save_growing_size > 0)
611938fd1498Szrj     obstack_grow (&obstack, save_growing_value, save_growing_size);
612038fd1498Szrj 
612138fd1498Szrj   return funcval;
612238fd1498Szrj }
612338fd1498Szrj 
612438fd1498Szrj /* Handle a spec function call of the form:
612538fd1498Szrj 
612638fd1498Szrj    %:function(args)
612738fd1498Szrj 
612838fd1498Szrj    ARGS is processed as a spec in a separate context and split into an
612938fd1498Szrj    argument vector in the normal fashion.  The function returns a string
613038fd1498Szrj    containing a spec which we then process in the caller's context, or
613138fd1498Szrj    NULL if no processing is required.
613238fd1498Szrj 
613338fd1498Szrj    If RETVAL_NONNULL is not NULL, then store a bool whether function
613438fd1498Szrj    returned non-NULL.  */
613538fd1498Szrj 
613638fd1498Szrj static const char *
handle_spec_function(const char * p,bool * retval_nonnull)613738fd1498Szrj handle_spec_function (const char *p, bool *retval_nonnull)
613838fd1498Szrj {
613938fd1498Szrj   char *func, *args;
614038fd1498Szrj   const char *endp, *funcval;
614138fd1498Szrj   int count;
614238fd1498Szrj 
614338fd1498Szrj   processing_spec_function++;
614438fd1498Szrj 
614538fd1498Szrj   /* Get the function name.  */
614638fd1498Szrj   for (endp = p; *endp != '\0'; endp++)
614738fd1498Szrj     {
614838fd1498Szrj       if (*endp == '(')		/* ) */
614938fd1498Szrj         break;
615038fd1498Szrj       /* Only allow [A-Za-z0-9], -, and _ in function names.  */
615138fd1498Szrj       if (!ISALNUM (*endp) && !(*endp == '-' || *endp == '_'))
615238fd1498Szrj 	fatal_error (input_location, "malformed spec function name");
615338fd1498Szrj     }
615438fd1498Szrj   if (*endp != '(')		/* ) */
615538fd1498Szrj     fatal_error (input_location, "no arguments for spec function");
615638fd1498Szrj   func = save_string (p, endp - p);
615738fd1498Szrj   p = ++endp;
615838fd1498Szrj 
615938fd1498Szrj   /* Get the arguments.  */
616038fd1498Szrj   for (count = 0; *endp != '\0'; endp++)
616138fd1498Szrj     {
616238fd1498Szrj       /* ( */
616338fd1498Szrj       if (*endp == ')')
616438fd1498Szrj 	{
616538fd1498Szrj 	  if (count == 0)
616638fd1498Szrj 	    break;
616738fd1498Szrj 	  count--;
616838fd1498Szrj 	}
616938fd1498Szrj       else if (*endp == '(')	/* ) */
617038fd1498Szrj 	count++;
617138fd1498Szrj     }
617238fd1498Szrj   /* ( */
617338fd1498Szrj   if (*endp != ')')
617438fd1498Szrj     fatal_error (input_location, "malformed spec function arguments");
617538fd1498Szrj   args = save_string (p, endp - p);
617638fd1498Szrj   p = ++endp;
617738fd1498Szrj 
617838fd1498Szrj   /* p now points to just past the end of the spec function expression.  */
617938fd1498Szrj 
618038fd1498Szrj   funcval = eval_spec_function (func, args);
618138fd1498Szrj   if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0)
618238fd1498Szrj     p = NULL;
618338fd1498Szrj   if (retval_nonnull)
618438fd1498Szrj     *retval_nonnull = funcval != NULL;
618538fd1498Szrj 
618638fd1498Szrj   free (func);
618738fd1498Szrj   free (args);
618838fd1498Szrj 
618938fd1498Szrj   processing_spec_function--;
619038fd1498Szrj 
619138fd1498Szrj   return p;
619238fd1498Szrj }
619338fd1498Szrj 
619438fd1498Szrj /* Inline subroutine of handle_braces.  Returns true if the current
619538fd1498Szrj    input suffix matches the atom bracketed by ATOM and END_ATOM.  */
619638fd1498Szrj static inline bool
input_suffix_matches(const char * atom,const char * end_atom)619738fd1498Szrj input_suffix_matches (const char *atom, const char *end_atom)
619838fd1498Szrj {
619938fd1498Szrj   return (input_suffix
620038fd1498Szrj 	  && !strncmp (input_suffix, atom, end_atom - atom)
620138fd1498Szrj 	  && input_suffix[end_atom - atom] == '\0');
620238fd1498Szrj }
620338fd1498Szrj 
620438fd1498Szrj /* Subroutine of handle_braces.  Returns true if the current
620538fd1498Szrj    input file's spec name matches the atom bracketed by ATOM and END_ATOM.  */
620638fd1498Szrj static bool
input_spec_matches(const char * atom,const char * end_atom)620738fd1498Szrj input_spec_matches (const char *atom, const char *end_atom)
620838fd1498Szrj {
620938fd1498Szrj   return (input_file_compiler
621038fd1498Szrj 	  && input_file_compiler->suffix
621138fd1498Szrj 	  && input_file_compiler->suffix[0] != '\0'
621238fd1498Szrj 	  && !strncmp (input_file_compiler->suffix + 1, atom,
621338fd1498Szrj 		       end_atom - atom)
621438fd1498Szrj 	  && input_file_compiler->suffix[end_atom - atom + 1] == '\0');
621538fd1498Szrj }
621638fd1498Szrj 
621738fd1498Szrj /* Subroutine of handle_braces.  Returns true if a switch
621838fd1498Szrj    matching the atom bracketed by ATOM and END_ATOM appeared on the
621938fd1498Szrj    command line.  */
622038fd1498Szrj static bool
switch_matches(const char * atom,const char * end_atom,int starred)622138fd1498Szrj switch_matches (const char *atom, const char *end_atom, int starred)
622238fd1498Szrj {
622338fd1498Szrj   int i;
622438fd1498Szrj   int len = end_atom - atom;
622538fd1498Szrj   int plen = starred ? len : -1;
622638fd1498Szrj 
622738fd1498Szrj   for (i = 0; i < n_switches; i++)
622838fd1498Szrj     if (!strncmp (switches[i].part1, atom, len)
622938fd1498Szrj 	&& (starred || switches[i].part1[len] == '\0')
623038fd1498Szrj 	&& check_live_switch (i, plen))
623138fd1498Szrj       return true;
623238fd1498Szrj 
623338fd1498Szrj     /* Check if a switch with separated form matching the atom.
623438fd1498Szrj        We check -D and -U switches. */
623538fd1498Szrj     else if (switches[i].args != 0)
623638fd1498Szrj       {
623738fd1498Szrj 	if ((*switches[i].part1 == 'D' || *switches[i].part1 == 'U')
623838fd1498Szrj 	    && *switches[i].part1 == atom[0])
623938fd1498Szrj 	  {
624038fd1498Szrj 	    if (!strncmp (switches[i].args[0], &atom[1], len - 1)
624138fd1498Szrj 		&& (starred || (switches[i].part1[1] == '\0'
624238fd1498Szrj 				&& switches[i].args[0][len - 1] == '\0'))
624338fd1498Szrj 		&& check_live_switch (i, (starred ? 1 : -1)))
624438fd1498Szrj 	      return true;
624538fd1498Szrj 	  }
624638fd1498Szrj       }
624738fd1498Szrj 
624838fd1498Szrj   return false;
624938fd1498Szrj }
625038fd1498Szrj 
625138fd1498Szrj /* Inline subroutine of handle_braces.  Mark all of the switches which
625238fd1498Szrj    match ATOM (extends to END_ATOM; STARRED indicates whether there
625338fd1498Szrj    was a star after the atom) for later processing.  */
625438fd1498Szrj static inline void
mark_matching_switches(const char * atom,const char * end_atom,int starred)625538fd1498Szrj mark_matching_switches (const char *atom, const char *end_atom, int starred)
625638fd1498Szrj {
625738fd1498Szrj   int i;
625838fd1498Szrj   int len = end_atom - atom;
625938fd1498Szrj   int plen = starred ? len : -1;
626038fd1498Szrj 
626138fd1498Szrj   for (i = 0; i < n_switches; i++)
626238fd1498Szrj     if (!strncmp (switches[i].part1, atom, len)
626338fd1498Szrj 	&& (starred || switches[i].part1[len] == '\0')
626438fd1498Szrj 	&& check_live_switch (i, plen))
626538fd1498Szrj       switches[i].ordering = 1;
626638fd1498Szrj }
626738fd1498Szrj 
626838fd1498Szrj /* Inline subroutine of handle_braces.  Process all the currently
626938fd1498Szrj    marked switches through give_switch, and clear the marks.  */
627038fd1498Szrj static inline void
process_marked_switches(void)627138fd1498Szrj process_marked_switches (void)
627238fd1498Szrj {
627338fd1498Szrj   int i;
627438fd1498Szrj 
627538fd1498Szrj   for (i = 0; i < n_switches; i++)
627638fd1498Szrj     if (switches[i].ordering == 1)
627738fd1498Szrj       {
627838fd1498Szrj 	switches[i].ordering = 0;
627938fd1498Szrj 	give_switch (i, 0);
628038fd1498Szrj       }
628138fd1498Szrj }
628238fd1498Szrj 
628338fd1498Szrj /* Handle a %{ ... } construct.  P points just inside the leading {.
628438fd1498Szrj    Returns a pointer one past the end of the brace block, or 0
628538fd1498Szrj    if we call do_spec_1 and that returns -1.  */
628638fd1498Szrj 
628738fd1498Szrj static const char *
handle_braces(const char * p)628838fd1498Szrj handle_braces (const char *p)
628938fd1498Szrj {
629038fd1498Szrj   const char *atom, *end_atom;
629138fd1498Szrj   const char *d_atom = NULL, *d_end_atom = NULL;
629238fd1498Szrj   char *esc_buf = NULL, *d_esc_buf = NULL;
629338fd1498Szrj   int esc;
629438fd1498Szrj   const char *orig = p;
629538fd1498Szrj 
629638fd1498Szrj   bool a_is_suffix;
629738fd1498Szrj   bool a_is_spectype;
629838fd1498Szrj   bool a_is_starred;
629938fd1498Szrj   bool a_is_negated;
630038fd1498Szrj   bool a_matched;
630138fd1498Szrj 
630238fd1498Szrj   bool a_must_be_last = false;
630338fd1498Szrj   bool ordered_set    = false;
630438fd1498Szrj   bool disjunct_set   = false;
630538fd1498Szrj   bool disj_matched   = false;
630638fd1498Szrj   bool disj_starred   = true;
630738fd1498Szrj   bool n_way_choice   = false;
630838fd1498Szrj   bool n_way_matched  = false;
630938fd1498Szrj 
631038fd1498Szrj #define SKIP_WHITE() do { while (*p == ' ' || *p == '\t') p++; } while (0)
631138fd1498Szrj 
631238fd1498Szrj   do
631338fd1498Szrj     {
631438fd1498Szrj       if (a_must_be_last)
631538fd1498Szrj 	goto invalid;
631638fd1498Szrj 
631738fd1498Szrj       /* Scan one "atom" (S in the description above of %{}, possibly
631838fd1498Szrj 	 with '!', '.', '@', ',', or '*' modifiers).  */
631938fd1498Szrj       a_matched = false;
632038fd1498Szrj       a_is_suffix = false;
632138fd1498Szrj       a_is_starred = false;
632238fd1498Szrj       a_is_negated = false;
632338fd1498Szrj       a_is_spectype = false;
632438fd1498Szrj 
632538fd1498Szrj       SKIP_WHITE ();
632638fd1498Szrj       if (*p == '!')
632738fd1498Szrj 	p++, a_is_negated = true;
632838fd1498Szrj 
632938fd1498Szrj       SKIP_WHITE ();
633038fd1498Szrj       if (*p == '%' && p[1] == ':')
633138fd1498Szrj 	{
633238fd1498Szrj 	  atom = NULL;
633338fd1498Szrj 	  end_atom = NULL;
633438fd1498Szrj 	  p = handle_spec_function (p + 2, &a_matched);
633538fd1498Szrj 	}
633638fd1498Szrj       else
633738fd1498Szrj 	{
633838fd1498Szrj 	  if (*p == '.')
633938fd1498Szrj 	    p++, a_is_suffix = true;
634038fd1498Szrj 	  else if (*p == ',')
634138fd1498Szrj 	    p++, a_is_spectype = true;
634238fd1498Szrj 
634338fd1498Szrj 	  atom = p;
634438fd1498Szrj 	  esc = 0;
634538fd1498Szrj 	  while (ISIDNUM (*p) || *p == '-' || *p == '+' || *p == '='
634638fd1498Szrj 		 || *p == ',' || *p == '.' || *p == '@' || *p == '\\')
634738fd1498Szrj 	    {
634838fd1498Szrj 	      if (*p == '\\')
634938fd1498Szrj 		{
635038fd1498Szrj 		  p++;
635138fd1498Szrj 		  if (!*p)
635238fd1498Szrj 		    fatal_error (input_location,
635338fd1498Szrj 				 "braced spec %qs ends in escape", orig);
635438fd1498Szrj 		  esc++;
635538fd1498Szrj 		}
635638fd1498Szrj 	      p++;
635738fd1498Szrj 	    }
635838fd1498Szrj 	  end_atom = p;
635938fd1498Szrj 
636038fd1498Szrj 	  if (esc)
636138fd1498Szrj 	    {
636238fd1498Szrj 	      const char *ap;
636338fd1498Szrj 	      char *ep;
636438fd1498Szrj 
636538fd1498Szrj 	      if (esc_buf && esc_buf != d_esc_buf)
636638fd1498Szrj 		free (esc_buf);
636738fd1498Szrj 	      esc_buf = NULL;
636838fd1498Szrj 	      ep = esc_buf = (char *) xmalloc (end_atom - atom - esc + 1);
636938fd1498Szrj 	      for (ap = atom; ap != end_atom; ap++, ep++)
637038fd1498Szrj 		{
637138fd1498Szrj 		  if (*ap == '\\')
637238fd1498Szrj 		    ap++;
637338fd1498Szrj 		  *ep = *ap;
637438fd1498Szrj 		}
637538fd1498Szrj 	      *ep = '\0';
637638fd1498Szrj 	      atom = esc_buf;
637738fd1498Szrj 	      end_atom = ep;
637838fd1498Szrj 	    }
637938fd1498Szrj 
638038fd1498Szrj 	  if (*p == '*')
638138fd1498Szrj 	    p++, a_is_starred = 1;
638238fd1498Szrj 	}
638338fd1498Szrj 
638438fd1498Szrj       SKIP_WHITE ();
638538fd1498Szrj       switch (*p)
638638fd1498Szrj 	{
638738fd1498Szrj 	case '&': case '}':
638838fd1498Szrj 	  /* Substitute the switch(es) indicated by the current atom.  */
638938fd1498Szrj 	  ordered_set = true;
639038fd1498Szrj 	  if (disjunct_set || n_way_choice || a_is_negated || a_is_suffix
639138fd1498Szrj 	      || a_is_spectype || atom == end_atom)
639238fd1498Szrj 	    goto invalid;
639338fd1498Szrj 
639438fd1498Szrj 	  mark_matching_switches (atom, end_atom, a_is_starred);
639538fd1498Szrj 
639638fd1498Szrj 	  if (*p == '}')
639738fd1498Szrj 	    process_marked_switches ();
639838fd1498Szrj 	  break;
639938fd1498Szrj 
640038fd1498Szrj 	case '|': case ':':
640138fd1498Szrj 	  /* Substitute some text if the current atom appears as a switch
640238fd1498Szrj 	     or suffix.  */
640338fd1498Szrj 	  disjunct_set = true;
640438fd1498Szrj 	  if (ordered_set)
640538fd1498Szrj 	    goto invalid;
640638fd1498Szrj 
640738fd1498Szrj 	  if (atom && atom == end_atom)
640838fd1498Szrj 	    {
640938fd1498Szrj 	      if (!n_way_choice || disj_matched || *p == '|'
641038fd1498Szrj 		  || a_is_negated || a_is_suffix || a_is_spectype
641138fd1498Szrj 		  || a_is_starred)
641238fd1498Szrj 		goto invalid;
641338fd1498Szrj 
641438fd1498Szrj 	      /* An empty term may appear as the last choice of an
641538fd1498Szrj 		 N-way choice set; it means "otherwise".  */
641638fd1498Szrj 	      a_must_be_last = true;
641738fd1498Szrj 	      disj_matched = !n_way_matched;
641838fd1498Szrj 	      disj_starred = false;
641938fd1498Szrj 	    }
642038fd1498Szrj 	  else
642138fd1498Szrj 	    {
642238fd1498Szrj 	      if ((a_is_suffix || a_is_spectype) && a_is_starred)
642338fd1498Szrj 		goto invalid;
642438fd1498Szrj 
642538fd1498Szrj 	      if (!a_is_starred)
642638fd1498Szrj 		disj_starred = false;
642738fd1498Szrj 
642838fd1498Szrj 	      /* Don't bother testing this atom if we already have a
642938fd1498Szrj 		 match.  */
643038fd1498Szrj 	      if (!disj_matched && !n_way_matched)
643138fd1498Szrj 		{
643238fd1498Szrj 		  if (atom == NULL)
643338fd1498Szrj 		    /* a_matched is already set by handle_spec_function.  */;
643438fd1498Szrj 		  else if (a_is_suffix)
643538fd1498Szrj 		    a_matched = input_suffix_matches (atom, end_atom);
643638fd1498Szrj 		  else if (a_is_spectype)
643738fd1498Szrj 		    a_matched = input_spec_matches (atom, end_atom);
643838fd1498Szrj 		  else
643938fd1498Szrj 		    a_matched = switch_matches (atom, end_atom, a_is_starred);
644038fd1498Szrj 
644138fd1498Szrj 		  if (a_matched != a_is_negated)
644238fd1498Szrj 		    {
644338fd1498Szrj 		      disj_matched = true;
644438fd1498Szrj 		      d_atom = atom;
644538fd1498Szrj 		      d_end_atom = end_atom;
644638fd1498Szrj 		      d_esc_buf = esc_buf;
644738fd1498Szrj 		    }
644838fd1498Szrj 		}
644938fd1498Szrj 	    }
645038fd1498Szrj 
645138fd1498Szrj 	  if (*p == ':')
645238fd1498Szrj 	    {
645338fd1498Szrj 	      /* Found the body, that is, the text to substitute if the
645438fd1498Szrj 		 current disjunction matches.  */
645538fd1498Szrj 	      p = process_brace_body (p + 1, d_atom, d_end_atom, disj_starred,
645638fd1498Szrj 				      disj_matched && !n_way_matched);
645738fd1498Szrj 	      if (p == 0)
645838fd1498Szrj 		goto done;
645938fd1498Szrj 
646038fd1498Szrj 	      /* If we have an N-way choice, reset state for the next
646138fd1498Szrj 		 disjunction.  */
646238fd1498Szrj 	      if (*p == ';')
646338fd1498Szrj 		{
646438fd1498Szrj 		  n_way_choice = true;
646538fd1498Szrj 		  n_way_matched |= disj_matched;
646638fd1498Szrj 		  disj_matched = false;
646738fd1498Szrj 		  disj_starred = true;
646838fd1498Szrj 		  d_atom = d_end_atom = NULL;
646938fd1498Szrj 		}
647038fd1498Szrj 	    }
647138fd1498Szrj 	  break;
647238fd1498Szrj 
647338fd1498Szrj 	default:
647438fd1498Szrj 	  goto invalid;
647538fd1498Szrj 	}
647638fd1498Szrj     }
647738fd1498Szrj   while (*p++ != '}');
647838fd1498Szrj 
647938fd1498Szrj  done:
648038fd1498Szrj   if (d_esc_buf && d_esc_buf != esc_buf)
648138fd1498Szrj     free (d_esc_buf);
648238fd1498Szrj   if (esc_buf)
648338fd1498Szrj     free (esc_buf);
648438fd1498Szrj 
648538fd1498Szrj   return p;
648638fd1498Szrj 
648738fd1498Szrj  invalid:
648838fd1498Szrj   fatal_error (input_location, "braced spec %qs is invalid at %qc", orig, *p);
648938fd1498Szrj 
649038fd1498Szrj #undef SKIP_WHITE
649138fd1498Szrj }
649238fd1498Szrj 
649338fd1498Szrj /* Subroutine of handle_braces.  Scan and process a brace substitution body
649438fd1498Szrj    (X in the description of %{} syntax).  P points one past the colon;
649538fd1498Szrj    ATOM and END_ATOM bracket the first atom which was found to be true
649638fd1498Szrj    (present) in the current disjunction; STARRED indicates whether all
649738fd1498Szrj    the atoms in the current disjunction were starred (for syntax validation);
649838fd1498Szrj    MATCHED indicates whether the disjunction matched or not, and therefore
649938fd1498Szrj    whether or not the body is to be processed through do_spec_1 or just
650038fd1498Szrj    skipped.  Returns a pointer to the closing } or ;, or 0 if do_spec_1
650138fd1498Szrj    returns -1.  */
650238fd1498Szrj 
650338fd1498Szrj static const char *
process_brace_body(const char * p,const char * atom,const char * end_atom,int starred,int matched)650438fd1498Szrj process_brace_body (const char *p, const char *atom, const char *end_atom,
650538fd1498Szrj 		    int starred, int matched)
650638fd1498Szrj {
650738fd1498Szrj   const char *body, *end_body;
650838fd1498Szrj   unsigned int nesting_level;
650938fd1498Szrj   bool have_subst     = false;
651038fd1498Szrj 
651138fd1498Szrj   /* Locate the closing } or ;, honoring nested braces.
651238fd1498Szrj      Trim trailing whitespace.  */
651338fd1498Szrj   body = p;
651438fd1498Szrj   nesting_level = 1;
651538fd1498Szrj   for (;;)
651638fd1498Szrj     {
651738fd1498Szrj       if (*p == '{')
651838fd1498Szrj 	nesting_level++;
651938fd1498Szrj       else if (*p == '}')
652038fd1498Szrj 	{
652138fd1498Szrj 	  if (!--nesting_level)
652238fd1498Szrj 	    break;
652338fd1498Szrj 	}
652438fd1498Szrj       else if (*p == ';' && nesting_level == 1)
652538fd1498Szrj 	break;
652638fd1498Szrj       else if (*p == '%' && p[1] == '*' && nesting_level == 1)
652738fd1498Szrj 	have_subst = true;
652838fd1498Szrj       else if (*p == '\0')
652938fd1498Szrj 	goto invalid;
653038fd1498Szrj       p++;
653138fd1498Szrj     }
653238fd1498Szrj 
653338fd1498Szrj   end_body = p;
653438fd1498Szrj   while (end_body[-1] == ' ' || end_body[-1] == '\t')
653538fd1498Szrj     end_body--;
653638fd1498Szrj 
653738fd1498Szrj   if (have_subst && !starred)
653838fd1498Szrj     goto invalid;
653938fd1498Szrj 
654038fd1498Szrj   if (matched)
654138fd1498Szrj     {
654238fd1498Szrj       /* Copy the substitution body to permanent storage and execute it.
654338fd1498Szrj 	 If have_subst is false, this is a simple matter of running the
654438fd1498Szrj 	 body through do_spec_1...  */
654538fd1498Szrj       char *string = save_string (body, end_body - body);
654638fd1498Szrj       if (!have_subst)
654738fd1498Szrj 	{
654838fd1498Szrj 	  if (do_spec_1 (string, 0, NULL) < 0)
654938fd1498Szrj 	    {
655038fd1498Szrj 	      free (string);
655138fd1498Szrj 	      return 0;
655238fd1498Szrj 	    }
655338fd1498Szrj 	}
655438fd1498Szrj       else
655538fd1498Szrj 	{
655638fd1498Szrj 	  /* ... but if have_subst is true, we have to process the
655738fd1498Szrj 	     body once for each matching switch, with %* set to the
655838fd1498Szrj 	     variant part of the switch.  */
655938fd1498Szrj 	  unsigned int hard_match_len = end_atom - atom;
656038fd1498Szrj 	  int i;
656138fd1498Szrj 
656238fd1498Szrj 	  for (i = 0; i < n_switches; i++)
656338fd1498Szrj 	    if (!strncmp (switches[i].part1, atom, hard_match_len)
656438fd1498Szrj 		&& check_live_switch (i, hard_match_len))
656538fd1498Szrj 	      {
656638fd1498Szrj 		if (do_spec_1 (string, 0,
656738fd1498Szrj 			       &switches[i].part1[hard_match_len]) < 0)
656838fd1498Szrj 		  {
656938fd1498Szrj 		    free (string);
657038fd1498Szrj 		    return 0;
657138fd1498Szrj 		  }
657238fd1498Szrj 		/* Pass any arguments this switch has.  */
657338fd1498Szrj 		give_switch (i, 1);
657438fd1498Szrj 		suffix_subst = NULL;
657538fd1498Szrj 	      }
657638fd1498Szrj 	}
657738fd1498Szrj       free (string);
657838fd1498Szrj     }
657938fd1498Szrj 
658038fd1498Szrj   return p;
658138fd1498Szrj 
658238fd1498Szrj  invalid:
658338fd1498Szrj   fatal_error (input_location, "braced spec body %qs is invalid", body);
658438fd1498Szrj }
658538fd1498Szrj 
658638fd1498Szrj /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
658738fd1498Szrj    on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
658838fd1498Szrj    spec, or -1 if either exact match or %* is used.
658938fd1498Szrj 
659038fd1498Szrj    A -O switch is obsoleted by a later -O switch.  A -f, -g, -m, or -W switch
659138fd1498Szrj    whose value does not begin with "no-" is obsoleted by the same value
659238fd1498Szrj    with the "no-", similarly for a switch with the "no-" prefix.  */
659338fd1498Szrj 
659438fd1498Szrj static int
check_live_switch(int switchnum,int prefix_length)659538fd1498Szrj check_live_switch (int switchnum, int prefix_length)
659638fd1498Szrj {
659738fd1498Szrj   const char *name = switches[switchnum].part1;
659838fd1498Szrj   int i;
659938fd1498Szrj 
660038fd1498Szrj   /* If we already processed this switch and determined if it was
660138fd1498Szrj      live or not, return our past determination.  */
660238fd1498Szrj   if (switches[switchnum].live_cond != 0)
660338fd1498Szrj     return ((switches[switchnum].live_cond & SWITCH_LIVE) != 0
660438fd1498Szrj 	    && (switches[switchnum].live_cond & SWITCH_FALSE) == 0
660538fd1498Szrj 	    && (switches[switchnum].live_cond & SWITCH_IGNORE_PERMANENTLY)
660638fd1498Szrj 	       == 0);
660738fd1498Szrj 
660838fd1498Szrj   /* In the common case of {<at-most-one-letter>*}, a negating
660938fd1498Szrj      switch would always match, so ignore that case.  We will just
661038fd1498Szrj      send the conflicting switches to the compiler phase.  */
661138fd1498Szrj   if (prefix_length >= 0 && prefix_length <= 1)
661238fd1498Szrj     return 1;
661338fd1498Szrj 
661438fd1498Szrj   /* Now search for duplicate in a manner that depends on the name.  */
661538fd1498Szrj   switch (*name)
661638fd1498Szrj     {
661738fd1498Szrj     case 'O':
661838fd1498Szrj       for (i = switchnum + 1; i < n_switches; i++)
661938fd1498Szrj 	if (switches[i].part1[0] == 'O')
662038fd1498Szrj 	  {
662138fd1498Szrj 	    switches[switchnum].validated = true;
662238fd1498Szrj 	    switches[switchnum].live_cond = SWITCH_FALSE;
662338fd1498Szrj 	    return 0;
662438fd1498Szrj 	  }
662538fd1498Szrj       break;
662638fd1498Szrj 
662738fd1498Szrj     case 'W':  case 'f':  case 'm': case 'g':
662838fd1498Szrj       if (! strncmp (name + 1, "no-", 3))
662938fd1498Szrj 	{
663038fd1498Szrj 	  /* We have Xno-YYY, search for XYYY.  */
663138fd1498Szrj 	  for (i = switchnum + 1; i < n_switches; i++)
663238fd1498Szrj 	    if (switches[i].part1[0] == name[0]
663338fd1498Szrj 		&& ! strcmp (&switches[i].part1[1], &name[4]))
663438fd1498Szrj 	      {
663538fd1498Szrj 		/* --specs are validated with the validate_switches mechanism.  */
663638fd1498Szrj 		if (switches[switchnum].known)
663738fd1498Szrj 		  switches[switchnum].validated = true;
663838fd1498Szrj 		switches[switchnum].live_cond = SWITCH_FALSE;
663938fd1498Szrj 		return 0;
664038fd1498Szrj 	      }
664138fd1498Szrj 	}
664238fd1498Szrj       else
664338fd1498Szrj 	{
664438fd1498Szrj 	  /* We have XYYY, search for Xno-YYY.  */
664538fd1498Szrj 	  for (i = switchnum + 1; i < n_switches; i++)
664638fd1498Szrj 	    if (switches[i].part1[0] == name[0]
664738fd1498Szrj 		&& switches[i].part1[1] == 'n'
664838fd1498Szrj 		&& switches[i].part1[2] == 'o'
664938fd1498Szrj 		&& switches[i].part1[3] == '-'
665038fd1498Szrj 		&& !strcmp (&switches[i].part1[4], &name[1]))
665138fd1498Szrj 	      {
665238fd1498Szrj 		/* --specs are validated with the validate_switches mechanism.  */
665338fd1498Szrj 		if (switches[switchnum].known)
665438fd1498Szrj 		  switches[switchnum].validated = true;
665538fd1498Szrj 		switches[switchnum].live_cond = SWITCH_FALSE;
665638fd1498Szrj 		return 0;
665738fd1498Szrj 	      }
665838fd1498Szrj 	}
665938fd1498Szrj       break;
666038fd1498Szrj     }
666138fd1498Szrj 
666238fd1498Szrj   /* Otherwise the switch is live.  */
666338fd1498Szrj   switches[switchnum].live_cond |= SWITCH_LIVE;
666438fd1498Szrj   return 1;
666538fd1498Szrj }
666638fd1498Szrj 
666738fd1498Szrj /* Pass a switch to the current accumulating command
666838fd1498Szrj    in the same form that we received it.
666938fd1498Szrj    SWITCHNUM identifies the switch; it is an index into
667038fd1498Szrj    the vector of switches gcc received, which is `switches'.
667138fd1498Szrj    This cannot fail since it never finishes a command line.
667238fd1498Szrj 
667338fd1498Szrj    If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument.  */
667438fd1498Szrj 
667538fd1498Szrj static void
give_switch(int switchnum,int omit_first_word)667638fd1498Szrj give_switch (int switchnum, int omit_first_word)
667738fd1498Szrj {
667838fd1498Szrj   if ((switches[switchnum].live_cond & SWITCH_IGNORE) != 0)
667938fd1498Szrj     return;
668038fd1498Szrj 
668138fd1498Szrj   if (!omit_first_word)
668238fd1498Szrj     {
668338fd1498Szrj       do_spec_1 ("-", 0, NULL);
668438fd1498Szrj       do_spec_1 (switches[switchnum].part1, 1, NULL);
668538fd1498Szrj     }
668638fd1498Szrj 
668738fd1498Szrj   if (switches[switchnum].args != 0)
668838fd1498Szrj     {
668938fd1498Szrj       const char **p;
669038fd1498Szrj       for (p = switches[switchnum].args; *p; p++)
669138fd1498Szrj 	{
669238fd1498Szrj 	  const char *arg = *p;
669338fd1498Szrj 
669438fd1498Szrj 	  do_spec_1 (" ", 0, NULL);
669538fd1498Szrj 	  if (suffix_subst)
669638fd1498Szrj 	    {
669738fd1498Szrj 	      unsigned length = strlen (arg);
669838fd1498Szrj 	      int dot = 0;
669938fd1498Szrj 
670038fd1498Szrj 	      while (length-- && !IS_DIR_SEPARATOR (arg[length]))
670138fd1498Szrj 		if (arg[length] == '.')
670238fd1498Szrj 		  {
670338fd1498Szrj 		    (CONST_CAST (char *, arg))[length] = 0;
670438fd1498Szrj 		    dot = 1;
670538fd1498Szrj 		    break;
670638fd1498Szrj 		  }
670738fd1498Szrj 	      do_spec_1 (arg, 1, NULL);
670838fd1498Szrj 	      if (dot)
670938fd1498Szrj 		(CONST_CAST (char *, arg))[length] = '.';
671038fd1498Szrj 	      do_spec_1 (suffix_subst, 1, NULL);
671138fd1498Szrj 	    }
671238fd1498Szrj 	  else
671338fd1498Szrj 	    do_spec_1 (arg, 1, NULL);
671438fd1498Szrj 	}
671538fd1498Szrj     }
671638fd1498Szrj 
671738fd1498Szrj   do_spec_1 (" ", 0, NULL);
671838fd1498Szrj   switches[switchnum].validated = true;
671938fd1498Szrj }
672038fd1498Szrj 
672138fd1498Szrj /* Print GCC configuration (e.g. version, thread model, target,
672238fd1498Szrj    configuration_arguments) to a given FILE.  */
672338fd1498Szrj 
672438fd1498Szrj static void
print_configuration(FILE * file)672538fd1498Szrj print_configuration (FILE *file)
672638fd1498Szrj {
672738fd1498Szrj   int n;
672838fd1498Szrj   const char *thrmod;
672938fd1498Szrj 
673038fd1498Szrj   fnotice (file, "Target: %s\n", spec_machine);
673138fd1498Szrj   fnotice (file, "Configured with: %s\n", configuration_arguments);
673238fd1498Szrj 
673338fd1498Szrj #ifdef THREAD_MODEL_SPEC
673438fd1498Szrj   /* We could have defined THREAD_MODEL_SPEC to "%*" by default,
673538fd1498Szrj   but there's no point in doing all this processing just to get
673638fd1498Szrj   thread_model back.  */
673738fd1498Szrj   obstack_init (&obstack);
673838fd1498Szrj   do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model);
673938fd1498Szrj   obstack_1grow (&obstack, '\0');
674038fd1498Szrj   thrmod = XOBFINISH (&obstack, const char *);
674138fd1498Szrj #else
674238fd1498Szrj   thrmod = thread_model;
674338fd1498Szrj #endif
674438fd1498Szrj 
674538fd1498Szrj   fnotice (file, "Thread model: %s\n", thrmod);
674638fd1498Szrj 
674738fd1498Szrj   /* compiler_version is truncated at the first space when initialized
674838fd1498Szrj   from version string, so truncate version_string at the first space
674938fd1498Szrj   before comparing.  */
675038fd1498Szrj   for (n = 0; version_string[n]; n++)
675138fd1498Szrj     if (version_string[n] == ' ')
675238fd1498Szrj       break;
675338fd1498Szrj 
675438fd1498Szrj   if (! strncmp (version_string, compiler_version, n)
675538fd1498Szrj       && compiler_version[n] == 0)
675638fd1498Szrj     fnotice (file, "gcc version %s %s\n", version_string,
675738fd1498Szrj 	     pkgversion_string);
675838fd1498Szrj   else
675938fd1498Szrj     fnotice (file, "gcc driver version %s %sexecuting gcc version %s\n",
676038fd1498Szrj 	     version_string, pkgversion_string, compiler_version);
676138fd1498Szrj 
676238fd1498Szrj }
676338fd1498Szrj 
676438fd1498Szrj #define RETRY_ICE_ATTEMPTS 3
676538fd1498Szrj 
676638fd1498Szrj /* Returns true if FILE1 and FILE2 contain equivalent data, 0 otherwise.  */
676738fd1498Szrj 
676838fd1498Szrj static bool
files_equal_p(char * file1,char * file2)676938fd1498Szrj files_equal_p (char *file1, char *file2)
677038fd1498Szrj {
677138fd1498Szrj   struct stat st1, st2;
677238fd1498Szrj   off_t n, len;
677338fd1498Szrj   int fd1, fd2;
677438fd1498Szrj   const int bufsize = 8192;
677538fd1498Szrj   char *buf = XNEWVEC (char, bufsize);
677638fd1498Szrj 
677738fd1498Szrj   fd1 = open (file1, O_RDONLY);
677838fd1498Szrj   fd2 = open (file2, O_RDONLY);
677938fd1498Szrj 
678038fd1498Szrj   if (fd1 < 0 || fd2 < 0)
678138fd1498Szrj     goto error;
678238fd1498Szrj 
678338fd1498Szrj   if (fstat (fd1, &st1) < 0 || fstat (fd2, &st2) < 0)
678438fd1498Szrj     goto error;
678538fd1498Szrj 
678638fd1498Szrj   if (st1.st_size != st2.st_size)
678738fd1498Szrj     goto error;
678838fd1498Szrj 
678938fd1498Szrj   for (n = st1.st_size; n; n -= len)
679038fd1498Szrj     {
679138fd1498Szrj       len = n;
679238fd1498Szrj       if ((int) len > bufsize / 2)
679338fd1498Szrj 	len = bufsize / 2;
679438fd1498Szrj 
679538fd1498Szrj       if (read (fd1, buf, len) != (int) len
679638fd1498Szrj 	  || read (fd2, buf + bufsize / 2, len) != (int) len)
679738fd1498Szrj 	{
679838fd1498Szrj 	  goto error;
679938fd1498Szrj 	}
680038fd1498Szrj 
680138fd1498Szrj       if (memcmp (buf, buf + bufsize / 2, len) != 0)
680238fd1498Szrj 	goto error;
680338fd1498Szrj     }
680438fd1498Szrj 
680538fd1498Szrj   free (buf);
680638fd1498Szrj   close (fd1);
680738fd1498Szrj   close (fd2);
680838fd1498Szrj 
680938fd1498Szrj   return 1;
681038fd1498Szrj 
681138fd1498Szrj error:
681238fd1498Szrj   free (buf);
681338fd1498Szrj   close (fd1);
681438fd1498Szrj   close (fd2);
681538fd1498Szrj   return 0;
681638fd1498Szrj }
681738fd1498Szrj 
681838fd1498Szrj /* Check that compiler's output doesn't differ across runs.
681938fd1498Szrj    TEMP_STDOUT_FILES and TEMP_STDERR_FILES are arrays of files, containing
682038fd1498Szrj    stdout and stderr for each compiler run.  Return true if all of
682138fd1498Szrj    TEMP_STDOUT_FILES and TEMP_STDERR_FILES are equivalent.  */
682238fd1498Szrj 
682338fd1498Szrj static bool
check_repro(char ** temp_stdout_files,char ** temp_stderr_files)682438fd1498Szrj check_repro (char **temp_stdout_files, char **temp_stderr_files)
682538fd1498Szrj {
682638fd1498Szrj   int i;
682738fd1498Szrj   for (i = 0; i < RETRY_ICE_ATTEMPTS - 2; ++i)
682838fd1498Szrj     {
682938fd1498Szrj      if (!files_equal_p (temp_stdout_files[i], temp_stdout_files[i + 1])
683038fd1498Szrj 	 || !files_equal_p (temp_stderr_files[i], temp_stderr_files[i + 1]))
683138fd1498Szrj        {
683238fd1498Szrj 	 fnotice (stderr, "The bug is not reproducible, so it is"
683338fd1498Szrj 		  " likely a hardware or OS problem.\n");
683438fd1498Szrj 	 break;
683538fd1498Szrj        }
683638fd1498Szrj     }
683738fd1498Szrj   return i == RETRY_ICE_ATTEMPTS - 2;
683838fd1498Szrj }
683938fd1498Szrj 
684038fd1498Szrj enum attempt_status {
684138fd1498Szrj   ATTEMPT_STATUS_FAIL_TO_RUN,
684238fd1498Szrj   ATTEMPT_STATUS_SUCCESS,
684338fd1498Szrj   ATTEMPT_STATUS_ICE
684438fd1498Szrj };
684538fd1498Szrj 
684638fd1498Szrj 
684738fd1498Szrj /* Run compiler with arguments NEW_ARGV to reproduce the ICE, storing stdout
684838fd1498Szrj    to OUT_TEMP and stderr to ERR_TEMP.  If APPEND is TRUE, append to OUT_TEMP
684938fd1498Szrj    and ERR_TEMP instead of truncating.  If EMIT_SYSTEM_INFO is TRUE, also write
685038fd1498Szrj    GCC configuration into to ERR_TEMP.  Return ATTEMPT_STATUS_FAIL_TO_RUN if
685138fd1498Szrj    compiler failed to run, ATTEMPT_STATUS_ICE if compiled ICE-ed and
685238fd1498Szrj    ATTEMPT_STATUS_SUCCESS otherwise.  */
685338fd1498Szrj 
685438fd1498Szrj static enum attempt_status
run_attempt(const char ** new_argv,const char * out_temp,const char * err_temp,int emit_system_info,int append)685538fd1498Szrj run_attempt (const char **new_argv, const char *out_temp,
685638fd1498Szrj 	     const char *err_temp, int emit_system_info, int append)
685738fd1498Szrj {
685838fd1498Szrj 
685938fd1498Szrj   if (emit_system_info)
686038fd1498Szrj     {
686138fd1498Szrj       FILE *file_out = fopen (err_temp, "a");
686238fd1498Szrj       print_configuration (file_out);
686338fd1498Szrj       fputs ("\n", file_out);
686438fd1498Szrj       fclose (file_out);
686538fd1498Szrj     }
686638fd1498Szrj 
686738fd1498Szrj   int exit_status;
686838fd1498Szrj   const char *errmsg;
686938fd1498Szrj   struct pex_obj *pex;
687038fd1498Szrj   int err;
687138fd1498Szrj   int pex_flags = PEX_USE_PIPES | PEX_LAST;
687238fd1498Szrj   enum attempt_status status = ATTEMPT_STATUS_FAIL_TO_RUN;
687338fd1498Szrj 
687438fd1498Szrj   if (append)
687538fd1498Szrj     pex_flags |= PEX_STDOUT_APPEND | PEX_STDERR_APPEND;
687638fd1498Szrj 
687738fd1498Szrj   pex = pex_init (PEX_USE_PIPES, new_argv[0], NULL);
687838fd1498Szrj   if (!pex)
687938fd1498Szrj     fatal_error (input_location, "pex_init failed: %m");
688038fd1498Szrj 
688138fd1498Szrj   errmsg = pex_run (pex, pex_flags, new_argv[0],
688238fd1498Szrj 		    CONST_CAST2 (char *const *, const char **, &new_argv[1]), out_temp,
688338fd1498Szrj 		    err_temp, &err);
688438fd1498Szrj   if (errmsg != NULL)
688538fd1498Szrj     {
688638fd1498Szrj       if (err == 0)
688738fd1498Szrj 	fatal_error (input_location, errmsg);
688838fd1498Szrj       else
688938fd1498Szrj 	{
689038fd1498Szrj 	  errno = err;
689138fd1498Szrj 	  pfatal_with_name (errmsg);
689238fd1498Szrj 	}
689338fd1498Szrj     }
689438fd1498Szrj 
689538fd1498Szrj   if (!pex_get_status (pex, 1, &exit_status))
689638fd1498Szrj     goto out;
689738fd1498Szrj 
689838fd1498Szrj   switch (WEXITSTATUS (exit_status))
689938fd1498Szrj     {
690038fd1498Szrj       case ICE_EXIT_CODE:
690138fd1498Szrj 	status = ATTEMPT_STATUS_ICE;
690238fd1498Szrj 	break;
690338fd1498Szrj 
690438fd1498Szrj       case SUCCESS_EXIT_CODE:
690538fd1498Szrj 	status = ATTEMPT_STATUS_SUCCESS;
690638fd1498Szrj 	break;
690738fd1498Szrj 
690838fd1498Szrj       default:
690938fd1498Szrj 	;
691038fd1498Szrj     }
691138fd1498Szrj 
691238fd1498Szrj out:
691338fd1498Szrj   pex_free (pex);
691438fd1498Szrj   return status;
691538fd1498Szrj }
691638fd1498Szrj 
691738fd1498Szrj /* This routine reads lines from IN file, adds C++ style comments
691838fd1498Szrj    at the begining of each line and writes result into OUT.  */
691938fd1498Szrj 
692038fd1498Szrj static void
insert_comments(const char * file_in,const char * file_out)692138fd1498Szrj insert_comments (const char *file_in, const char *file_out)
692238fd1498Szrj {
692338fd1498Szrj   FILE *in = fopen (file_in, "rb");
692438fd1498Szrj   FILE *out = fopen (file_out, "wb");
692538fd1498Szrj   char line[256];
692638fd1498Szrj 
692738fd1498Szrj   bool add_comment = true;
692838fd1498Szrj   while (fgets (line, sizeof (line), in))
692938fd1498Szrj     {
693038fd1498Szrj       if (add_comment)
693138fd1498Szrj 	fputs ("// ", out);
693238fd1498Szrj       fputs (line, out);
693338fd1498Szrj       add_comment = strchr (line, '\n') != NULL;
693438fd1498Szrj     }
693538fd1498Szrj 
693638fd1498Szrj   fclose (in);
693738fd1498Szrj   fclose (out);
693838fd1498Szrj }
693938fd1498Szrj 
694038fd1498Szrj /* This routine adds preprocessed source code into the given ERR_FILE.
694138fd1498Szrj    To do this, it adds "-E" to NEW_ARGV and execute RUN_ATTEMPT routine to
694238fd1498Szrj    add information in report file.  RUN_ATTEMPT should return
694338fd1498Szrj    ATTEMPT_STATUS_SUCCESS, in other case we cannot generate the report.  */
694438fd1498Szrj 
694538fd1498Szrj static void
do_report_bug(const char ** new_argv,const int nargs,char ** out_file,char ** err_file)694638fd1498Szrj do_report_bug (const char **new_argv, const int nargs,
694738fd1498Szrj 	       char **out_file, char **err_file)
694838fd1498Szrj {
694938fd1498Szrj   int i, status;
695038fd1498Szrj   int fd = open (*out_file, O_RDWR | O_APPEND);
695138fd1498Szrj   if (fd < 0)
695238fd1498Szrj     return;
695338fd1498Szrj   write (fd, "\n//", 3);
695438fd1498Szrj   for (i = 0; i < nargs; i++)
695538fd1498Szrj     {
695638fd1498Szrj       write (fd, " ", 1);
695738fd1498Szrj       write (fd, new_argv[i], strlen (new_argv[i]));
695838fd1498Szrj     }
695938fd1498Szrj   write (fd, "\n\n", 2);
696038fd1498Szrj   close (fd);
696138fd1498Szrj   new_argv[nargs] = "-E";
696238fd1498Szrj   new_argv[nargs + 1] = NULL;
696338fd1498Szrj 
696438fd1498Szrj   status = run_attempt (new_argv, *out_file, *err_file, 0, 1);
696538fd1498Szrj 
696638fd1498Szrj   if (status == ATTEMPT_STATUS_SUCCESS)
696738fd1498Szrj     {
696838fd1498Szrj       fnotice (stderr, "Preprocessed source stored into %s file,"
696938fd1498Szrj 	       " please attach this to your bugreport.\n", *out_file);
697038fd1498Szrj       /* Make sure it is not deleted.  */
697138fd1498Szrj       free (*out_file);
697238fd1498Szrj       *out_file = NULL;
697338fd1498Szrj     }
697438fd1498Szrj }
697538fd1498Szrj 
697638fd1498Szrj /* Try to reproduce ICE.  If bug is reproducible, generate report .err file
697738fd1498Szrj    containing GCC configuration, backtrace, compiler's command line options
697838fd1498Szrj    and preprocessed source code.  */
697938fd1498Szrj 
698038fd1498Szrj static void
try_generate_repro(const char ** argv)698138fd1498Szrj try_generate_repro (const char **argv)
698238fd1498Szrj {
698338fd1498Szrj   int i, nargs, out_arg = -1, quiet = 0, attempt;
698438fd1498Szrj   const char **new_argv;
698538fd1498Szrj   char *temp_files[RETRY_ICE_ATTEMPTS * 2];
698638fd1498Szrj   char **temp_stdout_files = &temp_files[0];
698738fd1498Szrj   char **temp_stderr_files = &temp_files[RETRY_ICE_ATTEMPTS];
698838fd1498Szrj 
698938fd1498Szrj   if (gcc_input_filename == NULL || ! strcmp (gcc_input_filename, "-"))
699038fd1498Szrj     return;
699138fd1498Szrj 
699238fd1498Szrj   for (nargs = 0; argv[nargs] != NULL; ++nargs)
699338fd1498Szrj     /* Only retry compiler ICEs, not preprocessor ones.  */
699438fd1498Szrj     if (! strcmp (argv[nargs], "-E"))
699538fd1498Szrj       return;
699638fd1498Szrj     else if (argv[nargs][0] == '-' && argv[nargs][1] == 'o')
699738fd1498Szrj       {
699838fd1498Szrj 	if (out_arg == -1)
699938fd1498Szrj 	  out_arg = nargs;
700038fd1498Szrj 	else
700138fd1498Szrj 	  return;
700238fd1498Szrj       }
700338fd1498Szrj     /* If the compiler is going to output any time information,
700438fd1498Szrj        it might varry between invocations.  */
700538fd1498Szrj     else if (! strcmp (argv[nargs], "-quiet"))
700638fd1498Szrj       quiet = 1;
700738fd1498Szrj     else if (! strcmp (argv[nargs], "-ftime-report"))
700838fd1498Szrj       return;
700938fd1498Szrj 
701038fd1498Szrj   if (out_arg == -1 || !quiet)
701138fd1498Szrj     return;
701238fd1498Szrj 
701338fd1498Szrj   memset (temp_files, '\0', sizeof (temp_files));
701438fd1498Szrj   new_argv = XALLOCAVEC (const char *, nargs + 4);
701538fd1498Szrj   memcpy (new_argv, argv, (nargs + 1) * sizeof (const char *));
701638fd1498Szrj   new_argv[nargs++] = "-frandom-seed=0";
701738fd1498Szrj   new_argv[nargs++] = "-fdump-noaddr";
701838fd1498Szrj   new_argv[nargs] = NULL;
701938fd1498Szrj   if (new_argv[out_arg][2] == '\0')
702038fd1498Szrj     new_argv[out_arg + 1] = "-";
702138fd1498Szrj   else
702238fd1498Szrj     new_argv[out_arg] = "-o-";
702338fd1498Szrj 
702438fd1498Szrj   int status;
702538fd1498Szrj   for (attempt = 0; attempt < RETRY_ICE_ATTEMPTS; ++attempt)
702638fd1498Szrj     {
702738fd1498Szrj       int emit_system_info = 0;
702838fd1498Szrj       int append = 0;
702938fd1498Szrj       temp_stdout_files[attempt] = make_temp_file (".out");
703038fd1498Szrj       temp_stderr_files[attempt] = make_temp_file (".err");
703138fd1498Szrj 
703238fd1498Szrj       if (attempt == RETRY_ICE_ATTEMPTS - 1)
703338fd1498Szrj 	{
703438fd1498Szrj 	  append = 1;
703538fd1498Szrj 	  emit_system_info = 1;
703638fd1498Szrj 	}
703738fd1498Szrj 
703838fd1498Szrj       status = run_attempt (new_argv, temp_stdout_files[attempt],
703938fd1498Szrj 			    temp_stderr_files[attempt], emit_system_info,
704038fd1498Szrj 			    append);
704138fd1498Szrj 
704238fd1498Szrj       if (status != ATTEMPT_STATUS_ICE)
704338fd1498Szrj 	{
704438fd1498Szrj 	  fnotice (stderr, "The bug is not reproducible, so it is"
704538fd1498Szrj 		   " likely a hardware or OS problem.\n");
704638fd1498Szrj 	  goto out;
704738fd1498Szrj 	}
704838fd1498Szrj     }
704938fd1498Szrj 
705038fd1498Szrj   if (!check_repro (temp_stdout_files, temp_stderr_files))
705138fd1498Szrj     goto out;
705238fd1498Szrj 
705338fd1498Szrj   {
705438fd1498Szrj     /* Insert commented out backtrace into report file.  */
705538fd1498Szrj     char **stderr_commented = &temp_stdout_files[RETRY_ICE_ATTEMPTS - 1];
705638fd1498Szrj     insert_comments (temp_stderr_files[RETRY_ICE_ATTEMPTS - 1],
705738fd1498Szrj 		     *stderr_commented);
705838fd1498Szrj 
705938fd1498Szrj     /* In final attempt we append compiler options and preprocesssed code to last
706038fd1498Szrj        generated .out file with configuration and backtrace.  */
706138fd1498Szrj     char **err = &temp_stderr_files[RETRY_ICE_ATTEMPTS - 1];
706238fd1498Szrj     do_report_bug (new_argv, nargs, stderr_commented, err);
706338fd1498Szrj   }
706438fd1498Szrj 
706538fd1498Szrj out:
706638fd1498Szrj   for (i = 0; i < RETRY_ICE_ATTEMPTS * 2; i++)
706738fd1498Szrj     if (temp_files[i])
706838fd1498Szrj       {
706938fd1498Szrj 	unlink (temp_stdout_files[i]);
707038fd1498Szrj 	free (temp_stdout_files[i]);
707138fd1498Szrj       }
707238fd1498Szrj }
707338fd1498Szrj 
707438fd1498Szrj /* Search for a file named NAME trying various prefixes including the
707538fd1498Szrj    user's -B prefix and some standard ones.
707638fd1498Szrj    Return the absolute file name found.  If nothing is found, return NAME.  */
707738fd1498Szrj 
707838fd1498Szrj static const char *
find_file(const char * name)707938fd1498Szrj find_file (const char *name)
708038fd1498Szrj {
708138fd1498Szrj   char *newname = find_a_file (&startfile_prefixes, name, R_OK, true);
708238fd1498Szrj   return newname ? newname : name;
708338fd1498Szrj }
708438fd1498Szrj 
708538fd1498Szrj /* Determine whether a directory exists.  If LINKER, return 0 for
708638fd1498Szrj    certain fixed names not needed by the linker.  */
708738fd1498Szrj 
708838fd1498Szrj static int
is_directory(const char * path1,bool linker)708938fd1498Szrj is_directory (const char *path1, bool linker)
709038fd1498Szrj {
709138fd1498Szrj   int len1;
709238fd1498Szrj   char *path;
709338fd1498Szrj   char *cp;
709438fd1498Szrj   struct stat st;
709538fd1498Szrj 
709638fd1498Szrj   /* Ensure the string ends with "/.".  The resulting path will be a
709738fd1498Szrj      directory even if the given path is a symbolic link.  */
709838fd1498Szrj   len1 = strlen (path1);
709938fd1498Szrj   path = (char *) alloca (3 + len1);
710038fd1498Szrj   memcpy (path, path1, len1);
710138fd1498Szrj   cp = path + len1;
710238fd1498Szrj   if (!IS_DIR_SEPARATOR (cp[-1]))
710338fd1498Szrj     *cp++ = DIR_SEPARATOR;
710438fd1498Szrj   *cp++ = '.';
710538fd1498Szrj   *cp = '\0';
710638fd1498Szrj 
710738fd1498Szrj   /* Exclude directories that the linker is known to search.  */
710838fd1498Szrj   if (linker
710938fd1498Szrj       && IS_DIR_SEPARATOR (path[0])
711038fd1498Szrj       && ((cp - path == 6
711138fd1498Szrj 	   && filename_ncmp (path + 1, "lib", 3) == 0)
711238fd1498Szrj 	  || (cp - path == 10
711338fd1498Szrj 	      && filename_ncmp (path + 1, "usr", 3) == 0
711438fd1498Szrj 	      && IS_DIR_SEPARATOR (path[4])
711538fd1498Szrj 	      && filename_ncmp (path + 5, "lib", 3) == 0)))
711638fd1498Szrj     return 0;
711738fd1498Szrj 
711838fd1498Szrj   return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
711938fd1498Szrj }
712038fd1498Szrj 
712138fd1498Szrj /* Set up the various global variables to indicate that we're processing
712238fd1498Szrj    the input file named FILENAME.  */
712338fd1498Szrj 
712438fd1498Szrj void
set_input(const char * filename)712538fd1498Szrj set_input (const char *filename)
712638fd1498Szrj {
712738fd1498Szrj   const char *p;
712838fd1498Szrj 
712938fd1498Szrj   gcc_input_filename = filename;
713038fd1498Szrj   input_filename_length = strlen (gcc_input_filename);
713138fd1498Szrj   input_basename = lbasename (gcc_input_filename);
713238fd1498Szrj 
713338fd1498Szrj   /* Find a suffix starting with the last period,
713438fd1498Szrj      and set basename_length to exclude that suffix.  */
713538fd1498Szrj   basename_length = strlen (input_basename);
713638fd1498Szrj   suffixed_basename_length = basename_length;
713738fd1498Szrj   p = input_basename + basename_length;
713838fd1498Szrj   while (p != input_basename && *p != '.')
713938fd1498Szrj     --p;
714038fd1498Szrj   if (*p == '.' && p != input_basename)
714138fd1498Szrj     {
714238fd1498Szrj       basename_length = p - input_basename;
714338fd1498Szrj       input_suffix = p + 1;
714438fd1498Szrj     }
714538fd1498Szrj   else
714638fd1498Szrj     input_suffix = "";
714738fd1498Szrj 
714838fd1498Szrj   /* If a spec for 'g', 'u', or 'U' is seen with -save-temps then
714938fd1498Szrj      we will need to do a stat on the gcc_input_filename.  The
715038fd1498Szrj      INPUT_STAT_SET signals that the stat is needed.  */
715138fd1498Szrj   input_stat_set = 0;
715238fd1498Szrj }
715338fd1498Szrj 
715438fd1498Szrj /* On fatal signals, delete all the temporary files.  */
715538fd1498Szrj 
715638fd1498Szrj static void
fatal_signal(int signum)715738fd1498Szrj fatal_signal (int signum)
715838fd1498Szrj {
715938fd1498Szrj   signal (signum, SIG_DFL);
716038fd1498Szrj   delete_failure_queue ();
716138fd1498Szrj   delete_temp_files ();
716238fd1498Szrj   /* Get the same signal again, this time not handled,
716338fd1498Szrj      so its normal effect occurs.  */
716438fd1498Szrj   kill (getpid (), signum);
716538fd1498Szrj }
716638fd1498Szrj 
716738fd1498Szrj /* Compare the contents of the two files named CMPFILE[0] and
716838fd1498Szrj    CMPFILE[1].  Return zero if they're identical, nonzero
716938fd1498Szrj    otherwise.  */
717038fd1498Szrj 
717138fd1498Szrj static int
compare_files(char * cmpfile[])717238fd1498Szrj compare_files (char *cmpfile[])
717338fd1498Szrj {
717438fd1498Szrj   int ret = 0;
717538fd1498Szrj   FILE *temp[2] = { NULL, NULL };
717638fd1498Szrj   int i;
717738fd1498Szrj 
717838fd1498Szrj #if HAVE_MMAP_FILE
717938fd1498Szrj   {
718038fd1498Szrj     size_t length[2];
718138fd1498Szrj     void *map[2] = { NULL, NULL };
718238fd1498Szrj 
718338fd1498Szrj     for (i = 0; i < 2; i++)
718438fd1498Szrj       {
718538fd1498Szrj 	struct stat st;
718638fd1498Szrj 
718738fd1498Szrj 	if (stat (cmpfile[i], &st) < 0 || !S_ISREG (st.st_mode))
718838fd1498Szrj 	  {
718938fd1498Szrj 	    error ("%s: could not determine length of compare-debug file %s",
719038fd1498Szrj 		   gcc_input_filename, cmpfile[i]);
719138fd1498Szrj 	    ret = 1;
719238fd1498Szrj 	    break;
719338fd1498Szrj 	  }
719438fd1498Szrj 
719538fd1498Szrj 	length[i] = st.st_size;
719638fd1498Szrj       }
719738fd1498Szrj 
719838fd1498Szrj     if (!ret && length[0] != length[1])
719938fd1498Szrj       {
720038fd1498Szrj 	error ("%s: -fcompare-debug failure (length)", gcc_input_filename);
720138fd1498Szrj 	ret = 1;
720238fd1498Szrj       }
720338fd1498Szrj 
720438fd1498Szrj     if (!ret)
720538fd1498Szrj       for (i = 0; i < 2; i++)
720638fd1498Szrj 	{
720738fd1498Szrj 	  int fd = open (cmpfile[i], O_RDONLY);
720838fd1498Szrj 	  if (fd < 0)
720938fd1498Szrj 	    {
721038fd1498Szrj 	      error ("%s: could not open compare-debug file %s",
721138fd1498Szrj 		     gcc_input_filename, cmpfile[i]);
721238fd1498Szrj 	      ret = 1;
721338fd1498Szrj 	      break;
721438fd1498Szrj 	    }
721538fd1498Szrj 
721638fd1498Szrj 	  map[i] = mmap (NULL, length[i], PROT_READ, MAP_PRIVATE, fd, 0);
721738fd1498Szrj 	  close (fd);
721838fd1498Szrj 
721938fd1498Szrj 	  if (map[i] == (void *) MAP_FAILED)
722038fd1498Szrj 	    {
722138fd1498Szrj 	      ret = -1;
722238fd1498Szrj 	      break;
722338fd1498Szrj 	    }
722438fd1498Szrj 	}
722538fd1498Szrj 
722638fd1498Szrj     if (!ret)
722738fd1498Szrj       {
722838fd1498Szrj 	if (memcmp (map[0], map[1], length[0]) != 0)
722938fd1498Szrj 	  {
723038fd1498Szrj 	    error ("%s: -fcompare-debug failure", gcc_input_filename);
723138fd1498Szrj 	    ret = 1;
723238fd1498Szrj 	  }
723338fd1498Szrj       }
723438fd1498Szrj 
723538fd1498Szrj     for (i = 0; i < 2; i++)
723638fd1498Szrj       if (map[i])
723738fd1498Szrj 	munmap ((caddr_t) map[i], length[i]);
723838fd1498Szrj 
723938fd1498Szrj     if (ret >= 0)
724038fd1498Szrj       return ret;
724138fd1498Szrj 
724238fd1498Szrj     ret = 0;
724338fd1498Szrj   }
724438fd1498Szrj #endif
724538fd1498Szrj 
724638fd1498Szrj   for (i = 0; i < 2; i++)
724738fd1498Szrj     {
724838fd1498Szrj       temp[i] = fopen (cmpfile[i], "r");
724938fd1498Szrj       if (!temp[i])
725038fd1498Szrj 	{
725138fd1498Szrj 	  error ("%s: could not open compare-debug file %s",
725238fd1498Szrj 		 gcc_input_filename, cmpfile[i]);
725338fd1498Szrj 	  ret = 1;
725438fd1498Szrj 	  break;
725538fd1498Szrj 	}
725638fd1498Szrj     }
725738fd1498Szrj 
725838fd1498Szrj   if (!ret && temp[0] && temp[1])
725938fd1498Szrj     for (;;)
726038fd1498Szrj       {
726138fd1498Szrj 	int c0, c1;
726238fd1498Szrj 	c0 = fgetc (temp[0]);
726338fd1498Szrj 	c1 = fgetc (temp[1]);
726438fd1498Szrj 
726538fd1498Szrj 	if (c0 != c1)
726638fd1498Szrj 	  {
726738fd1498Szrj 	    error ("%s: -fcompare-debug failure",
726838fd1498Szrj 		   gcc_input_filename);
726938fd1498Szrj 	    ret = 1;
727038fd1498Szrj 	    break;
727138fd1498Szrj 	  }
727238fd1498Szrj 
727338fd1498Szrj 	if (c0 == EOF)
727438fd1498Szrj 	  break;
727538fd1498Szrj       }
727638fd1498Szrj 
727738fd1498Szrj   for (i = 1; i >= 0; i--)
727838fd1498Szrj     {
727938fd1498Szrj       if (temp[i])
728038fd1498Szrj 	fclose (temp[i]);
728138fd1498Szrj     }
728238fd1498Szrj 
728338fd1498Szrj   return ret;
728438fd1498Szrj }
728538fd1498Szrj 
driver(bool can_finalize,bool debug)728638fd1498Szrj driver::driver (bool can_finalize, bool debug) :
728738fd1498Szrj   explicit_link_files (NULL),
728838fd1498Szrj   decoded_options (NULL),
728938fd1498Szrj   m_option_suggestions (NULL)
729038fd1498Szrj {
729138fd1498Szrj   env.init (can_finalize, debug);
729238fd1498Szrj }
729338fd1498Szrj 
~driver()729438fd1498Szrj driver::~driver ()
729538fd1498Szrj {
729638fd1498Szrj   XDELETEVEC (explicit_link_files);
729738fd1498Szrj   XDELETEVEC (decoded_options);
729838fd1498Szrj   if (m_option_suggestions)
729938fd1498Szrj     {
730038fd1498Szrj       int i;
730138fd1498Szrj       char *str;
730238fd1498Szrj       FOR_EACH_VEC_ELT (*m_option_suggestions, i, str)
730338fd1498Szrj 	free (str);
730438fd1498Szrj       delete m_option_suggestions;
730538fd1498Szrj     }
730638fd1498Szrj }
730738fd1498Szrj 
730838fd1498Szrj /* driver::main is implemented as a series of driver:: method calls.  */
730938fd1498Szrj 
731038fd1498Szrj int
main(int argc,char ** argv)731138fd1498Szrj driver::main (int argc, char **argv)
731238fd1498Szrj {
731338fd1498Szrj   bool early_exit;
731438fd1498Szrj 
731538fd1498Szrj   set_progname (argv[0]);
731638fd1498Szrj   expand_at_files (&argc, &argv);
731738fd1498Szrj   decode_argv (argc, const_cast <const char **> (argv));
731838fd1498Szrj   global_initializations ();
731938fd1498Szrj   build_multilib_strings ();
732038fd1498Szrj   set_up_specs ();
732138fd1498Szrj   putenv_COLLECT_GCC (argv[0]);
732238fd1498Szrj   maybe_putenv_COLLECT_LTO_WRAPPER ();
732338fd1498Szrj   maybe_putenv_OFFLOAD_TARGETS ();
732438fd1498Szrj   handle_unrecognized_options ();
732538fd1498Szrj 
732638fd1498Szrj   if (!maybe_print_and_exit ())
732738fd1498Szrj     return 0;
732838fd1498Szrj 
732938fd1498Szrj   early_exit = prepare_infiles ();
733038fd1498Szrj   if (early_exit)
733138fd1498Szrj     return get_exit_code ();
733238fd1498Szrj 
733338fd1498Szrj   do_spec_on_infiles ();
733438fd1498Szrj   maybe_run_linker (argv[0]);
733538fd1498Szrj   final_actions ();
733638fd1498Szrj   return get_exit_code ();
733738fd1498Szrj }
733838fd1498Szrj 
733938fd1498Szrj /* Locate the final component of argv[0] after any leading path, and set
734038fd1498Szrj    the program name accordingly.  */
734138fd1498Szrj 
734238fd1498Szrj void
set_progname(const char * argv0)734338fd1498Szrj driver::set_progname (const char *argv0) const
734438fd1498Szrj {
734538fd1498Szrj   const char *p = argv0 + strlen (argv0);
734638fd1498Szrj   while (p != argv0 && !IS_DIR_SEPARATOR (p[-1]))
734738fd1498Szrj     --p;
734838fd1498Szrj   progname = p;
734938fd1498Szrj 
735038fd1498Szrj   xmalloc_set_program_name (progname);
735138fd1498Szrj }
735238fd1498Szrj 
735338fd1498Szrj /* Expand any @ files within the command-line args,
735438fd1498Szrj    setting at_file_supplied if any were expanded.  */
735538fd1498Szrj 
735638fd1498Szrj void
expand_at_files(int * argc,char *** argv)735738fd1498Szrj driver::expand_at_files (int *argc, char ***argv) const
735838fd1498Szrj {
735938fd1498Szrj   char **old_argv = *argv;
736038fd1498Szrj 
736138fd1498Szrj   expandargv (argc, argv);
736238fd1498Szrj 
736338fd1498Szrj   /* Determine if any expansions were made.  */
736438fd1498Szrj   if (*argv != old_argv)
736538fd1498Szrj     at_file_supplied = true;
736638fd1498Szrj }
736738fd1498Szrj 
736838fd1498Szrj /* Decode the command-line arguments from argc/argv into the
736938fd1498Szrj    decoded_options array.  */
737038fd1498Szrj 
737138fd1498Szrj void
decode_argv(int argc,const char ** argv)737238fd1498Szrj driver::decode_argv (int argc, const char **argv)
737338fd1498Szrj {
737438fd1498Szrj   /* Register the language-independent parameters.  */
737538fd1498Szrj   global_init_params ();
737638fd1498Szrj   finish_params ();
737738fd1498Szrj 
737838fd1498Szrj   init_opts_obstack ();
737938fd1498Szrj   init_options_struct (&global_options, &global_options_set);
738038fd1498Szrj 
738138fd1498Szrj   decode_cmdline_options_to_array (argc, argv,
738238fd1498Szrj 				   CL_DRIVER,
738338fd1498Szrj 				   &decoded_options, &decoded_options_count);
738438fd1498Szrj }
738538fd1498Szrj 
738638fd1498Szrj /* Perform various initializations and setup.  */
738738fd1498Szrj 
738838fd1498Szrj void
global_initializations()738938fd1498Szrj driver::global_initializations ()
739038fd1498Szrj {
739138fd1498Szrj   /* Unlock the stdio streams.  */
739238fd1498Szrj   unlock_std_streams ();
739338fd1498Szrj 
739438fd1498Szrj   gcc_init_libintl ();
739538fd1498Szrj 
739638fd1498Szrj   diagnostic_initialize (global_dc, 0);
739738fd1498Szrj   diagnostic_color_init (global_dc);
739838fd1498Szrj 
739938fd1498Szrj #ifdef GCC_DRIVER_HOST_INITIALIZATION
740038fd1498Szrj   /* Perform host dependent initialization when needed.  */
740138fd1498Szrj   GCC_DRIVER_HOST_INITIALIZATION;
740238fd1498Szrj #endif
740338fd1498Szrj 
740438fd1498Szrj   if (atexit (delete_temp_files) != 0)
740538fd1498Szrj     fatal_error (input_location, "atexit failed");
740638fd1498Szrj 
740738fd1498Szrj   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
740838fd1498Szrj     signal (SIGINT, fatal_signal);
740938fd1498Szrj #ifdef SIGHUP
741038fd1498Szrj   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
741138fd1498Szrj     signal (SIGHUP, fatal_signal);
741238fd1498Szrj #endif
741338fd1498Szrj   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
741438fd1498Szrj     signal (SIGTERM, fatal_signal);
741538fd1498Szrj #ifdef SIGPIPE
741638fd1498Szrj   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
741738fd1498Szrj     signal (SIGPIPE, fatal_signal);
741838fd1498Szrj #endif
741938fd1498Szrj #ifdef SIGCHLD
742038fd1498Szrj   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
742138fd1498Szrj      receive the signal.  A different setting is inheritable */
742238fd1498Szrj   signal (SIGCHLD, SIG_DFL);
742338fd1498Szrj #endif
742438fd1498Szrj 
742538fd1498Szrj   /* Parsing and gimplification sometimes need quite large stack.
742638fd1498Szrj      Increase stack size limits if possible.  */
742738fd1498Szrj   stack_limit_increase (64 * 1024 * 1024);
742838fd1498Szrj 
742938fd1498Szrj   /* Allocate the argument vector.  */
743038fd1498Szrj   alloc_args ();
743138fd1498Szrj 
743238fd1498Szrj   obstack_init (&obstack);
743338fd1498Szrj }
743438fd1498Szrj 
743538fd1498Szrj /* Build multilib_select, et. al from the separate lines that make up each
743638fd1498Szrj    multilib selection.  */
743738fd1498Szrj 
743838fd1498Szrj void
build_multilib_strings()743938fd1498Szrj driver::build_multilib_strings () const
744038fd1498Szrj {
744138fd1498Szrj   {
744238fd1498Szrj     const char *p;
744338fd1498Szrj     const char *const *q = multilib_raw;
744438fd1498Szrj     int need_space;
744538fd1498Szrj 
744638fd1498Szrj     obstack_init (&multilib_obstack);
744738fd1498Szrj     while ((p = *q++) != (char *) 0)
744838fd1498Szrj       obstack_grow (&multilib_obstack, p, strlen (p));
744938fd1498Szrj 
745038fd1498Szrj     obstack_1grow (&multilib_obstack, 0);
745138fd1498Szrj     multilib_select = XOBFINISH (&multilib_obstack, const char *);
745238fd1498Szrj 
745338fd1498Szrj     q = multilib_matches_raw;
745438fd1498Szrj     while ((p = *q++) != (char *) 0)
745538fd1498Szrj       obstack_grow (&multilib_obstack, p, strlen (p));
745638fd1498Szrj 
745738fd1498Szrj     obstack_1grow (&multilib_obstack, 0);
745838fd1498Szrj     multilib_matches = XOBFINISH (&multilib_obstack, const char *);
745938fd1498Szrj 
746038fd1498Szrj     q = multilib_exclusions_raw;
746138fd1498Szrj     while ((p = *q++) != (char *) 0)
746238fd1498Szrj       obstack_grow (&multilib_obstack, p, strlen (p));
746338fd1498Szrj 
746438fd1498Szrj     obstack_1grow (&multilib_obstack, 0);
746538fd1498Szrj     multilib_exclusions = XOBFINISH (&multilib_obstack, const char *);
746638fd1498Szrj 
746738fd1498Szrj     q = multilib_reuse_raw;
746838fd1498Szrj     while ((p = *q++) != (char *) 0)
746938fd1498Szrj       obstack_grow (&multilib_obstack, p, strlen (p));
747038fd1498Szrj 
747138fd1498Szrj     obstack_1grow (&multilib_obstack, 0);
747238fd1498Szrj     multilib_reuse = XOBFINISH (&multilib_obstack, const char *);
747338fd1498Szrj 
747438fd1498Szrj     need_space = FALSE;
747538fd1498Szrj     for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
747638fd1498Szrj       {
747738fd1498Szrj 	if (need_space)
747838fd1498Szrj 	  obstack_1grow (&multilib_obstack, ' ');
747938fd1498Szrj 	obstack_grow (&multilib_obstack,
748038fd1498Szrj 		      multilib_defaults_raw[i],
748138fd1498Szrj 		      strlen (multilib_defaults_raw[i]));
748238fd1498Szrj 	need_space = TRUE;
748338fd1498Szrj       }
748438fd1498Szrj 
748538fd1498Szrj     obstack_1grow (&multilib_obstack, 0);
748638fd1498Szrj     multilib_defaults = XOBFINISH (&multilib_obstack, const char *);
748738fd1498Szrj   }
748838fd1498Szrj }
748938fd1498Szrj 
749038fd1498Szrj /* Set up the spec-handling machinery.  */
749138fd1498Szrj 
749238fd1498Szrj void
set_up_specs()749338fd1498Szrj driver::set_up_specs () const
749438fd1498Szrj {
749538fd1498Szrj   const char *spec_machine_suffix;
749638fd1498Szrj   char *specs_file;
749738fd1498Szrj   size_t i;
749838fd1498Szrj 
749938fd1498Szrj #ifdef INIT_ENVIRONMENT
750038fd1498Szrj   /* Set up any other necessary machine specific environment variables.  */
750138fd1498Szrj   xputenv (INIT_ENVIRONMENT);
750238fd1498Szrj #endif
750338fd1498Szrj 
750438fd1498Szrj   /* Make a table of what switches there are (switches, n_switches).
750538fd1498Szrj      Make a table of specified input files (infiles, n_infiles).
750638fd1498Szrj      Decode switches that are handled locally.  */
750738fd1498Szrj 
750838fd1498Szrj   process_command (decoded_options_count, decoded_options);
750938fd1498Szrj 
751038fd1498Szrj   /* Initialize the vector of specs to just the default.
751138fd1498Szrj      This means one element containing 0s, as a terminator.  */
751238fd1498Szrj 
751338fd1498Szrj   compilers = XNEWVAR (struct compiler, sizeof default_compilers);
751438fd1498Szrj   memcpy (compilers, default_compilers, sizeof default_compilers);
751538fd1498Szrj   n_compilers = n_default_compilers;
751638fd1498Szrj 
751738fd1498Szrj   /* Read specs from a file if there is one.  */
751838fd1498Szrj 
751938fd1498Szrj   machine_suffix = concat (spec_host_machine, dir_separator_str, spec_version,
752038fd1498Szrj 			   accel_dir_suffix, dir_separator_str, NULL);
752138fd1498Szrj   just_machine_suffix = concat (spec_machine, dir_separator_str, NULL);
752238fd1498Szrj 
752338fd1498Szrj   specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true);
752438fd1498Szrj   /* Read the specs file unless it is a default one.  */
752538fd1498Szrj   if (specs_file != 0 && strcmp (specs_file, "specs"))
752638fd1498Szrj     read_specs (specs_file, true, false);
752738fd1498Szrj   else
752838fd1498Szrj     init_spec ();
752938fd1498Szrj 
753038fd1498Szrj #ifdef ACCEL_COMPILER
753138fd1498Szrj   spec_machine_suffix = machine_suffix;
753238fd1498Szrj #else
753338fd1498Szrj   spec_machine_suffix = just_machine_suffix;
753438fd1498Szrj #endif
753538fd1498Szrj 
753638fd1498Szrj   /* We need to check standard_exec_prefix/spec_machine_suffix/specs
753738fd1498Szrj      for any override of as, ld and libraries.  */
753838fd1498Szrj   specs_file = (char *) alloca (strlen (standard_exec_prefix)
753938fd1498Szrj 		       + strlen (spec_machine_suffix) + sizeof ("specs"));
754038fd1498Szrj   strcpy (specs_file, standard_exec_prefix);
754138fd1498Szrj   strcat (specs_file, spec_machine_suffix);
754238fd1498Szrj   strcat (specs_file, "specs");
754338fd1498Szrj   if (access (specs_file, R_OK) == 0)
754438fd1498Szrj     read_specs (specs_file, true, false);
754538fd1498Szrj 
754638fd1498Szrj   /* Process any configure-time defaults specified for the command line
754738fd1498Szrj      options, via OPTION_DEFAULT_SPECS.  */
754838fd1498Szrj   for (i = 0; i < ARRAY_SIZE (option_default_specs); i++)
754938fd1498Szrj     do_option_spec (option_default_specs[i].name,
755038fd1498Szrj 		    option_default_specs[i].spec);
755138fd1498Szrj 
755238fd1498Szrj   /* Process DRIVER_SELF_SPECS, adding any new options to the end
755338fd1498Szrj      of the command line.  */
755438fd1498Szrj 
755538fd1498Szrj   for (i = 0; i < ARRAY_SIZE (driver_self_specs); i++)
755638fd1498Szrj     do_self_spec (driver_self_specs[i]);
755738fd1498Szrj 
755838fd1498Szrj   /* If not cross-compiling, look for executables in the standard
755938fd1498Szrj      places.  */
756038fd1498Szrj   if (*cross_compile == '0')
756138fd1498Szrj     {
756238fd1498Szrj       if (*md_exec_prefix)
756338fd1498Szrj 	{
756438fd1498Szrj 	  add_prefix (&exec_prefixes, md_exec_prefix, "GCC",
756538fd1498Szrj 		      PREFIX_PRIORITY_LAST, 0, 0);
756638fd1498Szrj 	}
756738fd1498Szrj     }
756838fd1498Szrj 
756938fd1498Szrj   /* Process sysroot_suffix_spec.  */
757038fd1498Szrj   if (*sysroot_suffix_spec != 0
757138fd1498Szrj       && !no_sysroot_suffix
757238fd1498Szrj       && do_spec_2 (sysroot_suffix_spec) == 0)
757338fd1498Szrj     {
757438fd1498Szrj       if (argbuf.length () > 1)
757538fd1498Szrj         error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC");
757638fd1498Szrj       else if (argbuf.length () == 1)
757738fd1498Szrj         target_sysroot_suffix = xstrdup (argbuf.last ());
757838fd1498Szrj     }
757938fd1498Szrj 
758038fd1498Szrj #ifdef HAVE_LD_SYSROOT
758138fd1498Szrj   /* Pass the --sysroot option to the linker, if it supports that.  If
758238fd1498Szrj      there is a sysroot_suffix_spec, it has already been processed by
758338fd1498Szrj      this point, so target_system_root really is the system root we
758438fd1498Szrj      should be using.  */
758538fd1498Szrj   if (target_system_root)
758638fd1498Szrj     {
758738fd1498Szrj       obstack_grow (&obstack, "%(sysroot_spec) ", strlen ("%(sysroot_spec) "));
758838fd1498Szrj       obstack_grow0 (&obstack, link_spec, strlen (link_spec));
758938fd1498Szrj       set_spec ("link", XOBFINISH (&obstack, const char *), false);
759038fd1498Szrj     }
759138fd1498Szrj #endif
759238fd1498Szrj 
759338fd1498Szrj   /* Process sysroot_hdrs_suffix_spec.  */
759438fd1498Szrj   if (*sysroot_hdrs_suffix_spec != 0
759538fd1498Szrj       && !no_sysroot_suffix
759638fd1498Szrj       && do_spec_2 (sysroot_hdrs_suffix_spec) == 0)
759738fd1498Szrj     {
759838fd1498Szrj       if (argbuf.length () > 1)
759938fd1498Szrj         error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC");
760038fd1498Szrj       else if (argbuf.length () == 1)
760138fd1498Szrj         target_sysroot_hdrs_suffix = xstrdup (argbuf.last ());
760238fd1498Szrj     }
760338fd1498Szrj 
760438fd1498Szrj   /* Look for startfiles in the standard places.  */
760538fd1498Szrj   if (*startfile_prefix_spec != 0
760638fd1498Szrj       && do_spec_2 (startfile_prefix_spec) == 0
760738fd1498Szrj       && do_spec_1 (" ", 0, NULL) == 0)
760838fd1498Szrj     {
760938fd1498Szrj       const char *arg;
761038fd1498Szrj       int ndx;
761138fd1498Szrj       FOR_EACH_VEC_ELT (argbuf, ndx, arg)
761238fd1498Szrj 	add_sysrooted_prefix (&startfile_prefixes, arg, "BINUTILS",
761338fd1498Szrj 			      PREFIX_PRIORITY_LAST, 0, 1);
761438fd1498Szrj     }
761538fd1498Szrj   /* We should eventually get rid of all these and stick to
761638fd1498Szrj      startfile_prefix_spec exclusively.  */
761738fd1498Szrj   else if (*cross_compile == '0' || target_system_root)
761838fd1498Szrj     {
761938fd1498Szrj       if (*md_startfile_prefix)
762038fd1498Szrj 	add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix,
762138fd1498Szrj 			      "GCC", PREFIX_PRIORITY_LAST, 0, 1);
762238fd1498Szrj 
762338fd1498Szrj       if (*md_startfile_prefix_1)
762438fd1498Szrj 	add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix_1,
762538fd1498Szrj 			      "GCC", PREFIX_PRIORITY_LAST, 0, 1);
762638fd1498Szrj 
762738fd1498Szrj       /* If standard_startfile_prefix is relative, base it on
762838fd1498Szrj 	 standard_exec_prefix.  This lets us move the installed tree
762938fd1498Szrj 	 as a unit.  If GCC_EXEC_PREFIX is defined, base
763038fd1498Szrj 	 standard_startfile_prefix on that as well.
763138fd1498Szrj 
763238fd1498Szrj          If the prefix is relative, only search it for native compilers;
763338fd1498Szrj          otherwise we will search a directory containing host libraries.  */
763438fd1498Szrj       if (IS_ABSOLUTE_PATH (standard_startfile_prefix))
763538fd1498Szrj 	add_sysrooted_prefix (&startfile_prefixes,
763638fd1498Szrj 			      standard_startfile_prefix, "BINUTILS",
763738fd1498Szrj 			      PREFIX_PRIORITY_LAST, 0, 1);
763838fd1498Szrj       else if (*cross_compile == '0')
763938fd1498Szrj 	{
764038fd1498Szrj 	  add_prefix (&startfile_prefixes,
764138fd1498Szrj 		      concat (gcc_exec_prefix
764238fd1498Szrj 			      ? gcc_exec_prefix : standard_exec_prefix,
764338fd1498Szrj 			      machine_suffix,
764438fd1498Szrj 			      standard_startfile_prefix, NULL),
764538fd1498Szrj 		      NULL, PREFIX_PRIORITY_LAST, 0, 1);
764638fd1498Szrj 	}
764738fd1498Szrj 
764838fd1498Szrj       /* Sysrooted prefixes are relocated because target_system_root is
764938fd1498Szrj 	 also relocated by gcc_exec_prefix.  */
765038fd1498Szrj       if (*standard_startfile_prefix_1)
765138fd1498Szrj  	add_sysrooted_prefix (&startfile_prefixes,
765238fd1498Szrj 			      standard_startfile_prefix_1, "BINUTILS",
765338fd1498Szrj 			      PREFIX_PRIORITY_LAST, 0, 1);
765438fd1498Szrj       if (*standard_startfile_prefix_2)
765538fd1498Szrj 	add_sysrooted_prefix (&startfile_prefixes,
765638fd1498Szrj 			      standard_startfile_prefix_2, "BINUTILS",
765738fd1498Szrj 			      PREFIX_PRIORITY_LAST, 0, 1);
765838fd1498Szrj     }
765938fd1498Szrj 
766038fd1498Szrj   /* Process any user specified specs in the order given on the command
766138fd1498Szrj      line.  */
766238fd1498Szrj   for (struct user_specs *uptr = user_specs_head; uptr; uptr = uptr->next)
766338fd1498Szrj     {
766438fd1498Szrj       char *filename = find_a_file (&startfile_prefixes, uptr->filename,
766538fd1498Szrj 				    R_OK, true);
766638fd1498Szrj       read_specs (filename ? filename : uptr->filename, false, true);
766738fd1498Szrj     }
766838fd1498Szrj 
766938fd1498Szrj   /* Process any user self specs.  */
767038fd1498Szrj   {
767138fd1498Szrj     struct spec_list *sl;
767238fd1498Szrj     for (sl = specs; sl; sl = sl->next)
767338fd1498Szrj       if (sl->name_len == sizeof "self_spec" - 1
767438fd1498Szrj 	  && !strcmp (sl->name, "self_spec"))
767538fd1498Szrj 	do_self_spec (*sl->ptr_spec);
767638fd1498Szrj   }
767738fd1498Szrj 
767838fd1498Szrj   if (compare_debug)
767938fd1498Szrj     {
768038fd1498Szrj       enum save_temps save;
768138fd1498Szrj 
768238fd1498Szrj       if (!compare_debug_second)
768338fd1498Szrj 	{
768438fd1498Szrj 	  n_switches_debug_check[1] = n_switches;
768538fd1498Szrj 	  n_switches_alloc_debug_check[1] = n_switches_alloc;
768638fd1498Szrj 	  switches_debug_check[1] = XDUPVEC (struct switchstr, switches,
768738fd1498Szrj 					     n_switches_alloc);
768838fd1498Szrj 
768938fd1498Szrj 	  do_self_spec ("%:compare-debug-self-opt()");
769038fd1498Szrj 	  n_switches_debug_check[0] = n_switches;
769138fd1498Szrj 	  n_switches_alloc_debug_check[0] = n_switches_alloc;
769238fd1498Szrj 	  switches_debug_check[0] = switches;
769338fd1498Szrj 
769438fd1498Szrj 	  n_switches = n_switches_debug_check[1];
769538fd1498Szrj 	  n_switches_alloc = n_switches_alloc_debug_check[1];
769638fd1498Szrj 	  switches = switches_debug_check[1];
769738fd1498Szrj 	}
769838fd1498Szrj 
769938fd1498Szrj       /* Avoid crash when computing %j in this early.  */
770038fd1498Szrj       save = save_temps_flag;
770138fd1498Szrj       save_temps_flag = SAVE_TEMPS_NONE;
770238fd1498Szrj 
770338fd1498Szrj       compare_debug = -compare_debug;
770438fd1498Szrj       do_self_spec ("%:compare-debug-self-opt()");
770538fd1498Szrj 
770638fd1498Szrj       save_temps_flag = save;
770738fd1498Szrj 
770838fd1498Szrj       if (!compare_debug_second)
770938fd1498Szrj 	{
771038fd1498Szrj 	  n_switches_debug_check[1] = n_switches;
771138fd1498Szrj 	  n_switches_alloc_debug_check[1] = n_switches_alloc;
771238fd1498Szrj 	  switches_debug_check[1] = switches;
771338fd1498Szrj 	  compare_debug = -compare_debug;
771438fd1498Szrj 	  n_switches = n_switches_debug_check[0];
771538fd1498Szrj 	  n_switches_alloc = n_switches_debug_check[0];
771638fd1498Szrj 	  switches = switches_debug_check[0];
771738fd1498Szrj 	}
771838fd1498Szrj     }
771938fd1498Szrj 
772038fd1498Szrj 
772138fd1498Szrj   /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake.  */
772238fd1498Szrj   if (gcc_exec_prefix)
772338fd1498Szrj     gcc_exec_prefix = concat (gcc_exec_prefix, spec_host_machine,
772438fd1498Szrj 			      dir_separator_str, spec_version,
772538fd1498Szrj 			      accel_dir_suffix, dir_separator_str, NULL);
772638fd1498Szrj 
772738fd1498Szrj   /* Now we have the specs.
772838fd1498Szrj      Set the `valid' bits for switches that match anything in any spec.  */
772938fd1498Szrj 
773038fd1498Szrj   validate_all_switches ();
773138fd1498Szrj 
773238fd1498Szrj   /* Now that we have the switches and the specs, set
773338fd1498Szrj      the subdirectory based on the options.  */
773438fd1498Szrj   set_multilib_dir ();
773538fd1498Szrj }
773638fd1498Szrj 
773738fd1498Szrj /* Set up to remember the pathname of gcc and any options
773838fd1498Szrj    needed for collect.  We use argv[0] instead of progname because
773938fd1498Szrj    we need the complete pathname.  */
774038fd1498Szrj 
774138fd1498Szrj void
putenv_COLLECT_GCC(const char * argv0)774238fd1498Szrj driver::putenv_COLLECT_GCC (const char *argv0) const
774338fd1498Szrj {
774438fd1498Szrj   obstack_init (&collect_obstack);
774538fd1498Szrj   obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
774638fd1498Szrj   obstack_grow (&collect_obstack, argv0, strlen (argv0) + 1);
774738fd1498Szrj   xputenv (XOBFINISH (&collect_obstack, char *));
774838fd1498Szrj }
774938fd1498Szrj 
775038fd1498Szrj /* Set up to remember the pathname of the lto wrapper. */
775138fd1498Szrj 
775238fd1498Szrj void
maybe_putenv_COLLECT_LTO_WRAPPER()775338fd1498Szrj driver::maybe_putenv_COLLECT_LTO_WRAPPER () const
775438fd1498Szrj {
775538fd1498Szrj   char *lto_wrapper_file;
775638fd1498Szrj 
775738fd1498Szrj   if (have_c)
775838fd1498Szrj     lto_wrapper_file = NULL;
775938fd1498Szrj   else
776038fd1498Szrj     lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper",
776138fd1498Szrj 				    X_OK, false);
776238fd1498Szrj   if (lto_wrapper_file)
776338fd1498Szrj     {
776438fd1498Szrj       lto_wrapper_file = convert_white_space (lto_wrapper_file);
776538fd1498Szrj       lto_wrapper_spec = lto_wrapper_file;
776638fd1498Szrj       obstack_init (&collect_obstack);
776738fd1498Szrj       obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
776838fd1498Szrj 		    sizeof ("COLLECT_LTO_WRAPPER=") - 1);
776938fd1498Szrj       obstack_grow (&collect_obstack, lto_wrapper_spec,
777038fd1498Szrj 		    strlen (lto_wrapper_spec) + 1);
777138fd1498Szrj       xputenv (XOBFINISH (&collect_obstack, char *));
777238fd1498Szrj     }
777338fd1498Szrj 
777438fd1498Szrj }
777538fd1498Szrj 
777638fd1498Szrj /* Set up to remember the names of offload targets.  */
777738fd1498Szrj 
777838fd1498Szrj void
maybe_putenv_OFFLOAD_TARGETS()777938fd1498Szrj driver::maybe_putenv_OFFLOAD_TARGETS () const
778038fd1498Szrj {
778138fd1498Szrj   if (offload_targets && offload_targets[0] != '\0')
778238fd1498Szrj     {
778338fd1498Szrj       obstack_grow (&collect_obstack, "OFFLOAD_TARGET_NAMES=",
778438fd1498Szrj 		    sizeof ("OFFLOAD_TARGET_NAMES=") - 1);
778538fd1498Szrj       obstack_grow (&collect_obstack, offload_targets,
778638fd1498Szrj 		    strlen (offload_targets) + 1);
778738fd1498Szrj       xputenv (XOBFINISH (&collect_obstack, char *));
778838fd1498Szrj     }
778938fd1498Szrj 
779038fd1498Szrj   free (offload_targets);
779138fd1498Szrj   offload_targets = NULL;
779238fd1498Szrj }
779338fd1498Szrj 
779438fd1498Szrj /* Helper function for driver::suggest_option.  Populate
779538fd1498Szrj    m_option_suggestions with candidate strings for misspelled options.
779638fd1498Szrj    The strings will be freed by the driver's dtor.  */
779738fd1498Szrj 
779838fd1498Szrj void
build_option_suggestions(void)779938fd1498Szrj driver::build_option_suggestions (void)
780038fd1498Szrj {
780138fd1498Szrj   gcc_assert (m_option_suggestions == NULL);
780238fd1498Szrj   m_option_suggestions = new auto_vec <char *> ();
780338fd1498Szrj 
780438fd1498Szrj   /* We build a vec of m_option_suggestions, using add_misspelling_candidates
780538fd1498Szrj      to add copies of strings, without a leading dash.  */
780638fd1498Szrj 
780738fd1498Szrj   for (unsigned int i = 0; i < cl_options_count; i++)
780838fd1498Szrj     {
780938fd1498Szrj       const struct cl_option *option = &cl_options[i];
781038fd1498Szrj       const char *opt_text = option->opt_text;
781138fd1498Szrj       switch (i)
781238fd1498Szrj 	{
781338fd1498Szrj 	default:
781438fd1498Szrj 	  if (option->var_type == CLVC_ENUM)
781538fd1498Szrj 	    {
781638fd1498Szrj 	      const struct cl_enum *e = &cl_enums[option->var_enum];
781738fd1498Szrj 	      for (unsigned j = 0; e->values[j].arg != NULL; j++)
781838fd1498Szrj 		{
781938fd1498Szrj 		  char *with_arg = concat (opt_text, e->values[j].arg, NULL);
782038fd1498Szrj 		  add_misspelling_candidates (m_option_suggestions, option,
782138fd1498Szrj 					      with_arg);
782238fd1498Szrj 		  free (with_arg);
782338fd1498Szrj 		}
782438fd1498Szrj 	    }
782538fd1498Szrj 	  else
782638fd1498Szrj 	    add_misspelling_candidates (m_option_suggestions, option,
782738fd1498Szrj 					opt_text);
782838fd1498Szrj 	  break;
782938fd1498Szrj 
783038fd1498Szrj 	case OPT_fsanitize_:
783138fd1498Szrj 	case OPT_fsanitize_recover_:
783238fd1498Szrj 	  /* -fsanitize= and -fsanitize-recover= can take
783338fd1498Szrj 	     a comma-separated list of arguments.  Given that combinations
783438fd1498Szrj 	     are supported, we can't add all potential candidates to the
783538fd1498Szrj 	     vec, but if we at least add them individually without commas,
783638fd1498Szrj 	     we should do a better job e.g. correcting
783738fd1498Szrj 	       "-sanitize=address"
783838fd1498Szrj 	     to
783938fd1498Szrj 	       "-fsanitize=address"
784038fd1498Szrj 	     rather than to "-Wframe-address" (PR driver/69265).  */
784138fd1498Szrj 	  {
784238fd1498Szrj 	    for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
784338fd1498Szrj 	      {
784438fd1498Szrj 		struct cl_option optb;
784538fd1498Szrj 		/* -fsanitize=all is not valid, only -fno-sanitize=all.
784638fd1498Szrj 		   So don't register the positive misspelling candidates
784738fd1498Szrj 		   for it.  */
784838fd1498Szrj 		if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
784938fd1498Szrj 		  {
785038fd1498Szrj 		    optb = *option;
785138fd1498Szrj 		    optb.opt_text = opt_text = "-fno-sanitize=";
785238fd1498Szrj 		    optb.cl_reject_negative = true;
785338fd1498Szrj 		    option = &optb;
785438fd1498Szrj 		  }
785538fd1498Szrj 		/* Get one arg at a time e.g. "-fsanitize=address".  */
785638fd1498Szrj 		char *with_arg = concat (opt_text,
785738fd1498Szrj 					 sanitizer_opts[j].name,
785838fd1498Szrj 					 NULL);
785938fd1498Szrj 		/* Add with_arg and all of its variant spellings e.g.
786038fd1498Szrj 		   "-fno-sanitize=address" to candidates (albeit without
786138fd1498Szrj 		   leading dashes).  */
786238fd1498Szrj 		add_misspelling_candidates (m_option_suggestions, option,
786338fd1498Szrj 					    with_arg);
786438fd1498Szrj 		free (with_arg);
786538fd1498Szrj 	      }
786638fd1498Szrj 	  }
786738fd1498Szrj 	  break;
786838fd1498Szrj 	}
786938fd1498Szrj     }
787038fd1498Szrj }
787138fd1498Szrj 
787238fd1498Szrj /* Helper function for driver::handle_unrecognized_options.
787338fd1498Szrj 
787438fd1498Szrj    Given an unrecognized option BAD_OPT (without the leading dash),
787538fd1498Szrj    locate the closest reasonable matching option (again, without the
787638fd1498Szrj    leading dash), or NULL.
787738fd1498Szrj 
787838fd1498Szrj    The returned string is owned by the driver instance.  */
787938fd1498Szrj 
788038fd1498Szrj const char *
suggest_option(const char * bad_opt)788138fd1498Szrj driver::suggest_option (const char *bad_opt)
788238fd1498Szrj {
788338fd1498Szrj   /* Lazily populate m_option_suggestions.  */
788438fd1498Szrj   if (!m_option_suggestions)
788538fd1498Szrj     build_option_suggestions ();
788638fd1498Szrj   gcc_assert (m_option_suggestions);
788738fd1498Szrj 
788838fd1498Szrj   /* "m_option_suggestions" is now populated.  Use it.  */
788938fd1498Szrj   return find_closest_string
789038fd1498Szrj     (bad_opt,
789138fd1498Szrj      (auto_vec <const char *> *) m_option_suggestions);
789238fd1498Szrj }
789338fd1498Szrj 
789438fd1498Szrj /* Reject switches that no pass was interested in.  */
789538fd1498Szrj 
789638fd1498Szrj void
handle_unrecognized_options()789738fd1498Szrj driver::handle_unrecognized_options ()
789838fd1498Szrj {
789938fd1498Szrj   for (size_t i = 0; (int) i < n_switches; i++)
790038fd1498Szrj     if (! switches[i].validated)
790138fd1498Szrj       {
790238fd1498Szrj 	const char *hint = suggest_option (switches[i].part1);
790338fd1498Szrj 	if (hint)
790438fd1498Szrj 	  error ("unrecognized command line option %<-%s%>;"
790538fd1498Szrj 		 " did you mean %<-%s%>?",
790638fd1498Szrj 		 switches[i].part1, hint);
790738fd1498Szrj 	else
790838fd1498Szrj 	  error ("unrecognized command line option %<-%s%>",
790938fd1498Szrj 		 switches[i].part1);
791038fd1498Szrj       }
791138fd1498Szrj }
791238fd1498Szrj 
791338fd1498Szrj /* Handle the various -print-* options, returning 0 if the driver
791438fd1498Szrj    should exit, or nonzero if the driver should continue.  */
791538fd1498Szrj 
791638fd1498Szrj int
maybe_print_and_exit()791738fd1498Szrj driver::maybe_print_and_exit () const
791838fd1498Szrj {
791938fd1498Szrj   if (print_search_dirs)
792038fd1498Szrj     {
792138fd1498Szrj       printf (_("install: %s%s\n"),
792238fd1498Szrj 	      gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix,
792338fd1498Szrj 	      gcc_exec_prefix ? "" : machine_suffix);
792438fd1498Szrj       printf (_("programs: %s\n"),
792538fd1498Szrj 	      build_search_list (&exec_prefixes, "", false, false));
792638fd1498Szrj       printf (_("libraries: %s\n"),
792738fd1498Szrj 	      build_search_list (&startfile_prefixes, "", false, true));
792838fd1498Szrj       return (0);
792938fd1498Szrj     }
793038fd1498Szrj 
793138fd1498Szrj   if (print_file_name)
793238fd1498Szrj     {
793338fd1498Szrj       printf ("%s\n", find_file (print_file_name));
793438fd1498Szrj       return (0);
793538fd1498Szrj     }
793638fd1498Szrj 
793738fd1498Szrj   if (print_prog_name)
793838fd1498Szrj     {
793938fd1498Szrj       if (use_ld != NULL && ! strcmp (print_prog_name, "ld"))
794038fd1498Szrj 	{
794138fd1498Szrj 	  /* Append USE_LD to the default linker.  */
794238fd1498Szrj #ifdef DEFAULT_LINKER
794338fd1498Szrj 	  char *ld;
794438fd1498Szrj # ifdef HAVE_HOST_EXECUTABLE_SUFFIX
794538fd1498Szrj 	  int len = (sizeof (DEFAULT_LINKER)
794638fd1498Szrj 		     - sizeof (HOST_EXECUTABLE_SUFFIX));
794738fd1498Szrj 	  ld = NULL;
794838fd1498Szrj 	  if (len > 0)
794938fd1498Szrj 	    {
795038fd1498Szrj 	      char *default_linker = xstrdup (DEFAULT_LINKER);
795138fd1498Szrj 	      /* Strip HOST_EXECUTABLE_SUFFIX if DEFAULT_LINKER contains
795238fd1498Szrj 		 HOST_EXECUTABLE_SUFFIX.  */
795338fd1498Szrj 	      if (! strcmp (&default_linker[len], HOST_EXECUTABLE_SUFFIX))
795438fd1498Szrj 		{
795538fd1498Szrj 		  default_linker[len] = '\0';
795638fd1498Szrj 		  ld = concat (default_linker, use_ld,
795738fd1498Szrj 			       HOST_EXECUTABLE_SUFFIX, NULL);
795838fd1498Szrj 		}
795938fd1498Szrj 	    }
796038fd1498Szrj 	  if (ld == NULL)
796138fd1498Szrj # endif
796238fd1498Szrj 	  ld = concat (DEFAULT_LINKER, use_ld, NULL);
796338fd1498Szrj 	  if (access (ld, X_OK) == 0)
796438fd1498Szrj 	    {
796538fd1498Szrj 	      printf ("%s\n", ld);
796638fd1498Szrj 	      return (0);
796738fd1498Szrj 	    }
796838fd1498Szrj #endif
796938fd1498Szrj 	  print_prog_name = concat (print_prog_name, use_ld, NULL);
797038fd1498Szrj 	}
797138fd1498Szrj       char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK, 0);
797238fd1498Szrj       printf ("%s\n", (newname ? newname : print_prog_name));
797338fd1498Szrj       return (0);
797438fd1498Szrj     }
797538fd1498Szrj 
797638fd1498Szrj   if (print_multi_lib)
797738fd1498Szrj     {
797838fd1498Szrj       print_multilib_info ();
797938fd1498Szrj       return (0);
798038fd1498Szrj     }
798138fd1498Szrj 
798238fd1498Szrj   if (print_multi_directory)
798338fd1498Szrj     {
798438fd1498Szrj       if (multilib_dir == NULL)
798538fd1498Szrj 	printf (".\n");
798638fd1498Szrj       else
798738fd1498Szrj 	printf ("%s\n", multilib_dir);
798838fd1498Szrj       return (0);
798938fd1498Szrj     }
799038fd1498Szrj 
799138fd1498Szrj   if (print_multiarch)
799238fd1498Szrj     {
799338fd1498Szrj       if (multiarch_dir == NULL)
799438fd1498Szrj 	printf ("\n");
799538fd1498Szrj       else
799638fd1498Szrj 	printf ("%s\n", multiarch_dir);
799738fd1498Szrj       return (0);
799838fd1498Szrj     }
799938fd1498Szrj 
800038fd1498Szrj   if (print_sysroot)
800138fd1498Szrj     {
800238fd1498Szrj       if (target_system_root)
800338fd1498Szrj 	{
800438fd1498Szrj           if (target_sysroot_suffix)
800538fd1498Szrj 	    printf ("%s%s\n", target_system_root, target_sysroot_suffix);
800638fd1498Szrj           else
800738fd1498Szrj 	    printf ("%s\n", target_system_root);
800838fd1498Szrj 	}
800938fd1498Szrj       return (0);
801038fd1498Szrj     }
801138fd1498Szrj 
801238fd1498Szrj   if (print_multi_os_directory)
801338fd1498Szrj     {
801438fd1498Szrj       if (multilib_os_dir == NULL)
801538fd1498Szrj 	printf (".\n");
801638fd1498Szrj       else
801738fd1498Szrj 	printf ("%s\n", multilib_os_dir);
801838fd1498Szrj       return (0);
801938fd1498Szrj     }
802038fd1498Szrj 
802138fd1498Szrj   if (print_sysroot_headers_suffix)
802238fd1498Szrj     {
802338fd1498Szrj       if (*sysroot_hdrs_suffix_spec)
802438fd1498Szrj 	{
802538fd1498Szrj 	  printf("%s\n", (target_sysroot_hdrs_suffix
802638fd1498Szrj 			  ? target_sysroot_hdrs_suffix
802738fd1498Szrj 			  : ""));
802838fd1498Szrj 	  return (0);
802938fd1498Szrj 	}
803038fd1498Szrj       else
803138fd1498Szrj 	/* The error status indicates that only one set of fixed
803238fd1498Szrj 	   headers should be built.  */
803338fd1498Szrj 	fatal_error (input_location,
803438fd1498Szrj 		     "not configured with sysroot headers suffix");
803538fd1498Szrj     }
803638fd1498Szrj 
803738fd1498Szrj   if (print_help_list)
803838fd1498Szrj     {
803938fd1498Szrj       display_help ();
804038fd1498Szrj 
804138fd1498Szrj       if (! verbose_flag)
804238fd1498Szrj 	{
804338fd1498Szrj 	  printf (_("\nFor bug reporting instructions, please see:\n"));
804438fd1498Szrj 	  printf ("%s.\n", bug_report_url);
804538fd1498Szrj 
804638fd1498Szrj 	  return (0);
804738fd1498Szrj 	}
804838fd1498Szrj 
804938fd1498Szrj       /* We do not exit here.  Instead we have created a fake input file
805038fd1498Szrj 	 called 'help-dummy' which needs to be compiled, and we pass this
805138fd1498Szrj 	 on the various sub-processes, along with the --help switch.
805238fd1498Szrj 	 Ensure their output appears after ours.  */
805338fd1498Szrj       fputc ('\n', stdout);
805438fd1498Szrj       fflush (stdout);
805538fd1498Szrj     }
805638fd1498Szrj 
805738fd1498Szrj   if (print_version)
805838fd1498Szrj     {
805938fd1498Szrj       printf (_("%s %s%s\n"), progname, pkgversion_string,
806038fd1498Szrj 	      version_string);
806138fd1498Szrj       printf ("Copyright %s 2018 Free Software Foundation, Inc.\n",
806238fd1498Szrj 	      _("(C)"));
806338fd1498Szrj       fputs (_("This is free software; see the source for copying conditions.  There is NO\n\
806438fd1498Szrj warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"),
806538fd1498Szrj 	     stdout);
806638fd1498Szrj       if (! verbose_flag)
806738fd1498Szrj 	return 0;
806838fd1498Szrj 
806938fd1498Szrj       /* We do not exit here. We use the same mechanism of --help to print
807038fd1498Szrj 	 the version of the sub-processes. */
807138fd1498Szrj       fputc ('\n', stdout);
807238fd1498Szrj       fflush (stdout);
807338fd1498Szrj     }
807438fd1498Szrj 
807538fd1498Szrj   if (verbose_flag)
807638fd1498Szrj     {
807738fd1498Szrj       print_configuration (stderr);
807838fd1498Szrj       if (n_infiles == 0)
807938fd1498Szrj 	return (0);
808038fd1498Szrj     }
808138fd1498Szrj 
808238fd1498Szrj   return 1;
808338fd1498Szrj }
808438fd1498Szrj 
808538fd1498Szrj /* Figure out what to do with each input file.
808638fd1498Szrj    Return true if we need to exit early from "main", false otherwise.  */
808738fd1498Szrj 
808838fd1498Szrj bool
prepare_infiles()808938fd1498Szrj driver::prepare_infiles ()
809038fd1498Szrj {
809138fd1498Szrj   size_t i;
809238fd1498Szrj   int lang_n_infiles = 0;
809338fd1498Szrj 
809438fd1498Szrj   if (n_infiles == added_libraries)
809538fd1498Szrj     fatal_error (input_location, "no input files");
809638fd1498Szrj 
809738fd1498Szrj   if (seen_error ())
809838fd1498Szrj     /* Early exit needed from main.  */
809938fd1498Szrj     return true;
810038fd1498Szrj 
810138fd1498Szrj   /* Make a place to record the compiler output file names
810238fd1498Szrj      that correspond to the input files.  */
810338fd1498Szrj 
810438fd1498Szrj   i = n_infiles;
810538fd1498Szrj   i += lang_specific_extra_outfiles;
810638fd1498Szrj   outfiles = XCNEWVEC (const char *, i);
810738fd1498Szrj 
810838fd1498Szrj   /* Record which files were specified explicitly as link input.  */
810938fd1498Szrj 
811038fd1498Szrj   explicit_link_files = XCNEWVEC (char, n_infiles);
811138fd1498Szrj 
811238fd1498Szrj   combine_inputs = have_o || flag_wpa;
811338fd1498Szrj 
811438fd1498Szrj   for (i = 0; (int) i < n_infiles; i++)
811538fd1498Szrj     {
811638fd1498Szrj       const char *name = infiles[i].name;
811738fd1498Szrj       struct compiler *compiler = lookup_compiler (name,
811838fd1498Szrj 						   strlen (name),
811938fd1498Szrj 						   infiles[i].language);
812038fd1498Szrj 
812138fd1498Szrj       if (compiler && !(compiler->combinable))
812238fd1498Szrj 	combine_inputs = false;
812338fd1498Szrj 
812438fd1498Szrj       if (lang_n_infiles > 0 && compiler != input_file_compiler
812538fd1498Szrj 	  && infiles[i].language && infiles[i].language[0] != '*')
812638fd1498Szrj 	infiles[i].incompiler = compiler;
812738fd1498Szrj       else if (compiler)
812838fd1498Szrj 	{
812938fd1498Szrj 	  lang_n_infiles++;
813038fd1498Szrj 	  input_file_compiler = compiler;
813138fd1498Szrj 	  infiles[i].incompiler = compiler;
813238fd1498Szrj 	}
813338fd1498Szrj       else
813438fd1498Szrj 	{
813538fd1498Szrj 	  /* Since there is no compiler for this input file, assume it is a
813638fd1498Szrj 	     linker file.  */
813738fd1498Szrj 	  explicit_link_files[i] = 1;
813838fd1498Szrj 	  infiles[i].incompiler = NULL;
813938fd1498Szrj 	}
814038fd1498Szrj       infiles[i].compiled = false;
814138fd1498Szrj       infiles[i].preprocessed = false;
814238fd1498Szrj     }
814338fd1498Szrj 
814438fd1498Szrj   if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
814538fd1498Szrj     fatal_error (input_location,
814638fd1498Szrj 		 "cannot specify -o with -c, -S or -E with multiple files");
814738fd1498Szrj 
814838fd1498Szrj   /* No early exit needed from main; we can continue.  */
814938fd1498Szrj   return false;
815038fd1498Szrj }
815138fd1498Szrj 
815238fd1498Szrj /* Run the spec machinery on each input file.  */
815338fd1498Szrj 
815438fd1498Szrj void
do_spec_on_infiles()815538fd1498Szrj driver::do_spec_on_infiles () const
815638fd1498Szrj {
815738fd1498Szrj   size_t i;
815838fd1498Szrj 
815938fd1498Szrj   for (i = 0; (int) i < n_infiles; i++)
816038fd1498Szrj     {
816138fd1498Szrj       int this_file_error = 0;
816238fd1498Szrj 
816338fd1498Szrj       /* Tell do_spec what to substitute for %i.  */
816438fd1498Szrj 
816538fd1498Szrj       input_file_number = i;
816638fd1498Szrj       set_input (infiles[i].name);
816738fd1498Szrj 
816838fd1498Szrj       if (infiles[i].compiled)
816938fd1498Szrj 	continue;
817038fd1498Szrj 
817138fd1498Szrj       /* Use the same thing in %o, unless cp->spec says otherwise.  */
817238fd1498Szrj 
817338fd1498Szrj       outfiles[i] = gcc_input_filename;
817438fd1498Szrj 
817538fd1498Szrj       /* Figure out which compiler from the file's suffix.  */
817638fd1498Szrj 
817738fd1498Szrj       input_file_compiler
817838fd1498Szrj 	= lookup_compiler (infiles[i].name, input_filename_length,
817938fd1498Szrj 			   infiles[i].language);
818038fd1498Szrj 
818138fd1498Szrj       if (input_file_compiler)
818238fd1498Szrj 	{
818338fd1498Szrj 	  /* Ok, we found an applicable compiler.  Run its spec.  */
818438fd1498Szrj 
818538fd1498Szrj 	  if (input_file_compiler->spec[0] == '#')
818638fd1498Szrj 	    {
818738fd1498Szrj 	      error ("%s: %s compiler not installed on this system",
818838fd1498Szrj 		     gcc_input_filename, &input_file_compiler->spec[1]);
818938fd1498Szrj 	      this_file_error = 1;
819038fd1498Szrj 	    }
819138fd1498Szrj 	  else
819238fd1498Szrj 	    {
819338fd1498Szrj 	      int value;
819438fd1498Szrj 
819538fd1498Szrj 	      if (compare_debug)
819638fd1498Szrj 		{
819738fd1498Szrj 		  free (debug_check_temp_file[0]);
819838fd1498Szrj 		  debug_check_temp_file[0] = NULL;
819938fd1498Szrj 
820038fd1498Szrj 		  free (debug_check_temp_file[1]);
820138fd1498Szrj 		  debug_check_temp_file[1] = NULL;
820238fd1498Szrj 		}
820338fd1498Szrj 
820438fd1498Szrj 	      value = do_spec (input_file_compiler->spec);
820538fd1498Szrj 	      infiles[i].compiled = true;
820638fd1498Szrj 	      if (value < 0)
820738fd1498Szrj 		this_file_error = 1;
820838fd1498Szrj 	      else if (compare_debug && debug_check_temp_file[0])
820938fd1498Szrj 		{
821038fd1498Szrj 		  if (verbose_flag)
821138fd1498Szrj 		    inform (UNKNOWN_LOCATION,
821238fd1498Szrj 			    "recompiling with -fcompare-debug");
821338fd1498Szrj 
821438fd1498Szrj 		  compare_debug = -compare_debug;
821538fd1498Szrj 		  n_switches = n_switches_debug_check[1];
821638fd1498Szrj 		  n_switches_alloc = n_switches_alloc_debug_check[1];
821738fd1498Szrj 		  switches = switches_debug_check[1];
821838fd1498Szrj 
821938fd1498Szrj 		  value = do_spec (input_file_compiler->spec);
822038fd1498Szrj 
822138fd1498Szrj 		  compare_debug = -compare_debug;
822238fd1498Szrj 		  n_switches = n_switches_debug_check[0];
822338fd1498Szrj 		  n_switches_alloc = n_switches_alloc_debug_check[0];
822438fd1498Szrj 		  switches = switches_debug_check[0];
822538fd1498Szrj 
822638fd1498Szrj 		  if (value < 0)
822738fd1498Szrj 		    {
822838fd1498Szrj 		      error ("during -fcompare-debug recompilation");
822938fd1498Szrj 		      this_file_error = 1;
823038fd1498Szrj 		    }
823138fd1498Szrj 
823238fd1498Szrj 		  gcc_assert (debug_check_temp_file[1]
823338fd1498Szrj 			      && filename_cmp (debug_check_temp_file[0],
823438fd1498Szrj 					       debug_check_temp_file[1]));
823538fd1498Szrj 
823638fd1498Szrj 		  if (verbose_flag)
823738fd1498Szrj 		    inform (UNKNOWN_LOCATION, "comparing final insns dumps");
823838fd1498Szrj 
823938fd1498Szrj 		  if (compare_files (debug_check_temp_file))
824038fd1498Szrj 		    this_file_error = 1;
824138fd1498Szrj 		}
824238fd1498Szrj 
824338fd1498Szrj 	      if (compare_debug)
824438fd1498Szrj 		{
824538fd1498Szrj 		  free (debug_check_temp_file[0]);
824638fd1498Szrj 		  debug_check_temp_file[0] = NULL;
824738fd1498Szrj 
824838fd1498Szrj 		  free (debug_check_temp_file[1]);
824938fd1498Szrj 		  debug_check_temp_file[1] = NULL;
825038fd1498Szrj 		}
825138fd1498Szrj 	    }
825238fd1498Szrj 	}
825338fd1498Szrj 
825438fd1498Szrj       /* If this file's name does not contain a recognized suffix,
825538fd1498Szrj 	 record it as explicit linker input.  */
825638fd1498Szrj 
825738fd1498Szrj       else
825838fd1498Szrj 	explicit_link_files[i] = 1;
825938fd1498Szrj 
826038fd1498Szrj       /* Clear the delete-on-failure queue, deleting the files in it
826138fd1498Szrj 	 if this compilation failed.  */
826238fd1498Szrj 
826338fd1498Szrj       if (this_file_error)
826438fd1498Szrj 	{
826538fd1498Szrj 	  delete_failure_queue ();
826638fd1498Szrj 	  errorcount++;
826738fd1498Szrj 	}
826838fd1498Szrj       /* If this compilation succeeded, don't delete those files later.  */
826938fd1498Szrj       clear_failure_queue ();
827038fd1498Szrj     }
827138fd1498Szrj 
827238fd1498Szrj   /* Reset the input file name to the first compile/object file name, for use
827338fd1498Szrj      with %b in LINK_SPEC. We use the first input file that we can find
827438fd1498Szrj      a compiler to compile it instead of using infiles.language since for
827538fd1498Szrj      languages other than C we use aliases that we then lookup later.  */
827638fd1498Szrj   if (n_infiles > 0)
827738fd1498Szrj     {
827838fd1498Szrj       int i;
827938fd1498Szrj 
828038fd1498Szrj       for (i = 0; i < n_infiles ; i++)
828138fd1498Szrj 	if (infiles[i].incompiler
828238fd1498Szrj 	    || (infiles[i].language && infiles[i].language[0] != '*'))
828338fd1498Szrj 	  {
828438fd1498Szrj 	    set_input (infiles[i].name);
828538fd1498Szrj 	    break;
828638fd1498Szrj 	  }
828738fd1498Szrj     }
828838fd1498Szrj 
828938fd1498Szrj   if (!seen_error ())
829038fd1498Szrj     {
829138fd1498Szrj       /* Make sure INPUT_FILE_NUMBER points to first available open
829238fd1498Szrj 	 slot.  */
829338fd1498Szrj       input_file_number = n_infiles;
829438fd1498Szrj       if (lang_specific_pre_link ())
829538fd1498Szrj 	errorcount++;
829638fd1498Szrj     }
829738fd1498Szrj }
829838fd1498Szrj 
829938fd1498Szrj /* If we have to run the linker, do it now.  */
830038fd1498Szrj 
830138fd1498Szrj void
maybe_run_linker(const char * argv0)830238fd1498Szrj driver::maybe_run_linker (const char *argv0) const
830338fd1498Szrj {
830438fd1498Szrj   size_t i;
830538fd1498Szrj   int linker_was_run = 0;
830638fd1498Szrj   int num_linker_inputs;
830738fd1498Szrj 
830838fd1498Szrj   /* Determine if there are any linker input files.  */
830938fd1498Szrj   num_linker_inputs = 0;
831038fd1498Szrj   for (i = 0; (int) i < n_infiles; i++)
831138fd1498Szrj     if (explicit_link_files[i] || outfiles[i] != NULL)
831238fd1498Szrj       num_linker_inputs++;
831338fd1498Szrj 
831438fd1498Szrj   /* Run ld to link all the compiler output files.  */
831538fd1498Szrj 
831638fd1498Szrj   if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
831738fd1498Szrj     {
831838fd1498Szrj       int tmp = execution_count;
831938fd1498Szrj 
832038fd1498Szrj       if (! have_c)
832138fd1498Szrj 	{
832238fd1498Szrj #if HAVE_LTO_PLUGIN > 0
832338fd1498Szrj #if HAVE_LTO_PLUGIN == 2
832438fd1498Szrj 	  const char *fno_use_linker_plugin = "fno-use-linker-plugin";
832538fd1498Szrj #else
832638fd1498Szrj 	  const char *fuse_linker_plugin = "fuse-linker-plugin";
832738fd1498Szrj #endif
832838fd1498Szrj #endif
832938fd1498Szrj 
833038fd1498Szrj 	  /* We'll use ld if we can't find collect2.  */
833138fd1498Szrj 	  if (! strcmp (linker_name_spec, "collect2"))
833238fd1498Szrj 	    {
833338fd1498Szrj 	      char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false);
833438fd1498Szrj 	      if (s == NULL)
833538fd1498Szrj 		linker_name_spec = "ld";
833638fd1498Szrj 	    }
833738fd1498Szrj 
833838fd1498Szrj #if HAVE_LTO_PLUGIN > 0
833938fd1498Szrj #if HAVE_LTO_PLUGIN == 2
834038fd1498Szrj 	  if (!switch_matches (fno_use_linker_plugin,
834138fd1498Szrj 			       fno_use_linker_plugin
834238fd1498Szrj 			       + strlen (fno_use_linker_plugin), 0))
834338fd1498Szrj #else
834438fd1498Szrj 	  if (switch_matches (fuse_linker_plugin,
834538fd1498Szrj 			      fuse_linker_plugin
834638fd1498Szrj 			      + strlen (fuse_linker_plugin), 0))
834738fd1498Szrj #endif
834838fd1498Szrj 	    {
834938fd1498Szrj 	      char *temp_spec = find_a_file (&exec_prefixes,
835038fd1498Szrj 					     LTOPLUGINSONAME, R_OK,
835138fd1498Szrj 					     false);
835238fd1498Szrj 	      if (!temp_spec)
835338fd1498Szrj 		fatal_error (input_location,
835438fd1498Szrj 			     "-fuse-linker-plugin, but %s not found",
835538fd1498Szrj 			     LTOPLUGINSONAME);
835638fd1498Szrj 	      linker_plugin_file_spec = convert_white_space (temp_spec);
835738fd1498Szrj 	    }
835838fd1498Szrj #endif
835938fd1498Szrj 	  lto_gcc_spec = argv0;
836038fd1498Szrj 	}
836138fd1498Szrj 
836238fd1498Szrj       /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
836338fd1498Szrj 	 for collect.  */
836438fd1498Szrj       putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false);
836538fd1498Szrj       putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV, true);
836638fd1498Szrj 
836738fd1498Szrj       if (print_subprocess_help == 1)
836838fd1498Szrj 	{
836938fd1498Szrj 	  printf (_("\nLinker options\n==============\n\n"));
837038fd1498Szrj 	  printf (_("Use \"-Wl,OPTION\" to pass \"OPTION\""
837138fd1498Szrj 		    " to the linker.\n\n"));
837238fd1498Szrj 	  fflush (stdout);
837338fd1498Szrj 	}
837438fd1498Szrj       int value = do_spec (link_command_spec);
837538fd1498Szrj       if (value < 0)
837638fd1498Szrj 	errorcount = 1;
837738fd1498Szrj       linker_was_run = (tmp != execution_count);
837838fd1498Szrj     }
837938fd1498Szrj 
838038fd1498Szrj   /* If options said don't run linker,
838138fd1498Szrj      complain about input files to be given to the linker.  */
838238fd1498Szrj 
838338fd1498Szrj   if (! linker_was_run && !seen_error ())
838438fd1498Szrj     for (i = 0; (int) i < n_infiles; i++)
838538fd1498Szrj       if (explicit_link_files[i]
838638fd1498Szrj 	  && !(infiles[i].language && infiles[i].language[0] == '*'))
838738fd1498Szrj 	warning (0, "%s: linker input file unused because linking not done",
838838fd1498Szrj 		 outfiles[i]);
838938fd1498Szrj }
839038fd1498Szrj 
839138fd1498Szrj /* The end of "main".  */
839238fd1498Szrj 
839338fd1498Szrj void
final_actions()839438fd1498Szrj driver::final_actions () const
839538fd1498Szrj {
839638fd1498Szrj   /* Delete some or all of the temporary files we made.  */
839738fd1498Szrj 
839838fd1498Szrj   if (seen_error ())
839938fd1498Szrj     delete_failure_queue ();
840038fd1498Szrj   delete_temp_files ();
840138fd1498Szrj 
840238fd1498Szrj   if (print_help_list)
840338fd1498Szrj     {
840438fd1498Szrj       printf (("\nFor bug reporting instructions, please see:\n"));
840538fd1498Szrj       printf ("%s\n", bug_report_url);
840638fd1498Szrj     }
840738fd1498Szrj }
840838fd1498Szrj 
840938fd1498Szrj /* Determine what the exit code of the driver should be.  */
841038fd1498Szrj 
841138fd1498Szrj int
get_exit_code()841238fd1498Szrj driver::get_exit_code () const
841338fd1498Szrj {
841438fd1498Szrj   return (signal_count != 0 ? 2
841538fd1498Szrj 	  : seen_error () ? (pass_exit_codes ? greatest_status : 1)
841638fd1498Szrj 	  : 0);
841738fd1498Szrj }
841838fd1498Szrj 
841938fd1498Szrj /* Find the proper compilation spec for the file name NAME,
842038fd1498Szrj    whose length is LENGTH.  LANGUAGE is the specified language,
842138fd1498Szrj    or 0 if this file is to be passed to the linker.  */
842238fd1498Szrj 
842338fd1498Szrj static struct compiler *
lookup_compiler(const char * name,size_t length,const char * language)842438fd1498Szrj lookup_compiler (const char *name, size_t length, const char *language)
842538fd1498Szrj {
842638fd1498Szrj   struct compiler *cp;
842738fd1498Szrj 
842838fd1498Szrj   /* If this was specified by the user to be a linker input, indicate that.  */
842938fd1498Szrj   if (language != 0 && language[0] == '*')
843038fd1498Szrj     return 0;
843138fd1498Szrj 
843238fd1498Szrj   /* Otherwise, look for the language, if one is spec'd.  */
843338fd1498Szrj   if (language != 0)
843438fd1498Szrj     {
843538fd1498Szrj       for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
843638fd1498Szrj 	if (cp->suffix[0] == '@' && !strcmp (cp->suffix + 1, language))
843738fd1498Szrj 	  {
843838fd1498Szrj 	    if (name != NULL && strcmp (name, "-") == 0
843938fd1498Szrj 		&& (strcmp (cp->suffix, "@c-header") == 0
844038fd1498Szrj 		    || strcmp (cp->suffix, "@c++-header") == 0)
844138fd1498Szrj 		&& !have_E)
844238fd1498Szrj 	      fatal_error (input_location,
844338fd1498Szrj 			   "cannot use %<-%> as input filename for a "
844438fd1498Szrj 			   "precompiled header");
844538fd1498Szrj 
844638fd1498Szrj 	    return cp;
844738fd1498Szrj 	  }
844838fd1498Szrj 
844938fd1498Szrj       error ("language %s not recognized", language);
845038fd1498Szrj       return 0;
845138fd1498Szrj     }
845238fd1498Szrj 
845338fd1498Szrj   /* Look for a suffix.  */
845438fd1498Szrj   for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
845538fd1498Szrj     {
845638fd1498Szrj       if (/* The suffix `-' matches only the file name `-'.  */
845738fd1498Szrj 	  (!strcmp (cp->suffix, "-") && !strcmp (name, "-"))
845838fd1498Szrj 	  || (strlen (cp->suffix) < length
845938fd1498Szrj 	      /* See if the suffix matches the end of NAME.  */
846038fd1498Szrj 	      && !strcmp (cp->suffix,
846138fd1498Szrj 			  name + length - strlen (cp->suffix))
846238fd1498Szrj 	 ))
846338fd1498Szrj 	break;
846438fd1498Szrj     }
846538fd1498Szrj 
846638fd1498Szrj #if defined (OS2) ||defined (HAVE_DOS_BASED_FILE_SYSTEM)
846738fd1498Szrj   /* Look again, but case-insensitively this time.  */
846838fd1498Szrj   if (cp < compilers)
846938fd1498Szrj     for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
847038fd1498Szrj       {
847138fd1498Szrj 	if (/* The suffix `-' matches only the file name `-'.  */
847238fd1498Szrj 	    (!strcmp (cp->suffix, "-") && !strcmp (name, "-"))
847338fd1498Szrj 	    || (strlen (cp->suffix) < length
847438fd1498Szrj 		/* See if the suffix matches the end of NAME.  */
847538fd1498Szrj 		&& ((!strcmp (cp->suffix,
847638fd1498Szrj 			     name + length - strlen (cp->suffix))
847738fd1498Szrj 		     || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
847838fd1498Szrj 		    && !strcasecmp (cp->suffix,
847938fd1498Szrj 				    name + length - strlen (cp->suffix)))
848038fd1498Szrj 	   ))
848138fd1498Szrj 	  break;
848238fd1498Szrj       }
848338fd1498Szrj #endif
848438fd1498Szrj 
848538fd1498Szrj   if (cp >= compilers)
848638fd1498Szrj     {
848738fd1498Szrj       if (cp->spec[0] != '@')
848838fd1498Szrj 	/* A non-alias entry: return it.  */
848938fd1498Szrj 	return cp;
849038fd1498Szrj 
849138fd1498Szrj       /* An alias entry maps a suffix to a language.
849238fd1498Szrj 	 Search for the language; pass 0 for NAME and LENGTH
849338fd1498Szrj 	 to avoid infinite recursion if language not found.  */
849438fd1498Szrj       return lookup_compiler (NULL, 0, cp->spec + 1);
849538fd1498Szrj     }
849638fd1498Szrj   return 0;
849738fd1498Szrj }
849838fd1498Szrj 
849938fd1498Szrj static char *
save_string(const char * s,int len)850038fd1498Szrj save_string (const char *s, int len)
850138fd1498Szrj {
850238fd1498Szrj   char *result = XNEWVEC (char, len + 1);
850338fd1498Szrj 
850438fd1498Szrj   gcc_checking_assert (strlen (s) >= (unsigned int) len);
850538fd1498Szrj   memcpy (result, s, len);
850638fd1498Szrj   result[len] = 0;
850738fd1498Szrj   return result;
850838fd1498Szrj }
850938fd1498Szrj 
851038fd1498Szrj void
pfatal_with_name(const char * name)851138fd1498Szrj pfatal_with_name (const char *name)
851238fd1498Szrj {
851338fd1498Szrj   perror_with_name (name);
851438fd1498Szrj   delete_temp_files ();
851538fd1498Szrj   exit (1);
851638fd1498Szrj }
851738fd1498Szrj 
851838fd1498Szrj static void
perror_with_name(const char * name)851938fd1498Szrj perror_with_name (const char *name)
852038fd1498Szrj {
852138fd1498Szrj   error ("%s: %m", name);
852238fd1498Szrj }
852338fd1498Szrj 
852438fd1498Szrj static inline void
validate_switches_from_spec(const char * spec,bool user)852538fd1498Szrj validate_switches_from_spec (const char *spec, bool user)
852638fd1498Szrj {
852738fd1498Szrj   const char *p = spec;
852838fd1498Szrj   char c;
852938fd1498Szrj   while ((c = *p++))
853038fd1498Szrj     if (c == '%' && (*p == '{' || *p == '<' || (*p == 'W' && *++p == '{')))
853138fd1498Szrj       /* We have a switch spec.  */
853238fd1498Szrj       p = validate_switches (p + 1, user);
853338fd1498Szrj }
853438fd1498Szrj 
853538fd1498Szrj static void
validate_all_switches(void)853638fd1498Szrj validate_all_switches (void)
853738fd1498Szrj {
853838fd1498Szrj   struct compiler *comp;
853938fd1498Szrj   struct spec_list *spec;
854038fd1498Szrj 
854138fd1498Szrj   for (comp = compilers; comp->spec; comp++)
854238fd1498Szrj     validate_switches_from_spec (comp->spec, false);
854338fd1498Szrj 
854438fd1498Szrj   /* Look through the linked list of specs read from the specs file.  */
854538fd1498Szrj   for (spec = specs; spec; spec = spec->next)
854638fd1498Szrj     validate_switches_from_spec (*spec->ptr_spec, spec->user_p);
854738fd1498Szrj 
854838fd1498Szrj   validate_switches_from_spec (link_command_spec, false);
854938fd1498Szrj }
855038fd1498Szrj 
855138fd1498Szrj /* Look at the switch-name that comes after START
855238fd1498Szrj    and mark as valid all supplied switches that match it.  */
855338fd1498Szrj 
855438fd1498Szrj static const char *
validate_switches(const char * start,bool user_spec)855538fd1498Szrj validate_switches (const char *start, bool user_spec)
855638fd1498Szrj {
855738fd1498Szrj   const char *p = start;
855838fd1498Szrj   const char *atom;
855938fd1498Szrj   size_t len;
856038fd1498Szrj   int i;
856138fd1498Szrj   bool suffix = false;
856238fd1498Szrj   bool starred = false;
856338fd1498Szrj 
856438fd1498Szrj #define SKIP_WHITE() do { while (*p == ' ' || *p == '\t') p++; } while (0)
856538fd1498Szrj 
856638fd1498Szrj next_member:
856738fd1498Szrj   SKIP_WHITE ();
856838fd1498Szrj 
856938fd1498Szrj   if (*p == '!')
857038fd1498Szrj     p++;
857138fd1498Szrj 
857238fd1498Szrj   SKIP_WHITE ();
857338fd1498Szrj   if (*p == '.' || *p == ',')
857438fd1498Szrj     suffix = true, p++;
857538fd1498Szrj 
857638fd1498Szrj   atom = p;
857738fd1498Szrj   while (ISIDNUM (*p) || *p == '-' || *p == '+' || *p == '='
857838fd1498Szrj 	 || *p == ',' || *p == '.' || *p == '@')
857938fd1498Szrj     p++;
858038fd1498Szrj   len = p - atom;
858138fd1498Szrj 
858238fd1498Szrj   if (*p == '*')
858338fd1498Szrj     starred = true, p++;
858438fd1498Szrj 
858538fd1498Szrj   SKIP_WHITE ();
858638fd1498Szrj 
858738fd1498Szrj   if (!suffix)
858838fd1498Szrj     {
858938fd1498Szrj       /* Mark all matching switches as valid.  */
859038fd1498Szrj       for (i = 0; i < n_switches; i++)
859138fd1498Szrj 	if (!strncmp (switches[i].part1, atom, len)
859238fd1498Szrj 	    && (starred || switches[i].part1[len] == '\0')
859338fd1498Szrj 	    && (switches[i].known || user_spec))
859438fd1498Szrj 	      switches[i].validated = true;
859538fd1498Szrj     }
859638fd1498Szrj 
859738fd1498Szrj   if (*p) p++;
859838fd1498Szrj   if (*p && (p[-1] == '|' || p[-1] == '&'))
859938fd1498Szrj     goto next_member;
860038fd1498Szrj 
860138fd1498Szrj   if (*p && p[-1] == ':')
860238fd1498Szrj     {
860338fd1498Szrj       while (*p && *p != ';' && *p != '}')
860438fd1498Szrj 	{
860538fd1498Szrj 	  if (*p == '%')
860638fd1498Szrj 	    {
860738fd1498Szrj 	      p++;
860838fd1498Szrj 	      if (*p == '{' || *p == '<')
860938fd1498Szrj 		p = validate_switches (p+1, user_spec);
861038fd1498Szrj 	      else if (p[0] == 'W' && p[1] == '{')
861138fd1498Szrj 		p = validate_switches (p+2, user_spec);
861238fd1498Szrj 	    }
861338fd1498Szrj 	  else
861438fd1498Szrj 	    p++;
861538fd1498Szrj 	}
861638fd1498Szrj 
861738fd1498Szrj       if (*p) p++;
861838fd1498Szrj       if (*p && p[-1] == ';')
861938fd1498Szrj 	goto next_member;
862038fd1498Szrj     }
862138fd1498Szrj 
862238fd1498Szrj   return p;
862338fd1498Szrj #undef SKIP_WHITE
862438fd1498Szrj }
862538fd1498Szrj 
862638fd1498Szrj struct mdswitchstr
862738fd1498Szrj {
862838fd1498Szrj   const char *str;
862938fd1498Szrj   int len;
863038fd1498Szrj };
863138fd1498Szrj 
863238fd1498Szrj static struct mdswitchstr *mdswitches;
863338fd1498Szrj static int n_mdswitches;
863438fd1498Szrj 
863538fd1498Szrj /* Check whether a particular argument was used.  The first time we
863638fd1498Szrj    canonicalize the switches to keep only the ones we care about.  */
863738fd1498Szrj 
863838fd1498Szrj class used_arg_t
863938fd1498Szrj {
864038fd1498Szrj  public:
864138fd1498Szrj   int operator () (const char *p, int len);
864238fd1498Szrj   void finalize ();
864338fd1498Szrj 
864438fd1498Szrj  private:
864538fd1498Szrj   struct mswitchstr
864638fd1498Szrj   {
864738fd1498Szrj     const char *str;
864838fd1498Szrj     const char *replace;
864938fd1498Szrj     int len;
865038fd1498Szrj     int rep_len;
865138fd1498Szrj   };
865238fd1498Szrj 
865338fd1498Szrj   mswitchstr *mswitches;
865438fd1498Szrj   int n_mswitches;
865538fd1498Szrj 
865638fd1498Szrj };
865738fd1498Szrj 
865838fd1498Szrj used_arg_t used_arg;
865938fd1498Szrj 
866038fd1498Szrj int
operator()866138fd1498Szrj used_arg_t::operator () (const char *p, int len)
866238fd1498Szrj {
866338fd1498Szrj   int i, j;
866438fd1498Szrj 
866538fd1498Szrj   if (!mswitches)
866638fd1498Szrj     {
866738fd1498Szrj       struct mswitchstr *matches;
866838fd1498Szrj       const char *q;
866938fd1498Szrj       int cnt = 0;
867038fd1498Szrj 
867138fd1498Szrj       /* Break multilib_matches into the component strings of string
867238fd1498Szrj          and replacement string.  */
867338fd1498Szrj       for (q = multilib_matches; *q != '\0'; q++)
867438fd1498Szrj 	if (*q == ';')
867538fd1498Szrj 	  cnt++;
867638fd1498Szrj 
867738fd1498Szrj       matches
867838fd1498Szrj 	= (struct mswitchstr *) alloca ((sizeof (struct mswitchstr)) * cnt);
867938fd1498Szrj       i = 0;
868038fd1498Szrj       q = multilib_matches;
868138fd1498Szrj       while (*q != '\0')
868238fd1498Szrj 	{
868338fd1498Szrj 	  matches[i].str = q;
868438fd1498Szrj 	  while (*q != ' ')
868538fd1498Szrj 	    {
868638fd1498Szrj 	      if (*q == '\0')
868738fd1498Szrj 		{
868838fd1498Szrj 		invalid_matches:
868938fd1498Szrj 		  fatal_error (input_location, "multilib spec %qs is invalid",
869038fd1498Szrj 			       multilib_matches);
869138fd1498Szrj 		}
869238fd1498Szrj 	      q++;
869338fd1498Szrj 	    }
869438fd1498Szrj 	  matches[i].len = q - matches[i].str;
869538fd1498Szrj 
869638fd1498Szrj 	  matches[i].replace = ++q;
869738fd1498Szrj 	  while (*q != ';' && *q != '\0')
869838fd1498Szrj 	    {
869938fd1498Szrj 	      if (*q == ' ')
870038fd1498Szrj 		goto invalid_matches;
870138fd1498Szrj 	      q++;
870238fd1498Szrj 	    }
870338fd1498Szrj 	  matches[i].rep_len = q - matches[i].replace;
870438fd1498Szrj 	  i++;
870538fd1498Szrj 	  if (*q == ';')
870638fd1498Szrj 	    q++;
870738fd1498Szrj 	}
870838fd1498Szrj 
870938fd1498Szrj       /* Now build a list of the replacement string for switches that we care
871038fd1498Szrj 	 about.  Make sure we allocate at least one entry.  This prevents
871138fd1498Szrj 	 xmalloc from calling fatal, and prevents us from re-executing this
871238fd1498Szrj 	 block of code.  */
871338fd1498Szrj       mswitches
871438fd1498Szrj 	= XNEWVEC (struct mswitchstr, n_mdswitches + (n_switches ? n_switches : 1));
871538fd1498Szrj       for (i = 0; i < n_switches; i++)
871638fd1498Szrj 	if ((switches[i].live_cond & SWITCH_IGNORE) == 0)
871738fd1498Szrj 	  {
871838fd1498Szrj 	    int xlen = strlen (switches[i].part1);
871938fd1498Szrj 	    for (j = 0; j < cnt; j++)
872038fd1498Szrj 	      if (xlen == matches[j].len
872138fd1498Szrj 		  && ! strncmp (switches[i].part1, matches[j].str, xlen))
872238fd1498Szrj 		{
872338fd1498Szrj 		  mswitches[n_mswitches].str = matches[j].replace;
872438fd1498Szrj 		  mswitches[n_mswitches].len = matches[j].rep_len;
872538fd1498Szrj 		  mswitches[n_mswitches].replace = (char *) 0;
872638fd1498Szrj 		  mswitches[n_mswitches].rep_len = 0;
872738fd1498Szrj 		  n_mswitches++;
872838fd1498Szrj 		  break;
872938fd1498Szrj 		}
873038fd1498Szrj 	  }
873138fd1498Szrj 
873238fd1498Szrj       /* Add MULTILIB_DEFAULTS switches too, as long as they were not present
873338fd1498Szrj 	 on the command line nor any options mutually incompatible with
873438fd1498Szrj 	 them.  */
873538fd1498Szrj       for (i = 0; i < n_mdswitches; i++)
873638fd1498Szrj 	{
873738fd1498Szrj 	  const char *r;
873838fd1498Szrj 
873938fd1498Szrj 	  for (q = multilib_options; *q != '\0'; *q && q++)
874038fd1498Szrj 	    {
874138fd1498Szrj 	      while (*q == ' ')
874238fd1498Szrj 		q++;
874338fd1498Szrj 
874438fd1498Szrj 	      r = q;
874538fd1498Szrj 	      while (strncmp (q, mdswitches[i].str, mdswitches[i].len) != 0
874638fd1498Szrj 		     || strchr (" /", q[mdswitches[i].len]) == NULL)
874738fd1498Szrj 		{
874838fd1498Szrj 		  while (*q != ' ' && *q != '/' && *q != '\0')
874938fd1498Szrj 		    q++;
875038fd1498Szrj 		  if (*q != '/')
875138fd1498Szrj 		    break;
875238fd1498Szrj 		  q++;
875338fd1498Szrj 		}
875438fd1498Szrj 
875538fd1498Szrj 	      if (*q != ' ' && *q != '\0')
875638fd1498Szrj 		{
875738fd1498Szrj 		  while (*r != ' ' && *r != '\0')
875838fd1498Szrj 		    {
875938fd1498Szrj 		      q = r;
876038fd1498Szrj 		      while (*q != ' ' && *q != '/' && *q != '\0')
876138fd1498Szrj 			q++;
876238fd1498Szrj 
876338fd1498Szrj 		      if (used_arg (r, q - r))
876438fd1498Szrj 			break;
876538fd1498Szrj 
876638fd1498Szrj 		      if (*q != '/')
876738fd1498Szrj 			{
876838fd1498Szrj 			  mswitches[n_mswitches].str = mdswitches[i].str;
876938fd1498Szrj 			  mswitches[n_mswitches].len = mdswitches[i].len;
877038fd1498Szrj 			  mswitches[n_mswitches].replace = (char *) 0;
877138fd1498Szrj 			  mswitches[n_mswitches].rep_len = 0;
877238fd1498Szrj 			  n_mswitches++;
877338fd1498Szrj 			  break;
877438fd1498Szrj 			}
877538fd1498Szrj 
877638fd1498Szrj 		      r = q + 1;
877738fd1498Szrj 		    }
877838fd1498Szrj 		  break;
877938fd1498Szrj 		}
878038fd1498Szrj 	    }
878138fd1498Szrj 	}
878238fd1498Szrj     }
878338fd1498Szrj 
878438fd1498Szrj   for (i = 0; i < n_mswitches; i++)
878538fd1498Szrj     if (len == mswitches[i].len && ! strncmp (p, mswitches[i].str, len))
878638fd1498Szrj       return 1;
878738fd1498Szrj 
878838fd1498Szrj   return 0;
878938fd1498Szrj }
879038fd1498Szrj 
finalize()879138fd1498Szrj void used_arg_t::finalize ()
879238fd1498Szrj {
879338fd1498Szrj   XDELETEVEC (mswitches);
879438fd1498Szrj   mswitches = NULL;
879538fd1498Szrj   n_mswitches = 0;
879638fd1498Szrj }
879738fd1498Szrj 
879838fd1498Szrj 
879938fd1498Szrj static int
default_arg(const char * p,int len)880038fd1498Szrj default_arg (const char *p, int len)
880138fd1498Szrj {
880238fd1498Szrj   int i;
880338fd1498Szrj 
880438fd1498Szrj   for (i = 0; i < n_mdswitches; i++)
880538fd1498Szrj     if (len == mdswitches[i].len && ! strncmp (p, mdswitches[i].str, len))
880638fd1498Szrj       return 1;
880738fd1498Szrj 
880838fd1498Szrj   return 0;
880938fd1498Szrj }
881038fd1498Szrj 
881138fd1498Szrj /* Work out the subdirectory to use based on the options. The format of
881238fd1498Szrj    multilib_select is a list of elements. Each element is a subdirectory
881338fd1498Szrj    name followed by a list of options followed by a semicolon. The format
881438fd1498Szrj    of multilib_exclusions is the same, but without the preceding
881538fd1498Szrj    directory. First gcc will check the exclusions, if none of the options
881638fd1498Szrj    beginning with an exclamation point are present, and all of the other
881738fd1498Szrj    options are present, then we will ignore this completely. Passing
881838fd1498Szrj    that, gcc will consider each multilib_select in turn using the same
881938fd1498Szrj    rules for matching the options. If a match is found, that subdirectory
882038fd1498Szrj    will be used.
882138fd1498Szrj    A subdirectory name is optionally followed by a colon and the corresponding
882238fd1498Szrj    multiarch name.  */
882338fd1498Szrj 
882438fd1498Szrj static void
set_multilib_dir(void)882538fd1498Szrj set_multilib_dir (void)
882638fd1498Szrj {
882738fd1498Szrj   const char *p;
882838fd1498Szrj   unsigned int this_path_len;
882938fd1498Szrj   const char *this_path, *this_arg;
883038fd1498Szrj   const char *start, *end;
883138fd1498Szrj   int not_arg;
883238fd1498Szrj   int ok, ndfltok, first;
883338fd1498Szrj 
883438fd1498Szrj   n_mdswitches = 0;
883538fd1498Szrj   start = multilib_defaults;
883638fd1498Szrj   while (*start == ' ' || *start == '\t')
883738fd1498Szrj     start++;
883838fd1498Szrj   while (*start != '\0')
883938fd1498Szrj     {
884038fd1498Szrj       n_mdswitches++;
884138fd1498Szrj       while (*start != ' ' && *start != '\t' && *start != '\0')
884238fd1498Szrj 	start++;
884338fd1498Szrj       while (*start == ' ' || *start == '\t')
884438fd1498Szrj         start++;
884538fd1498Szrj     }
884638fd1498Szrj 
884738fd1498Szrj   if (n_mdswitches)
884838fd1498Szrj     {
884938fd1498Szrj       int i = 0;
885038fd1498Szrj 
885138fd1498Szrj       mdswitches = XNEWVEC (struct mdswitchstr, n_mdswitches);
885238fd1498Szrj       for (start = multilib_defaults; *start != '\0'; start = end + 1)
885338fd1498Szrj 	{
885438fd1498Szrj 	  while (*start == ' ' || *start == '\t')
885538fd1498Szrj 	    start++;
885638fd1498Szrj 
885738fd1498Szrj 	  if (*start == '\0')
885838fd1498Szrj 	    break;
885938fd1498Szrj 
886038fd1498Szrj 	  for (end = start + 1;
886138fd1498Szrj 	       *end != ' ' && *end != '\t' && *end != '\0'; end++)
886238fd1498Szrj 	    ;
886338fd1498Szrj 
886438fd1498Szrj 	  obstack_grow (&multilib_obstack, start, end - start);
886538fd1498Szrj 	  obstack_1grow (&multilib_obstack, 0);
886638fd1498Szrj 	  mdswitches[i].str = XOBFINISH (&multilib_obstack, const char *);
886738fd1498Szrj 	  mdswitches[i++].len = end - start;
886838fd1498Szrj 
886938fd1498Szrj 	  if (*end == '\0')
887038fd1498Szrj 	    break;
887138fd1498Szrj 	}
887238fd1498Szrj     }
887338fd1498Szrj 
887438fd1498Szrj   p = multilib_exclusions;
887538fd1498Szrj   while (*p != '\0')
887638fd1498Szrj     {
887738fd1498Szrj       /* Ignore newlines.  */
887838fd1498Szrj       if (*p == '\n')
887938fd1498Szrj 	{
888038fd1498Szrj 	  ++p;
888138fd1498Szrj 	  continue;
888238fd1498Szrj 	}
888338fd1498Szrj 
888438fd1498Szrj       /* Check the arguments.  */
888538fd1498Szrj       ok = 1;
888638fd1498Szrj       while (*p != ';')
888738fd1498Szrj 	{
888838fd1498Szrj 	  if (*p == '\0')
888938fd1498Szrj 	    {
889038fd1498Szrj 	    invalid_exclusions:
889138fd1498Szrj 	      fatal_error (input_location, "multilib exclusions %qs is invalid",
889238fd1498Szrj 			   multilib_exclusions);
889338fd1498Szrj 	    }
889438fd1498Szrj 
889538fd1498Szrj 	  if (! ok)
889638fd1498Szrj 	    {
889738fd1498Szrj 	      ++p;
889838fd1498Szrj 	      continue;
889938fd1498Szrj 	    }
890038fd1498Szrj 
890138fd1498Szrj 	  this_arg = p;
890238fd1498Szrj 	  while (*p != ' ' && *p != ';')
890338fd1498Szrj 	    {
890438fd1498Szrj 	      if (*p == '\0')
890538fd1498Szrj 		goto invalid_exclusions;
890638fd1498Szrj 	      ++p;
890738fd1498Szrj 	    }
890838fd1498Szrj 
890938fd1498Szrj 	  if (*this_arg != '!')
891038fd1498Szrj 	    not_arg = 0;
891138fd1498Szrj 	  else
891238fd1498Szrj 	    {
891338fd1498Szrj 	      not_arg = 1;
891438fd1498Szrj 	      ++this_arg;
891538fd1498Szrj 	    }
891638fd1498Szrj 
891738fd1498Szrj 	  ok = used_arg (this_arg, p - this_arg);
891838fd1498Szrj 	  if (not_arg)
891938fd1498Szrj 	    ok = ! ok;
892038fd1498Szrj 
892138fd1498Szrj 	  if (*p == ' ')
892238fd1498Szrj 	    ++p;
892338fd1498Szrj 	}
892438fd1498Szrj 
892538fd1498Szrj       if (ok)
892638fd1498Szrj 	return;
892738fd1498Szrj 
892838fd1498Szrj       ++p;
892938fd1498Szrj     }
893038fd1498Szrj 
893138fd1498Szrj   first = 1;
893238fd1498Szrj   p = multilib_select;
893338fd1498Szrj 
893438fd1498Szrj   /* Append multilib reuse rules if any.  With those rules, we can reuse
893538fd1498Szrj      one multilib for certain different options sets.  */
893638fd1498Szrj   if (strlen (multilib_reuse) > 0)
893738fd1498Szrj     p = concat (p, multilib_reuse, NULL);
893838fd1498Szrj 
893938fd1498Szrj   while (*p != '\0')
894038fd1498Szrj     {
894138fd1498Szrj       /* Ignore newlines.  */
894238fd1498Szrj       if (*p == '\n')
894338fd1498Szrj 	{
894438fd1498Szrj 	  ++p;
894538fd1498Szrj 	  continue;
894638fd1498Szrj 	}
894738fd1498Szrj 
894838fd1498Szrj       /* Get the initial path.  */
894938fd1498Szrj       this_path = p;
895038fd1498Szrj       while (*p != ' ')
895138fd1498Szrj 	{
895238fd1498Szrj 	  if (*p == '\0')
895338fd1498Szrj 	    {
895438fd1498Szrj 	    invalid_select:
895538fd1498Szrj 	      fatal_error (input_location, "multilib select %qs %qs is invalid",
895638fd1498Szrj 			   multilib_select, multilib_reuse);
895738fd1498Szrj 	    }
895838fd1498Szrj 	  ++p;
895938fd1498Szrj 	}
896038fd1498Szrj       this_path_len = p - this_path;
896138fd1498Szrj 
896238fd1498Szrj       /* Check the arguments.  */
896338fd1498Szrj       ok = 1;
896438fd1498Szrj       ndfltok = 1;
896538fd1498Szrj       ++p;
896638fd1498Szrj       while (*p != ';')
896738fd1498Szrj 	{
896838fd1498Szrj 	  if (*p == '\0')
896938fd1498Szrj 	    goto invalid_select;
897038fd1498Szrj 
897138fd1498Szrj 	  if (! ok)
897238fd1498Szrj 	    {
897338fd1498Szrj 	      ++p;
897438fd1498Szrj 	      continue;
897538fd1498Szrj 	    }
897638fd1498Szrj 
897738fd1498Szrj 	  this_arg = p;
897838fd1498Szrj 	  while (*p != ' ' && *p != ';')
897938fd1498Szrj 	    {
898038fd1498Szrj 	      if (*p == '\0')
898138fd1498Szrj 		goto invalid_select;
898238fd1498Szrj 	      ++p;
898338fd1498Szrj 	    }
898438fd1498Szrj 
898538fd1498Szrj 	  if (*this_arg != '!')
898638fd1498Szrj 	    not_arg = 0;
898738fd1498Szrj 	  else
898838fd1498Szrj 	    {
898938fd1498Szrj 	      not_arg = 1;
899038fd1498Szrj 	      ++this_arg;
899138fd1498Szrj 	    }
899238fd1498Szrj 
899338fd1498Szrj 	  /* If this is a default argument, we can just ignore it.
899438fd1498Szrj 	     This is true even if this_arg begins with '!'.  Beginning
899538fd1498Szrj 	     with '!' does not mean that this argument is necessarily
899638fd1498Szrj 	     inappropriate for this library: it merely means that
899738fd1498Szrj 	     there is a more specific library which uses this
899838fd1498Szrj 	     argument.  If this argument is a default, we need not
899938fd1498Szrj 	     consider that more specific library.  */
900038fd1498Szrj 	  ok = used_arg (this_arg, p - this_arg);
900138fd1498Szrj 	  if (not_arg)
900238fd1498Szrj 	    ok = ! ok;
900338fd1498Szrj 
900438fd1498Szrj 	  if (! ok)
900538fd1498Szrj 	    ndfltok = 0;
900638fd1498Szrj 
900738fd1498Szrj 	  if (default_arg (this_arg, p - this_arg))
900838fd1498Szrj 	    ok = 1;
900938fd1498Szrj 
901038fd1498Szrj 	  if (*p == ' ')
901138fd1498Szrj 	    ++p;
901238fd1498Szrj 	}
901338fd1498Szrj 
901438fd1498Szrj       if (ok && first)
901538fd1498Szrj 	{
901638fd1498Szrj 	  if (this_path_len != 1
901738fd1498Szrj 	      || this_path[0] != '.')
901838fd1498Szrj 	    {
901938fd1498Szrj 	      char *new_multilib_dir = XNEWVEC (char, this_path_len + 1);
902038fd1498Szrj 	      char *q;
902138fd1498Szrj 
902238fd1498Szrj 	      strncpy (new_multilib_dir, this_path, this_path_len);
902338fd1498Szrj 	      new_multilib_dir[this_path_len] = '\0';
902438fd1498Szrj 	      q = strchr (new_multilib_dir, ':');
902538fd1498Szrj 	      if (q != NULL)
902638fd1498Szrj 		*q = '\0';
902738fd1498Szrj 	      multilib_dir = new_multilib_dir;
902838fd1498Szrj 	    }
902938fd1498Szrj 	  first = 0;
903038fd1498Szrj 	}
903138fd1498Szrj 
903238fd1498Szrj       if (ndfltok)
903338fd1498Szrj 	{
903438fd1498Szrj 	  const char *q = this_path, *end = this_path + this_path_len;
903538fd1498Szrj 
903638fd1498Szrj 	  while (q < end && *q != ':')
903738fd1498Szrj 	    q++;
903838fd1498Szrj 	  if (q < end)
903938fd1498Szrj 	    {
904038fd1498Szrj 	      const char *q2 = q + 1, *ml_end = end;
904138fd1498Szrj 	      char *new_multilib_os_dir;
904238fd1498Szrj 
904338fd1498Szrj 	      while (q2 < end && *q2 != ':')
904438fd1498Szrj 		q2++;
904538fd1498Szrj 	      if (*q2 == ':')
904638fd1498Szrj 		ml_end = q2;
904738fd1498Szrj 	      if (ml_end - q == 1)
904838fd1498Szrj 		multilib_os_dir = xstrdup (".");
904938fd1498Szrj 	      else
905038fd1498Szrj 		{
905138fd1498Szrj 		  new_multilib_os_dir = XNEWVEC (char, ml_end - q);
905238fd1498Szrj 		  memcpy (new_multilib_os_dir, q + 1, ml_end - q - 1);
905338fd1498Szrj 		  new_multilib_os_dir[ml_end - q - 1] = '\0';
905438fd1498Szrj 		  multilib_os_dir = new_multilib_os_dir;
905538fd1498Szrj 		}
905638fd1498Szrj 
905738fd1498Szrj 	      if (q2 < end && *q2 == ':')
905838fd1498Szrj 		{
905938fd1498Szrj 		  char *new_multiarch_dir = XNEWVEC (char, end - q2);
906038fd1498Szrj 		  memcpy (new_multiarch_dir, q2 + 1, end - q2 - 1);
906138fd1498Szrj 		  new_multiarch_dir[end - q2 - 1] = '\0';
906238fd1498Szrj 		  multiarch_dir = new_multiarch_dir;
906338fd1498Szrj 		}
906438fd1498Szrj 	      break;
906538fd1498Szrj 	    }
906638fd1498Szrj 	}
906738fd1498Szrj 
906838fd1498Szrj       ++p;
906938fd1498Szrj     }
907038fd1498Szrj 
907138fd1498Szrj   if (multilib_dir == NULL && multilib_os_dir != NULL
907238fd1498Szrj       && strcmp (multilib_os_dir, ".") == 0)
907338fd1498Szrj     {
907438fd1498Szrj       free (CONST_CAST (char *, multilib_os_dir));
907538fd1498Szrj       multilib_os_dir = NULL;
907638fd1498Szrj     }
907738fd1498Szrj   else if (multilib_dir != NULL && multilib_os_dir == NULL)
907838fd1498Szrj     multilib_os_dir = multilib_dir;
907938fd1498Szrj }
908038fd1498Szrj 
908138fd1498Szrj /* Print out the multiple library subdirectory selection
908238fd1498Szrj    information.  This prints out a series of lines.  Each line looks
908338fd1498Szrj    like SUBDIRECTORY;@OPTION@OPTION, with as many options as is
908438fd1498Szrj    required.  Only the desired options are printed out, the negative
908538fd1498Szrj    matches.  The options are print without a leading dash.  There are
908638fd1498Szrj    no spaces to make it easy to use the information in the shell.
908738fd1498Szrj    Each subdirectory is printed only once.  This assumes the ordering
908838fd1498Szrj    generated by the genmultilib script. Also, we leave out ones that match
908938fd1498Szrj    the exclusions.  */
909038fd1498Szrj 
909138fd1498Szrj static void
print_multilib_info(void)909238fd1498Szrj print_multilib_info (void)
909338fd1498Szrj {
909438fd1498Szrj   const char *p = multilib_select;
909538fd1498Szrj   const char *last_path = 0, *this_path;
909638fd1498Szrj   int skip;
909738fd1498Szrj   unsigned int last_path_len = 0;
909838fd1498Szrj 
909938fd1498Szrj   while (*p != '\0')
910038fd1498Szrj     {
910138fd1498Szrj       skip = 0;
910238fd1498Szrj       /* Ignore newlines.  */
910338fd1498Szrj       if (*p == '\n')
910438fd1498Szrj 	{
910538fd1498Szrj 	  ++p;
910638fd1498Szrj 	  continue;
910738fd1498Szrj 	}
910838fd1498Szrj 
910938fd1498Szrj       /* Get the initial path.  */
911038fd1498Szrj       this_path = p;
911138fd1498Szrj       while (*p != ' ')
911238fd1498Szrj 	{
911338fd1498Szrj 	  if (*p == '\0')
911438fd1498Szrj 	    {
911538fd1498Szrj 	    invalid_select:
911638fd1498Szrj 	      fatal_error (input_location,
911738fd1498Szrj 			   "multilib select %qs is invalid", multilib_select);
911838fd1498Szrj 	    }
911938fd1498Szrj 
912038fd1498Szrj 	  ++p;
912138fd1498Szrj 	}
912238fd1498Szrj 
912338fd1498Szrj       /* When --disable-multilib was used but target defines
912438fd1498Szrj 	 MULTILIB_OSDIRNAMES, entries starting with .: (and not starting
912538fd1498Szrj          with .:: for multiarch configurations) are there just to find
912638fd1498Szrj          multilib_os_dir, so skip them from output.  */
912738fd1498Szrj       if (this_path[0] == '.' && this_path[1] == ':' && this_path[2] != ':')
912838fd1498Szrj 	skip = 1;
912938fd1498Szrj 
913038fd1498Szrj       /* Check for matches with the multilib_exclusions. We don't bother
913138fd1498Szrj          with the '!' in either list. If any of the exclusion rules match
913238fd1498Szrj          all of its options with the select rule, we skip it.  */
913338fd1498Szrj       {
913438fd1498Szrj 	const char *e = multilib_exclusions;
913538fd1498Szrj 	const char *this_arg;
913638fd1498Szrj 
913738fd1498Szrj 	while (*e != '\0')
913838fd1498Szrj 	  {
913938fd1498Szrj 	    int m = 1;
914038fd1498Szrj 	    /* Ignore newlines.  */
914138fd1498Szrj 	    if (*e == '\n')
914238fd1498Szrj 	      {
914338fd1498Szrj 		++e;
914438fd1498Szrj 		continue;
914538fd1498Szrj 	      }
914638fd1498Szrj 
914738fd1498Szrj 	    /* Check the arguments.  */
914838fd1498Szrj 	    while (*e != ';')
914938fd1498Szrj 	      {
915038fd1498Szrj 		const char *q;
915138fd1498Szrj 		int mp = 0;
915238fd1498Szrj 
915338fd1498Szrj 		if (*e == '\0')
915438fd1498Szrj 		  {
915538fd1498Szrj 		  invalid_exclusion:
915638fd1498Szrj 		    fatal_error (input_location,
915738fd1498Szrj 				 "multilib exclusion %qs is invalid",
915838fd1498Szrj 				 multilib_exclusions);
915938fd1498Szrj 		  }
916038fd1498Szrj 
916138fd1498Szrj 		if (! m)
916238fd1498Szrj 		  {
916338fd1498Szrj 		    ++e;
916438fd1498Szrj 		    continue;
916538fd1498Szrj 		  }
916638fd1498Szrj 
916738fd1498Szrj 		this_arg = e;
916838fd1498Szrj 
916938fd1498Szrj 		while (*e != ' ' && *e != ';')
917038fd1498Szrj 		  {
917138fd1498Szrj 		    if (*e == '\0')
917238fd1498Szrj 		      goto invalid_exclusion;
917338fd1498Szrj 		    ++e;
917438fd1498Szrj 		  }
917538fd1498Szrj 
917638fd1498Szrj 		q = p + 1;
917738fd1498Szrj 		while (*q != ';')
917838fd1498Szrj 		  {
917938fd1498Szrj 		    const char *arg;
918038fd1498Szrj 		    int len = e - this_arg;
918138fd1498Szrj 
918238fd1498Szrj 		    if (*q == '\0')
918338fd1498Szrj 		      goto invalid_select;
918438fd1498Szrj 
918538fd1498Szrj 		    arg = q;
918638fd1498Szrj 
918738fd1498Szrj 		    while (*q != ' ' && *q != ';')
918838fd1498Szrj 		      {
918938fd1498Szrj 			if (*q == '\0')
919038fd1498Szrj 			  goto invalid_select;
919138fd1498Szrj 			++q;
919238fd1498Szrj 		      }
919338fd1498Szrj 
919438fd1498Szrj 		    if (! strncmp (arg, this_arg,
919538fd1498Szrj 				   (len < q - arg) ? q - arg : len)
919638fd1498Szrj 			|| default_arg (this_arg, e - this_arg))
919738fd1498Szrj 		      {
919838fd1498Szrj 			mp = 1;
919938fd1498Szrj 			break;
920038fd1498Szrj 		      }
920138fd1498Szrj 
920238fd1498Szrj 		    if (*q == ' ')
920338fd1498Szrj 		      ++q;
920438fd1498Szrj 		  }
920538fd1498Szrj 
920638fd1498Szrj 		if (! mp)
920738fd1498Szrj 		  m = 0;
920838fd1498Szrj 
920938fd1498Szrj 		if (*e == ' ')
921038fd1498Szrj 		  ++e;
921138fd1498Szrj 	      }
921238fd1498Szrj 
921338fd1498Szrj 	    if (m)
921438fd1498Szrj 	      {
921538fd1498Szrj 		skip = 1;
921638fd1498Szrj 		break;
921738fd1498Szrj 	      }
921838fd1498Szrj 
921938fd1498Szrj 	    if (*e != '\0')
922038fd1498Szrj 	      ++e;
922138fd1498Szrj 	  }
922238fd1498Szrj       }
922338fd1498Szrj 
922438fd1498Szrj       if (! skip)
922538fd1498Szrj 	{
922638fd1498Szrj 	  /* If this is a duplicate, skip it.  */
922738fd1498Szrj 	  skip = (last_path != 0
922838fd1498Szrj 		  && (unsigned int) (p - this_path) == last_path_len
922938fd1498Szrj 		  && ! filename_ncmp (last_path, this_path, last_path_len));
923038fd1498Szrj 
923138fd1498Szrj 	  last_path = this_path;
923238fd1498Szrj 	  last_path_len = p - this_path;
923338fd1498Szrj 	}
923438fd1498Szrj 
923538fd1498Szrj       /* If this directory requires any default arguments, we can skip
923638fd1498Szrj 	 it.  We will already have printed a directory identical to
923738fd1498Szrj 	 this one which does not require that default argument.  */
923838fd1498Szrj       if (! skip)
923938fd1498Szrj 	{
924038fd1498Szrj 	  const char *q;
924138fd1498Szrj 
924238fd1498Szrj 	  q = p + 1;
924338fd1498Szrj 	  while (*q != ';')
924438fd1498Szrj 	    {
924538fd1498Szrj 	      const char *arg;
924638fd1498Szrj 
924738fd1498Szrj 	      if (*q == '\0')
924838fd1498Szrj 		goto invalid_select;
924938fd1498Szrj 
925038fd1498Szrj 	      if (*q == '!')
925138fd1498Szrj 		arg = NULL;
925238fd1498Szrj 	      else
925338fd1498Szrj 		arg = q;
925438fd1498Szrj 
925538fd1498Szrj 	      while (*q != ' ' && *q != ';')
925638fd1498Szrj 		{
925738fd1498Szrj 		  if (*q == '\0')
925838fd1498Szrj 		    goto invalid_select;
925938fd1498Szrj 		  ++q;
926038fd1498Szrj 		}
926138fd1498Szrj 
926238fd1498Szrj 	      if (arg != NULL
926338fd1498Szrj 		  && default_arg (arg, q - arg))
926438fd1498Szrj 		{
926538fd1498Szrj 		  skip = 1;
926638fd1498Szrj 		  break;
926738fd1498Szrj 		}
926838fd1498Szrj 
926938fd1498Szrj 	      if (*q == ' ')
927038fd1498Szrj 		++q;
927138fd1498Szrj 	    }
927238fd1498Szrj 	}
927338fd1498Szrj 
927438fd1498Szrj       if (! skip)
927538fd1498Szrj 	{
927638fd1498Szrj 	  const char *p1;
927738fd1498Szrj 
927838fd1498Szrj 	  for (p1 = last_path; p1 < p && *p1 != ':'; p1++)
927938fd1498Szrj 	    putchar (*p1);
928038fd1498Szrj 	  putchar (';');
928138fd1498Szrj 	}
928238fd1498Szrj 
928338fd1498Szrj       ++p;
928438fd1498Szrj       while (*p != ';')
928538fd1498Szrj 	{
928638fd1498Szrj 	  int use_arg;
928738fd1498Szrj 
928838fd1498Szrj 	  if (*p == '\0')
928938fd1498Szrj 	    goto invalid_select;
929038fd1498Szrj 
929138fd1498Szrj 	  if (skip)
929238fd1498Szrj 	    {
929338fd1498Szrj 	      ++p;
929438fd1498Szrj 	      continue;
929538fd1498Szrj 	    }
929638fd1498Szrj 
929738fd1498Szrj 	  use_arg = *p != '!';
929838fd1498Szrj 
929938fd1498Szrj 	  if (use_arg)
930038fd1498Szrj 	    putchar ('@');
930138fd1498Szrj 
930238fd1498Szrj 	  while (*p != ' ' && *p != ';')
930338fd1498Szrj 	    {
930438fd1498Szrj 	      if (*p == '\0')
930538fd1498Szrj 		goto invalid_select;
930638fd1498Szrj 	      if (use_arg)
930738fd1498Szrj 		putchar (*p);
930838fd1498Szrj 	      ++p;
930938fd1498Szrj 	    }
931038fd1498Szrj 
931138fd1498Szrj 	  if (*p == ' ')
931238fd1498Szrj 	    ++p;
931338fd1498Szrj 	}
931438fd1498Szrj 
931538fd1498Szrj       if (! skip)
931638fd1498Szrj 	{
931738fd1498Szrj 	  /* If there are extra options, print them now.  */
931838fd1498Szrj 	  if (multilib_extra && *multilib_extra)
931938fd1498Szrj 	    {
932038fd1498Szrj 	      int print_at = TRUE;
932138fd1498Szrj 	      const char *q;
932238fd1498Szrj 
932338fd1498Szrj 	      for (q = multilib_extra; *q != '\0'; q++)
932438fd1498Szrj 		{
932538fd1498Szrj 		  if (*q == ' ')
932638fd1498Szrj 		    print_at = TRUE;
932738fd1498Szrj 		  else
932838fd1498Szrj 		    {
932938fd1498Szrj 		      if (print_at)
933038fd1498Szrj 			putchar ('@');
933138fd1498Szrj 		      putchar (*q);
933238fd1498Szrj 		      print_at = FALSE;
933338fd1498Szrj 		    }
933438fd1498Szrj 		}
933538fd1498Szrj 	    }
933638fd1498Szrj 
933738fd1498Szrj 	  putchar ('\n');
933838fd1498Szrj 	}
933938fd1498Szrj 
934038fd1498Szrj       ++p;
934138fd1498Szrj     }
934238fd1498Szrj }
934338fd1498Szrj 
934438fd1498Szrj /* getenv built-in spec function.
934538fd1498Szrj 
934638fd1498Szrj    Returns the value of the environment variable given by its first argument,
934738fd1498Szrj    concatenated with the second argument.  If the variable is not defined, a
934838fd1498Szrj    fatal error is issued unless such undefs are internally allowed, in which
934938fd1498Szrj    case the variable name is used as the variable value.  */
935038fd1498Szrj 
935138fd1498Szrj static const char *
getenv_spec_function(int argc,const char ** argv)935238fd1498Szrj getenv_spec_function (int argc, const char **argv)
935338fd1498Szrj {
935438fd1498Szrj   const char *value;
935538fd1498Szrj   const char *varname;
935638fd1498Szrj 
935738fd1498Szrj   char *result;
935838fd1498Szrj   char *ptr;
935938fd1498Szrj   size_t len;
936038fd1498Szrj 
936138fd1498Szrj   if (argc != 2)
936238fd1498Szrj     return NULL;
936338fd1498Szrj 
936438fd1498Szrj   varname = argv[0];
936538fd1498Szrj   value = env.get (varname);
936638fd1498Szrj 
936738fd1498Szrj   if (!value && spec_undefvar_allowed)
936838fd1498Szrj     value = varname;
936938fd1498Szrj 
937038fd1498Szrj   if (!value)
937138fd1498Szrj     fatal_error (input_location,
937238fd1498Szrj 		 "environment variable %qs not defined", varname);
937338fd1498Szrj 
937438fd1498Szrj   /* We have to escape every character of the environment variable so
937538fd1498Szrj      they are not interpreted as active spec characters.  A
937638fd1498Szrj      particularly painful case is when we are reading a variable
937738fd1498Szrj      holding a windows path complete with \ separators.  */
937838fd1498Szrj   len = strlen (value) * 2 + strlen (argv[1]) + 1;
937938fd1498Szrj   result = XNEWVAR (char, len);
938038fd1498Szrj   for (ptr = result; *value; ptr += 2)
938138fd1498Szrj     {
938238fd1498Szrj       ptr[0] = '\\';
938338fd1498Szrj       ptr[1] = *value++;
938438fd1498Szrj     }
938538fd1498Szrj 
938638fd1498Szrj   strcpy (ptr, argv[1]);
938738fd1498Szrj 
938838fd1498Szrj   return result;
938938fd1498Szrj }
939038fd1498Szrj 
939138fd1498Szrj /* if-exists built-in spec function.
939238fd1498Szrj 
939338fd1498Szrj    Checks to see if the file specified by the absolute pathname in
939438fd1498Szrj    ARGS exists.  Returns that pathname if found.
939538fd1498Szrj 
939638fd1498Szrj    The usual use for this function is to check for a library file
939738fd1498Szrj    (whose name has been expanded with %s).  */
939838fd1498Szrj 
939938fd1498Szrj static const char *
if_exists_spec_function(int argc,const char ** argv)940038fd1498Szrj if_exists_spec_function (int argc, const char **argv)
940138fd1498Szrj {
940238fd1498Szrj   /* Must have only one argument.  */
940338fd1498Szrj   if (argc == 1 && IS_ABSOLUTE_PATH (argv[0]) && ! access (argv[0], R_OK))
940438fd1498Szrj     return argv[0];
940538fd1498Szrj 
940638fd1498Szrj   return NULL;
940738fd1498Szrj }
940838fd1498Szrj 
940938fd1498Szrj /* if-exists-else built-in spec function.
941038fd1498Szrj 
941138fd1498Szrj    This is like if-exists, but takes an additional argument which
941238fd1498Szrj    is returned if the first argument does not exist.  */
941338fd1498Szrj 
941438fd1498Szrj static const char *
if_exists_else_spec_function(int argc,const char ** argv)941538fd1498Szrj if_exists_else_spec_function (int argc, const char **argv)
941638fd1498Szrj {
941738fd1498Szrj   /* Must have exactly two arguments.  */
941838fd1498Szrj   if (argc != 2)
941938fd1498Szrj     return NULL;
942038fd1498Szrj 
942138fd1498Szrj   if (IS_ABSOLUTE_PATH (argv[0]) && ! access (argv[0], R_OK))
942238fd1498Szrj     return argv[0];
942338fd1498Szrj 
942438fd1498Szrj   return argv[1];
942538fd1498Szrj }
942638fd1498Szrj 
942738fd1498Szrj /* sanitize built-in spec function.
942838fd1498Szrj 
942938fd1498Szrj    This returns non-NULL, if sanitizing address, thread or
943038fd1498Szrj    any of the undefined behavior sanitizers.  */
943138fd1498Szrj 
943238fd1498Szrj static const char *
sanitize_spec_function(int argc,const char ** argv)943338fd1498Szrj sanitize_spec_function (int argc, const char **argv)
943438fd1498Szrj {
943538fd1498Szrj   if (argc != 1)
943638fd1498Szrj     return NULL;
943738fd1498Szrj 
943838fd1498Szrj   if (strcmp (argv[0], "address") == 0)
943938fd1498Szrj     return (flag_sanitize & SANITIZE_USER_ADDRESS) ? "" : NULL;
944038fd1498Szrj   if (strcmp (argv[0], "kernel-address") == 0)
944138fd1498Szrj     return (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ? "" : NULL;
944238fd1498Szrj   if (strcmp (argv[0], "thread") == 0)
944338fd1498Szrj     return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL;
944438fd1498Szrj   if (strcmp (argv[0], "undefined") == 0)
944538fd1498Szrj     return ((flag_sanitize
944638fd1498Szrj 	     & (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT))
944738fd1498Szrj 	    && !flag_sanitize_undefined_trap_on_error) ? "" : NULL;
944838fd1498Szrj   if (strcmp (argv[0], "leak") == 0)
944938fd1498Szrj     return ((flag_sanitize
945038fd1498Szrj 	     & (SANITIZE_ADDRESS | SANITIZE_LEAK | SANITIZE_THREAD))
945138fd1498Szrj 	    == SANITIZE_LEAK) ? "" : NULL;
945238fd1498Szrj   return NULL;
945338fd1498Szrj }
945438fd1498Szrj 
945538fd1498Szrj /* replace-outfile built-in spec function.
945638fd1498Szrj 
945738fd1498Szrj    This looks for the first argument in the outfiles array's name and
945838fd1498Szrj    replaces it with the second argument.  */
945938fd1498Szrj 
946038fd1498Szrj static const char *
replace_outfile_spec_function(int argc,const char ** argv)946138fd1498Szrj replace_outfile_spec_function (int argc, const char **argv)
946238fd1498Szrj {
946338fd1498Szrj   int i;
946438fd1498Szrj   /* Must have exactly two arguments.  */
946538fd1498Szrj   if (argc != 2)
946638fd1498Szrj     abort ();
946738fd1498Szrj 
946838fd1498Szrj   for (i = 0; i < n_infiles; i++)
946938fd1498Szrj     {
947038fd1498Szrj       if (outfiles[i] && !filename_cmp (outfiles[i], argv[0]))
947138fd1498Szrj 	outfiles[i] = xstrdup (argv[1]);
947238fd1498Szrj     }
947338fd1498Szrj   return NULL;
947438fd1498Szrj }
947538fd1498Szrj 
947638fd1498Szrj /* remove-outfile built-in spec function.
947738fd1498Szrj  *
947838fd1498Szrj  *    This looks for the first argument in the outfiles array's name and
947938fd1498Szrj  *       removes it.  */
948038fd1498Szrj 
948138fd1498Szrj static const char *
remove_outfile_spec_function(int argc,const char ** argv)948238fd1498Szrj remove_outfile_spec_function (int argc, const char **argv)
948338fd1498Szrj {
948438fd1498Szrj   int i;
948538fd1498Szrj   /* Must have exactly one argument.  */
948638fd1498Szrj   if (argc != 1)
948738fd1498Szrj     abort ();
948838fd1498Szrj 
948938fd1498Szrj   for (i = 0; i < n_infiles; i++)
949038fd1498Szrj     {
949138fd1498Szrj       if (outfiles[i] && !filename_cmp (outfiles[i], argv[0]))
949238fd1498Szrj         outfiles[i] = NULL;
949338fd1498Szrj     }
949438fd1498Szrj   return NULL;
949538fd1498Szrj }
949638fd1498Szrj 
949738fd1498Szrj /* Given two version numbers, compares the two numbers.
949838fd1498Szrj    A version number must match the regular expression
949938fd1498Szrj    ([1-9][0-9]*|0)(\.([1-9][0-9]*|0))*
950038fd1498Szrj */
950138fd1498Szrj static int
compare_version_strings(const char * v1,const char * v2)950238fd1498Szrj compare_version_strings (const char *v1, const char *v2)
950338fd1498Szrj {
950438fd1498Szrj   int rresult;
950538fd1498Szrj   regex_t r;
950638fd1498Szrj 
950738fd1498Szrj   if (regcomp (&r, "^([1-9][0-9]*|0)(\\.([1-9][0-9]*|0))*$",
950838fd1498Szrj 	       REG_EXTENDED | REG_NOSUB) != 0)
950938fd1498Szrj     abort ();
951038fd1498Szrj   rresult = regexec (&r, v1, 0, NULL, 0);
951138fd1498Szrj   if (rresult == REG_NOMATCH)
951238fd1498Szrj     fatal_error (input_location, "invalid version number %qs", v1);
951338fd1498Szrj   else if (rresult != 0)
951438fd1498Szrj     abort ();
951538fd1498Szrj   rresult = regexec (&r, v2, 0, NULL, 0);
951638fd1498Szrj   if (rresult == REG_NOMATCH)
951738fd1498Szrj     fatal_error (input_location, "invalid version number %qs", v2);
951838fd1498Szrj   else if (rresult != 0)
951938fd1498Szrj     abort ();
952038fd1498Szrj 
952138fd1498Szrj   return strverscmp (v1, v2);
952238fd1498Szrj }
952338fd1498Szrj 
952438fd1498Szrj 
952538fd1498Szrj /* version_compare built-in spec function.
952638fd1498Szrj 
952738fd1498Szrj    This takes an argument of the following form:
952838fd1498Szrj 
952938fd1498Szrj    <comparison-op> <arg1> [<arg2>] <switch> <result>
953038fd1498Szrj 
953138fd1498Szrj    and produces "result" if the comparison evaluates to true,
953238fd1498Szrj    and nothing if it doesn't.
953338fd1498Szrj 
953438fd1498Szrj    The supported <comparison-op> values are:
953538fd1498Szrj 
953638fd1498Szrj    >=  true if switch is a later (or same) version than arg1
953738fd1498Szrj    !>  opposite of >=
953838fd1498Szrj    <   true if switch is an earlier version than arg1
953938fd1498Szrj    !<  opposite of <
954038fd1498Szrj    ><  true if switch is arg1 or later, and earlier than arg2
954138fd1498Szrj    <>  true if switch is earlier than arg1 or is arg2 or later
954238fd1498Szrj 
954338fd1498Szrj    If the switch is not present, the condition is false unless
954438fd1498Szrj    the first character of the <comparison-op> is '!'.
954538fd1498Szrj 
954638fd1498Szrj    For example,
954738fd1498Szrj    %:version-compare(>= 10.3 mmacosx-version-min= -lmx)
954838fd1498Szrj    adds -lmx if -mmacosx-version-min=10.3.9 was passed.  */
954938fd1498Szrj 
955038fd1498Szrj static const char *
version_compare_spec_function(int argc,const char ** argv)955138fd1498Szrj version_compare_spec_function (int argc, const char **argv)
955238fd1498Szrj {
955338fd1498Szrj   int comp1, comp2;
955438fd1498Szrj   size_t switch_len;
955538fd1498Szrj   const char *switch_value = NULL;
955638fd1498Szrj   int nargs = 1, i;
955738fd1498Szrj   bool result;
955838fd1498Szrj 
955938fd1498Szrj   if (argc < 3)
956038fd1498Szrj     fatal_error (input_location, "too few arguments to %%:version-compare");
956138fd1498Szrj   if (argv[0][0] == '\0')
956238fd1498Szrj     abort ();
956338fd1498Szrj   if ((argv[0][1] == '<' || argv[0][1] == '>') && argv[0][0] != '!')
956438fd1498Szrj     nargs = 2;
956538fd1498Szrj   if (argc != nargs + 3)
956638fd1498Szrj     fatal_error (input_location, "too many arguments to %%:version-compare");
956738fd1498Szrj 
956838fd1498Szrj   switch_len = strlen (argv[nargs + 1]);
956938fd1498Szrj   for (i = 0; i < n_switches; i++)
957038fd1498Szrj     if (!strncmp (switches[i].part1, argv[nargs + 1], switch_len)
957138fd1498Szrj 	&& check_live_switch (i, switch_len))
957238fd1498Szrj       switch_value = switches[i].part1 + switch_len;
957338fd1498Szrj 
957438fd1498Szrj   if (switch_value == NULL)
957538fd1498Szrj     comp1 = comp2 = -1;
957638fd1498Szrj   else
957738fd1498Szrj     {
957838fd1498Szrj       comp1 = compare_version_strings (switch_value, argv[1]);
957938fd1498Szrj       if (nargs == 2)
958038fd1498Szrj 	comp2 = compare_version_strings (switch_value, argv[2]);
958138fd1498Szrj       else
958238fd1498Szrj 	comp2 = -1;  /* This value unused.  */
958338fd1498Szrj     }
958438fd1498Szrj 
958538fd1498Szrj   switch (argv[0][0] << 8 | argv[0][1])
958638fd1498Szrj     {
958738fd1498Szrj     case '>' << 8 | '=':
958838fd1498Szrj       result = comp1 >= 0;
958938fd1498Szrj       break;
959038fd1498Szrj     case '!' << 8 | '<':
959138fd1498Szrj       result = comp1 >= 0 || switch_value == NULL;
959238fd1498Szrj       break;
959338fd1498Szrj     case '<' << 8:
959438fd1498Szrj       result = comp1 < 0;
959538fd1498Szrj       break;
959638fd1498Szrj     case '!' << 8 | '>':
959738fd1498Szrj       result = comp1 < 0 || switch_value == NULL;
959838fd1498Szrj       break;
959938fd1498Szrj     case '>' << 8 | '<':
960038fd1498Szrj       result = comp1 >= 0 && comp2 < 0;
960138fd1498Szrj       break;
960238fd1498Szrj     case '<' << 8 | '>':
960338fd1498Szrj       result = comp1 < 0 || comp2 >= 0;
960438fd1498Szrj       break;
960538fd1498Szrj 
960638fd1498Szrj     default:
960738fd1498Szrj       fatal_error (input_location,
960838fd1498Szrj 		   "unknown operator %qs in %%:version-compare", argv[0]);
960938fd1498Szrj     }
961038fd1498Szrj   if (! result)
961138fd1498Szrj     return NULL;
961238fd1498Szrj 
961338fd1498Szrj   return argv[nargs + 2];
961438fd1498Szrj }
961538fd1498Szrj 
961638fd1498Szrj /* %:include builtin spec function.  This differs from %include in that it
961738fd1498Szrj    can be nested inside a spec, and thus be conditionalized.  It takes
961838fd1498Szrj    one argument, the filename, and looks for it in the startfile path.
961938fd1498Szrj    The result is always NULL, i.e. an empty expansion.  */
962038fd1498Szrj 
962138fd1498Szrj static const char *
include_spec_function(int argc,const char ** argv)962238fd1498Szrj include_spec_function (int argc, const char **argv)
962338fd1498Szrj {
962438fd1498Szrj   char *file;
962538fd1498Szrj 
962638fd1498Szrj   if (argc != 1)
962738fd1498Szrj     abort ();
962838fd1498Szrj 
962938fd1498Szrj   file = find_a_file (&startfile_prefixes, argv[0], R_OK, true);
963038fd1498Szrj   read_specs (file ? file : argv[0], false, false);
963138fd1498Szrj 
963238fd1498Szrj   return NULL;
963338fd1498Szrj }
963438fd1498Szrj 
963538fd1498Szrj /* %:find-file spec function.  This function replaces its argument by
963638fd1498Szrj     the file found through find_file, that is the -print-file-name gcc
963738fd1498Szrj     program option. */
963838fd1498Szrj static const char *
find_file_spec_function(int argc,const char ** argv)963938fd1498Szrj find_file_spec_function (int argc, const char **argv)
964038fd1498Szrj {
964138fd1498Szrj   const char *file;
964238fd1498Szrj 
964338fd1498Szrj   if (argc != 1)
964438fd1498Szrj     abort ();
964538fd1498Szrj 
964638fd1498Szrj   file = find_file (argv[0]);
964738fd1498Szrj   return file;
964838fd1498Szrj }
964938fd1498Szrj 
965038fd1498Szrj 
965138fd1498Szrj /* %:find-plugindir spec function.  This function replaces its argument
965238fd1498Szrj     by the -iplugindir=<dir> option.  `dir' is found through find_file, that
965338fd1498Szrj     is the -print-file-name gcc program option. */
965438fd1498Szrj static const char *
find_plugindir_spec_function(int argc,const char ** argv ATTRIBUTE_UNUSED)965538fd1498Szrj find_plugindir_spec_function (int argc, const char **argv ATTRIBUTE_UNUSED)
965638fd1498Szrj {
965738fd1498Szrj   const char *option;
965838fd1498Szrj 
965938fd1498Szrj   if (argc != 0)
966038fd1498Szrj     abort ();
966138fd1498Szrj 
966238fd1498Szrj   option = concat ("-iplugindir=", find_file ("plugin"), NULL);
966338fd1498Szrj   return option;
966438fd1498Szrj }
966538fd1498Szrj 
966638fd1498Szrj 
966738fd1498Szrj /* %:print-asm-header spec function.  Print a banner to say that the
966838fd1498Szrj    following output is from the assembler.  */
966938fd1498Szrj 
967038fd1498Szrj static const char *
print_asm_header_spec_function(int arg ATTRIBUTE_UNUSED,const char ** argv ATTRIBUTE_UNUSED)967138fd1498Szrj print_asm_header_spec_function (int arg ATTRIBUTE_UNUSED,
967238fd1498Szrj 				const char **argv ATTRIBUTE_UNUSED)
967338fd1498Szrj {
967438fd1498Szrj   printf (_("Assembler options\n=================\n\n"));
967538fd1498Szrj   printf (_("Use \"-Wa,OPTION\" to pass \"OPTION\" to the assembler.\n\n"));
967638fd1498Szrj   fflush (stdout);
967738fd1498Szrj   return NULL;
967838fd1498Szrj }
967938fd1498Szrj 
968038fd1498Szrj /* Get a random number for -frandom-seed */
968138fd1498Szrj 
968238fd1498Szrj static unsigned HOST_WIDE_INT
get_random_number(void)968338fd1498Szrj get_random_number (void)
968438fd1498Szrj {
968538fd1498Szrj   unsigned HOST_WIDE_INT ret = 0;
968638fd1498Szrj   int fd;
968738fd1498Szrj 
968838fd1498Szrj   fd = open ("/dev/urandom", O_RDONLY);
968938fd1498Szrj   if (fd >= 0)
969038fd1498Szrj     {
969138fd1498Szrj       read (fd, &ret, sizeof (HOST_WIDE_INT));
969238fd1498Szrj       close (fd);
969338fd1498Szrj       if (ret)
969438fd1498Szrj         return ret;
969538fd1498Szrj     }
969638fd1498Szrj 
969738fd1498Szrj   /* Get some more or less random data.  */
969838fd1498Szrj #ifdef HAVE_GETTIMEOFDAY
969938fd1498Szrj   {
970038fd1498Szrj     struct timeval tv;
970138fd1498Szrj 
970238fd1498Szrj     gettimeofday (&tv, NULL);
970338fd1498Szrj     ret = tv.tv_sec * 1000 + tv.tv_usec / 1000;
970438fd1498Szrj   }
970538fd1498Szrj #else
970638fd1498Szrj   {
970738fd1498Szrj     time_t now = time (NULL);
970838fd1498Szrj 
970938fd1498Szrj     if (now != (time_t)-1)
971038fd1498Szrj       ret = (unsigned) now;
971138fd1498Szrj   }
971238fd1498Szrj #endif
971338fd1498Szrj 
971438fd1498Szrj   return ret ^ getpid ();
971538fd1498Szrj }
971638fd1498Szrj 
971738fd1498Szrj /* %:compare-debug-dump-opt spec function.  Save the last argument,
971838fd1498Szrj    expected to be the last -fdump-final-insns option, or generate a
971938fd1498Szrj    temporary.  */
972038fd1498Szrj 
972138fd1498Szrj static const char *
compare_debug_dump_opt_spec_function(int arg,const char ** argv ATTRIBUTE_UNUSED)972238fd1498Szrj compare_debug_dump_opt_spec_function (int arg,
972338fd1498Szrj 				      const char **argv ATTRIBUTE_UNUSED)
972438fd1498Szrj {
972538fd1498Szrj   char *ret;
972638fd1498Szrj   char *name;
972738fd1498Szrj   int which;
972838fd1498Szrj   static char random_seed[HOST_BITS_PER_WIDE_INT / 4 + 3];
972938fd1498Szrj 
973038fd1498Szrj   if (arg != 0)
973138fd1498Szrj     fatal_error (input_location,
973238fd1498Szrj 		 "too many arguments to %%:compare-debug-dump-opt");
973338fd1498Szrj 
973438fd1498Szrj   do_spec_2 ("%{fdump-final-insns=*:%*}");
973538fd1498Szrj   do_spec_1 (" ", 0, NULL);
973638fd1498Szrj 
973738fd1498Szrj   if (argbuf.length () > 0
973838fd1498Szrj       && strcmp (argv[argbuf.length () - 1], "."))
973938fd1498Szrj     {
974038fd1498Szrj       if (!compare_debug)
974138fd1498Szrj 	return NULL;
974238fd1498Szrj 
974338fd1498Szrj       name = xstrdup (argv[argbuf.length () - 1]);
974438fd1498Szrj       ret = NULL;
974538fd1498Szrj     }
974638fd1498Szrj   else
974738fd1498Szrj     {
974838fd1498Szrj       const char *ext = NULL;
974938fd1498Szrj 
975038fd1498Szrj       if (argbuf.length () > 0)
975138fd1498Szrj 	{
975238fd1498Szrj 	  do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}");
975338fd1498Szrj 	  ext = ".gkd";
975438fd1498Szrj 	}
975538fd1498Szrj       else if (!compare_debug)
975638fd1498Szrj 	return NULL;
975738fd1498Szrj       else
975838fd1498Szrj 	do_spec_2 ("%g.gkd");
975938fd1498Szrj 
976038fd1498Szrj       do_spec_1 (" ", 0, NULL);
976138fd1498Szrj 
976238fd1498Szrj       gcc_assert (argbuf.length () > 0);
976338fd1498Szrj 
976438fd1498Szrj       name = concat (argbuf.last (), ext, NULL);
976538fd1498Szrj 
976638fd1498Szrj       ret = concat ("-fdump-final-insns=", name, NULL);
976738fd1498Szrj     }
976838fd1498Szrj 
976938fd1498Szrj   which = compare_debug < 0;
977038fd1498Szrj   debug_check_temp_file[which] = name;
977138fd1498Szrj 
977238fd1498Szrj   if (!which)
977338fd1498Szrj     {
977438fd1498Szrj       unsigned HOST_WIDE_INT value = get_random_number ();
977538fd1498Szrj 
977638fd1498Szrj       sprintf (random_seed, HOST_WIDE_INT_PRINT_HEX, value);
977738fd1498Szrj     }
977838fd1498Szrj 
977938fd1498Szrj   if (*random_seed)
978038fd1498Szrj     {
978138fd1498Szrj       char *tmp = ret;
978238fd1498Szrj       ret = concat ("%{!frandom-seed=*:-frandom-seed=", random_seed, "} ",
978338fd1498Szrj 		    ret, NULL);
978438fd1498Szrj       free (tmp);
978538fd1498Szrj     }
978638fd1498Szrj 
978738fd1498Szrj   if (which)
978838fd1498Szrj     *random_seed = 0;
978938fd1498Szrj 
979038fd1498Szrj   return ret;
979138fd1498Szrj }
979238fd1498Szrj 
979338fd1498Szrj static const char *debug_auxbase_opt;
979438fd1498Szrj 
979538fd1498Szrj /* %:compare-debug-self-opt spec function.  Expands to the options
979638fd1498Szrj     that are to be passed in the second compilation of
979738fd1498Szrj     compare-debug.  */
979838fd1498Szrj 
979938fd1498Szrj static const char *
compare_debug_self_opt_spec_function(int arg,const char ** argv ATTRIBUTE_UNUSED)980038fd1498Szrj compare_debug_self_opt_spec_function (int arg,
980138fd1498Szrj 				      const char **argv ATTRIBUTE_UNUSED)
980238fd1498Szrj {
980338fd1498Szrj   if (arg != 0)
980438fd1498Szrj     fatal_error (input_location,
980538fd1498Szrj 		 "too many arguments to %%:compare-debug-self-opt");
980638fd1498Szrj 
980738fd1498Szrj   if (compare_debug >= 0)
980838fd1498Szrj     return NULL;
980938fd1498Szrj 
981038fd1498Szrj   do_spec_2 ("%{c|S:%{o*:%*}}");
981138fd1498Szrj   do_spec_1 (" ", 0, NULL);
981238fd1498Szrj 
981338fd1498Szrj   if (argbuf.length () > 0)
981438fd1498Szrj     debug_auxbase_opt = concat ("-auxbase-strip ",
981538fd1498Szrj 				argbuf.last (),
981638fd1498Szrj 				NULL);
981738fd1498Szrj   else
981838fd1498Szrj     debug_auxbase_opt = NULL;
981938fd1498Szrj 
982038fd1498Szrj   return concat ("\
982138fd1498Szrj %<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
982238fd1498Szrj %<fdump-final-insns=* -w -S -o %j \
982338fd1498Szrj %{!fcompare-debug-second:-fcompare-debug-second} \
982438fd1498Szrj ", compare_debug_opt, NULL);
982538fd1498Szrj }
982638fd1498Szrj 
982738fd1498Szrj /* %:compare-debug-auxbase-opt spec function.  Expands to the auxbase
982838fd1498Szrj     options that are to be passed in the second compilation of
982938fd1498Szrj     compare-debug.  It expects, as an argument, the basename of the
983038fd1498Szrj     current input file name, with the .gk suffix appended to it.  */
983138fd1498Szrj 
983238fd1498Szrj static const char *
compare_debug_auxbase_opt_spec_function(int arg,const char ** argv)983338fd1498Szrj compare_debug_auxbase_opt_spec_function (int arg,
983438fd1498Szrj 					 const char **argv)
983538fd1498Szrj {
983638fd1498Szrj   char *name;
983738fd1498Szrj   int len;
983838fd1498Szrj 
983938fd1498Szrj   if (arg == 0)
984038fd1498Szrj     fatal_error (input_location,
984138fd1498Szrj 		 "too few arguments to %%:compare-debug-auxbase-opt");
984238fd1498Szrj 
984338fd1498Szrj   if (arg != 1)
984438fd1498Szrj     fatal_error (input_location,
984538fd1498Szrj 		 "too many arguments to %%:compare-debug-auxbase-opt");
984638fd1498Szrj 
984738fd1498Szrj   if (compare_debug >= 0)
984838fd1498Szrj     return NULL;
984938fd1498Szrj 
985038fd1498Szrj   len = strlen (argv[0]);
985138fd1498Szrj   if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
985238fd1498Szrj     fatal_error (input_location, "argument to %%:compare-debug-auxbase-opt "
985338fd1498Szrj 		 "does not end in .gk");
985438fd1498Szrj 
985538fd1498Szrj   if (debug_auxbase_opt)
985638fd1498Szrj     return debug_auxbase_opt;
985738fd1498Szrj 
985838fd1498Szrj #define OPT "-auxbase "
985938fd1498Szrj 
986038fd1498Szrj   len -= 3;
986138fd1498Szrj   name = (char*) xmalloc (sizeof (OPT) + len);
986238fd1498Szrj   memcpy (name, OPT, sizeof (OPT) - 1);
986338fd1498Szrj   memcpy (name + sizeof (OPT) - 1, argv[0], len);
986438fd1498Szrj   name[sizeof (OPT) - 1 + len] = '\0';
986538fd1498Szrj 
986638fd1498Szrj #undef OPT
986738fd1498Szrj 
986838fd1498Szrj   return name;
986938fd1498Szrj }
987038fd1498Szrj 
987138fd1498Szrj /* %:pass-through-libs spec function.  Finds all -l options and input
987238fd1498Szrj    file names in the lib spec passed to it, and makes a list of them
987338fd1498Szrj    prepended with the plugin option to cause them to be passed through
987438fd1498Szrj    to the final link after all the new object files have been added.  */
987538fd1498Szrj 
987638fd1498Szrj const char *
pass_through_libs_spec_func(int argc,const char ** argv)987738fd1498Szrj pass_through_libs_spec_func (int argc, const char **argv)
987838fd1498Szrj {
987938fd1498Szrj   char *prepended = xstrdup (" ");
988038fd1498Szrj   int n;
988138fd1498Szrj   /* Shlemiel the painter's algorithm.  Innately horrible, but at least
988238fd1498Szrj      we know that there will never be more than a handful of strings to
988338fd1498Szrj      concat, and it's only once per run, so it's not worth optimising.  */
988438fd1498Szrj   for (n = 0; n < argc; n++)
988538fd1498Szrj     {
988638fd1498Szrj       char *old = prepended;
988738fd1498Szrj       /* Anything that isn't an option is a full path to an output
988838fd1498Szrj          file; pass it through if it ends in '.a'.  Among options,
988938fd1498Szrj 	 pass only -l.  */
989038fd1498Szrj       if (argv[n][0] == '-' && argv[n][1] == 'l')
989138fd1498Szrj 	{
989238fd1498Szrj 	  const char *lopt = argv[n] + 2;
989338fd1498Szrj 	  /* Handle both joined and non-joined -l options.  If for any
989438fd1498Szrj 	     reason there's a trailing -l with no joined or following
989538fd1498Szrj 	     arg just discard it.  */
989638fd1498Szrj 	  if (!*lopt && ++n >= argc)
989738fd1498Szrj 	    break;
989838fd1498Szrj 	  else if (!*lopt)
989938fd1498Szrj 	    lopt = argv[n];
990038fd1498Szrj 	  prepended = concat (prepended, "-plugin-opt=-pass-through=-l",
990138fd1498Szrj 		lopt, " ", NULL);
990238fd1498Szrj 	}
990338fd1498Szrj       else if (!strcmp (".a", argv[n] + strlen (argv[n]) - 2))
990438fd1498Szrj 	{
990538fd1498Szrj 	  prepended = concat (prepended, "-plugin-opt=-pass-through=",
990638fd1498Szrj 		argv[n], " ", NULL);
990738fd1498Szrj 	}
990838fd1498Szrj       if (prepended != old)
990938fd1498Szrj 	free (old);
991038fd1498Szrj     }
991138fd1498Szrj   return prepended;
991238fd1498Szrj }
991338fd1498Szrj 
991438fd1498Szrj /* %:replace-extension spec function.  Replaces the extension of the
991538fd1498Szrj    first argument with the second argument.  */
991638fd1498Szrj 
991738fd1498Szrj const char *
replace_extension_spec_func(int argc,const char ** argv)991838fd1498Szrj replace_extension_spec_func (int argc, const char **argv)
991938fd1498Szrj {
992038fd1498Szrj   char *name;
992138fd1498Szrj   char *p;
992238fd1498Szrj   char *result;
992338fd1498Szrj   int i;
992438fd1498Szrj 
992538fd1498Szrj   if (argc != 2)
992638fd1498Szrj     fatal_error (input_location, "too few arguments to %%:replace-extension");
992738fd1498Szrj 
992838fd1498Szrj   name = xstrdup (argv[0]);
992938fd1498Szrj 
993038fd1498Szrj   for (i = strlen (name) - 1; i >= 0; i--)
993138fd1498Szrj     if (IS_DIR_SEPARATOR (name[i]))
993238fd1498Szrj       break;
993338fd1498Szrj 
993438fd1498Szrj   p = strrchr (name + i + 1, '.');
993538fd1498Szrj   if (p != NULL)
993638fd1498Szrj       *p = '\0';
993738fd1498Szrj 
993838fd1498Szrj   result = concat (name, argv[1], NULL);
993938fd1498Szrj 
994038fd1498Szrj   free (name);
994138fd1498Szrj   return result;
994238fd1498Szrj }
994338fd1498Szrj 
994438fd1498Szrj /* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
994538fd1498Szrj    Otherwise, return NULL.  */
994638fd1498Szrj 
994738fd1498Szrj static const char *
greater_than_spec_func(int argc,const char ** argv)994838fd1498Szrj greater_than_spec_func (int argc, const char **argv)
994938fd1498Szrj {
995038fd1498Szrj   char *converted;
995138fd1498Szrj 
995238fd1498Szrj   if (argc == 1)
995338fd1498Szrj     return NULL;
995438fd1498Szrj 
995538fd1498Szrj   gcc_assert (argc >= 2);
995638fd1498Szrj 
995738fd1498Szrj   long arg = strtol (argv[argc - 2], &converted, 10);
995838fd1498Szrj   gcc_assert (converted != argv[argc - 2]);
995938fd1498Szrj 
996038fd1498Szrj   long lim = strtol (argv[argc - 1], &converted, 10);
996138fd1498Szrj   gcc_assert (converted != argv[argc - 1]);
996238fd1498Szrj 
996338fd1498Szrj   if (arg > lim)
996438fd1498Szrj     return "";
996538fd1498Szrj 
996638fd1498Szrj   return NULL;
996738fd1498Szrj }
996838fd1498Szrj 
996938fd1498Szrj /* Returns "" if debug_info_level is greater than ARGV[ARGC-1].
997038fd1498Szrj    Otherwise, return NULL.  */
997138fd1498Szrj 
997238fd1498Szrj static const char *
debug_level_greater_than_spec_func(int argc,const char ** argv)997338fd1498Szrj debug_level_greater_than_spec_func (int argc, const char **argv)
997438fd1498Szrj {
997538fd1498Szrj   char *converted;
997638fd1498Szrj 
997738fd1498Szrj   if (argc != 1)
997838fd1498Szrj     fatal_error (input_location,
997938fd1498Szrj 		 "wrong number of arguments to %%:debug-level-gt");
998038fd1498Szrj 
998138fd1498Szrj   long arg = strtol (argv[0], &converted, 10);
998238fd1498Szrj   gcc_assert (converted != argv[0]);
998338fd1498Szrj 
998438fd1498Szrj   if (debug_info_level > arg)
998538fd1498Szrj     return "";
998638fd1498Szrj 
998738fd1498Szrj   return NULL;
998838fd1498Szrj }
998938fd1498Szrj 
999038fd1498Szrj /* Insert backslash before spaces in ORIG (usually a file path), to
999138fd1498Szrj    avoid being broken by spec parser.
999238fd1498Szrj 
999338fd1498Szrj    This function is needed as do_spec_1 treats white space (' ' and '\t')
999438fd1498Szrj    as the end of an argument. But in case of -plugin /usr/gcc install/xxx.so,
999538fd1498Szrj    the file name should be treated as a single argument rather than being
999638fd1498Szrj    broken into multiple. Solution is to insert '\\' before the space in a
999738fd1498Szrj    file name.
999838fd1498Szrj 
999938fd1498Szrj    This function converts and only converts all occurrence of ' '
1000038fd1498Szrj    to '\\' + ' ' and '\t' to '\\' + '\t'.  For example:
1000138fd1498Szrj    "a b"  -> "a\\ b"
1000238fd1498Szrj    "a  b" -> "a\\ \\ b"
1000338fd1498Szrj    "a\tb" -> "a\\\tb"
1000438fd1498Szrj    "a\\ b" -> "a\\\\ b"
1000538fd1498Szrj 
1000638fd1498Szrj    orig: input null-terminating string that was allocated by xalloc. The
1000738fd1498Szrj    memory it points to might be freed in this function. Behavior undefined
1000838fd1498Szrj    if ORIG wasn't xalloced or was freed already at entry.
1000938fd1498Szrj 
1001038fd1498Szrj    Return: ORIG if no conversion needed. Otherwise a newly allocated string
1001138fd1498Szrj    that was converted from ORIG.  */
1001238fd1498Szrj 
1001338fd1498Szrj static char *
convert_white_space(char * orig)1001438fd1498Szrj convert_white_space (char *orig)
1001538fd1498Szrj {
1001638fd1498Szrj   int len, number_of_space = 0;
1001738fd1498Szrj 
1001838fd1498Szrj   for (len = 0; orig[len]; len++)
1001938fd1498Szrj     if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
1002038fd1498Szrj 
1002138fd1498Szrj   if (number_of_space)
1002238fd1498Szrj     {
1002338fd1498Szrj       char *new_spec = (char *) xmalloc (len + number_of_space + 1);
1002438fd1498Szrj       int j, k;
1002538fd1498Szrj       for (j = 0, k = 0; j <= len; j++, k++)
1002638fd1498Szrj 	{
1002738fd1498Szrj 	  if (orig[j] == ' ' || orig[j] == '\t')
1002838fd1498Szrj 	    new_spec[k++] = '\\';
1002938fd1498Szrj 	  new_spec[k] = orig[j];
1003038fd1498Szrj 	}
1003138fd1498Szrj       free (orig);
1003238fd1498Szrj       return new_spec;
1003338fd1498Szrj   }
1003438fd1498Szrj   else
1003538fd1498Szrj     return orig;
1003638fd1498Szrj }
1003738fd1498Szrj 
1003838fd1498Szrj static void
path_prefix_reset(path_prefix * prefix)1003938fd1498Szrj path_prefix_reset (path_prefix *prefix)
1004038fd1498Szrj {
1004138fd1498Szrj   struct prefix_list *iter, *next;
1004238fd1498Szrj   iter = prefix->plist;
1004338fd1498Szrj   while (iter)
1004438fd1498Szrj     {
1004538fd1498Szrj       next = iter->next;
1004638fd1498Szrj       free (const_cast <char *> (iter->prefix));
1004738fd1498Szrj       XDELETE (iter);
1004838fd1498Szrj       iter = next;
1004938fd1498Szrj     }
1005038fd1498Szrj   prefix->plist = 0;
1005138fd1498Szrj   prefix->max_len = 0;
1005238fd1498Szrj }
1005338fd1498Szrj 
1005438fd1498Szrj /* Restore all state within gcc.c to the initial state, so that the driver
1005538fd1498Szrj    code can be safely re-run in-process.
1005638fd1498Szrj 
1005738fd1498Szrj    Many const char * variables are referenced by static specs (see
1005838fd1498Szrj    INIT_STATIC_SPEC above).  These variables are restored to their default
1005938fd1498Szrj    values by a simple loop over the static specs.
1006038fd1498Szrj 
1006138fd1498Szrj    For other variables, we directly restore them all to their initial
1006238fd1498Szrj    values (often implicitly 0).
1006338fd1498Szrj 
1006438fd1498Szrj    Free the various obstacks in this file, along with "opts_obstack"
1006538fd1498Szrj    from opts.c.
1006638fd1498Szrj 
1006738fd1498Szrj    This function also restores any environment variables that were changed.  */
1006838fd1498Szrj 
1006938fd1498Szrj void
finalize()1007038fd1498Szrj driver::finalize ()
1007138fd1498Szrj {
1007238fd1498Szrj   env.restore ();
1007338fd1498Szrj   params_c_finalize ();
1007438fd1498Szrj   diagnostic_finish (global_dc);
1007538fd1498Szrj 
1007638fd1498Szrj   is_cpp_driver = 0;
1007738fd1498Szrj   at_file_supplied = 0;
1007838fd1498Szrj   print_help_list = 0;
1007938fd1498Szrj   print_version = 0;
1008038fd1498Szrj   verbose_only_flag = 0;
1008138fd1498Szrj   print_subprocess_help = 0;
1008238fd1498Szrj   use_ld = NULL;
1008338fd1498Szrj   report_times_to_file = NULL;
1008438fd1498Szrj   target_system_root = DEFAULT_TARGET_SYSTEM_ROOT;
1008538fd1498Szrj   target_system_root_changed = 0;
1008638fd1498Szrj   target_sysroot_suffix = 0;
1008738fd1498Szrj   target_sysroot_hdrs_suffix = 0;
1008838fd1498Szrj   save_temps_flag = SAVE_TEMPS_NONE;
1008938fd1498Szrj   save_temps_prefix = 0;
1009038fd1498Szrj   save_temps_length = 0;
1009138fd1498Szrj   spec_machine = DEFAULT_TARGET_MACHINE;
1009238fd1498Szrj   greatest_status = 1;
1009338fd1498Szrj 
1009438fd1498Szrj   finalize_options_struct (&global_options);
1009538fd1498Szrj   finalize_options_struct (&global_options_set);
1009638fd1498Szrj 
1009738fd1498Szrj   obstack_free (&obstack, NULL);
1009838fd1498Szrj   obstack_free (&opts_obstack, NULL); /* in opts.c */
1009938fd1498Szrj   obstack_free (&collect_obstack, NULL);
1010038fd1498Szrj 
1010138fd1498Szrj   link_command_spec = LINK_COMMAND_SPEC;
1010238fd1498Szrj 
1010338fd1498Szrj   obstack_free (&multilib_obstack, NULL);
1010438fd1498Szrj 
1010538fd1498Szrj   user_specs_head = NULL;
1010638fd1498Szrj   user_specs_tail = NULL;
1010738fd1498Szrj 
1010838fd1498Szrj   /* Within the "compilers" vec, the fields "suffix" and "spec" were
1010938fd1498Szrj      statically allocated for the default compilers, but dynamically
1011038fd1498Szrj      allocated for additional compilers.  Delete them for the latter. */
1011138fd1498Szrj   for (int i = n_default_compilers; i < n_compilers; i++)
1011238fd1498Szrj     {
1011338fd1498Szrj       free (const_cast <char *> (compilers[i].suffix));
1011438fd1498Szrj       free (const_cast <char *> (compilers[i].spec));
1011538fd1498Szrj     }
1011638fd1498Szrj   XDELETEVEC (compilers);
1011738fd1498Szrj   compilers = NULL;
1011838fd1498Szrj   n_compilers = 0;
1011938fd1498Szrj 
1012038fd1498Szrj   linker_options.truncate (0);
1012138fd1498Szrj   assembler_options.truncate (0);
1012238fd1498Szrj   preprocessor_options.truncate (0);
1012338fd1498Szrj 
1012438fd1498Szrj   path_prefix_reset (&exec_prefixes);
1012538fd1498Szrj   path_prefix_reset (&startfile_prefixes);
1012638fd1498Szrj   path_prefix_reset (&include_prefixes);
1012738fd1498Szrj 
1012838fd1498Szrj   machine_suffix = 0;
1012938fd1498Szrj   just_machine_suffix = 0;
1013038fd1498Szrj   gcc_exec_prefix = 0;
1013138fd1498Szrj   gcc_libexec_prefix = 0;
1013238fd1498Szrj   md_exec_prefix = MD_EXEC_PREFIX;
1013338fd1498Szrj   md_startfile_prefix = MD_STARTFILE_PREFIX;
1013438fd1498Szrj   md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1;
1013538fd1498Szrj   multilib_dir = 0;
1013638fd1498Szrj   multilib_os_dir = 0;
1013738fd1498Szrj   multiarch_dir = 0;
1013838fd1498Szrj 
1013938fd1498Szrj   /* Free any specs dynamically-allocated by set_spec.
1014038fd1498Szrj      These will be at the head of the list, before the
1014138fd1498Szrj      statically-allocated ones.  */
1014238fd1498Szrj   if (specs)
1014338fd1498Szrj     {
1014438fd1498Szrj       while (specs != static_specs)
1014538fd1498Szrj 	{
1014638fd1498Szrj 	  spec_list *next = specs->next;
1014738fd1498Szrj 	  free (const_cast <char *> (specs->name));
1014838fd1498Szrj 	  XDELETE (specs);
1014938fd1498Szrj 	  specs = next;
1015038fd1498Szrj 	}
1015138fd1498Szrj       specs = 0;
1015238fd1498Szrj     }
1015338fd1498Szrj   for (unsigned i = 0; i < ARRAY_SIZE (static_specs); i++)
1015438fd1498Szrj     {
1015538fd1498Szrj       spec_list *sl = &static_specs[i];
1015638fd1498Szrj       if (sl->alloc_p)
1015738fd1498Szrj 	{
1015838fd1498Szrj 	  if (0)
1015938fd1498Szrj 	    free (const_cast <char *> (*(sl->ptr_spec)));
1016038fd1498Szrj 	  sl->alloc_p = false;
1016138fd1498Szrj 	}
1016238fd1498Szrj       *(sl->ptr_spec) = sl->default_ptr;
1016338fd1498Szrj     }
1016438fd1498Szrj #ifdef EXTRA_SPECS
1016538fd1498Szrj   extra_specs = NULL;
1016638fd1498Szrj #endif
1016738fd1498Szrj 
1016838fd1498Szrj   processing_spec_function = 0;
1016938fd1498Szrj 
1017038fd1498Szrj   argbuf.truncate (0);
1017138fd1498Szrj 
1017238fd1498Szrj   have_c = 0;
1017338fd1498Szrj   have_o = 0;
1017438fd1498Szrj 
1017538fd1498Szrj   temp_names = NULL;
1017638fd1498Szrj   execution_count = 0;
1017738fd1498Szrj   signal_count = 0;
1017838fd1498Szrj 
1017938fd1498Szrj   temp_filename = NULL;
1018038fd1498Szrj   temp_filename_length = 0;
1018138fd1498Szrj   always_delete_queue = NULL;
1018238fd1498Szrj   failure_delete_queue = NULL;
1018338fd1498Szrj 
1018438fd1498Szrj   XDELETEVEC (switches);
1018538fd1498Szrj   switches = NULL;
1018638fd1498Szrj   n_switches = 0;
1018738fd1498Szrj   n_switches_alloc = 0;
1018838fd1498Szrj 
1018938fd1498Szrj   compare_debug = 0;
1019038fd1498Szrj   compare_debug_second = 0;
1019138fd1498Szrj   compare_debug_opt = NULL;
1019238fd1498Szrj   for (int i = 0; i < 2; i++)
1019338fd1498Szrj     {
1019438fd1498Szrj       switches_debug_check[i] = NULL;
1019538fd1498Szrj       n_switches_debug_check[i] = 0;
1019638fd1498Szrj       n_switches_alloc_debug_check[i] = 0;
1019738fd1498Szrj       debug_check_temp_file[i] = NULL;
1019838fd1498Szrj     }
1019938fd1498Szrj 
1020038fd1498Szrj   XDELETEVEC (infiles);
1020138fd1498Szrj   infiles = NULL;
1020238fd1498Szrj   n_infiles = 0;
1020338fd1498Szrj   n_infiles_alloc = 0;
1020438fd1498Szrj 
1020538fd1498Szrj   combine_inputs = false;
1020638fd1498Szrj   added_libraries = 0;
1020738fd1498Szrj   XDELETEVEC (outfiles);
1020838fd1498Szrj   outfiles = NULL;
1020938fd1498Szrj   spec_lang = 0;
1021038fd1498Szrj   last_language_n_infiles = 0;
1021138fd1498Szrj   gcc_input_filename = NULL;
1021238fd1498Szrj   input_file_number = 0;
1021338fd1498Szrj   input_filename_length = 0;
1021438fd1498Szrj   basename_length = 0;
1021538fd1498Szrj   suffixed_basename_length = 0;
1021638fd1498Szrj   input_basename = NULL;
1021738fd1498Szrj   input_suffix = NULL;
1021838fd1498Szrj   /* We don't need to purge "input_stat", just to unset "input_stat_set".  */
1021938fd1498Szrj   input_stat_set = 0;
1022038fd1498Szrj   input_file_compiler = NULL;
1022138fd1498Szrj   arg_going = 0;
1022238fd1498Szrj   delete_this_arg = 0;
1022338fd1498Szrj   this_is_output_file = 0;
1022438fd1498Szrj   this_is_library_file = 0;
1022538fd1498Szrj   this_is_linker_script = 0;
1022638fd1498Szrj   input_from_pipe = 0;
1022738fd1498Szrj   suffix_subst = NULL;
1022838fd1498Szrj 
1022938fd1498Szrj   mdswitches = NULL;
1023038fd1498Szrj   n_mdswitches = 0;
1023138fd1498Szrj 
1023238fd1498Szrj   debug_auxbase_opt = NULL;
1023338fd1498Szrj 
1023438fd1498Szrj   used_arg.finalize ();
1023538fd1498Szrj }
1023638fd1498Szrj 
1023738fd1498Szrj /* PR jit/64810.
1023838fd1498Szrj    Targets can provide configure-time default options in
1023938fd1498Szrj    OPTION_DEFAULT_SPECS.  The jit needs to access these, but
1024038fd1498Szrj    they are expressed in the spec language.
1024138fd1498Szrj 
1024238fd1498Szrj    Run just enough of the driver to be able to expand these
1024338fd1498Szrj    specs, and then call the callback CB on each
1024438fd1498Szrj    such option.  The options strings are *without* a leading
1024538fd1498Szrj    '-' character e.g. ("march=x86-64").  Finally, clean up.  */
1024638fd1498Szrj 
1024738fd1498Szrj void
driver_get_configure_time_options(void (* cb)(const char * option,void * user_data),void * user_data)1024838fd1498Szrj driver_get_configure_time_options (void (*cb) (const char *option,
1024938fd1498Szrj 					       void *user_data),
1025038fd1498Szrj 				   void *user_data)
1025138fd1498Szrj {
1025238fd1498Szrj   size_t i;
1025338fd1498Szrj 
1025438fd1498Szrj   obstack_init (&obstack);
1025538fd1498Szrj   init_opts_obstack ();
1025638fd1498Szrj   n_switches = 0;
1025738fd1498Szrj 
1025838fd1498Szrj   for (i = 0; i < ARRAY_SIZE (option_default_specs); i++)
1025938fd1498Szrj     do_option_spec (option_default_specs[i].name,
1026038fd1498Szrj 		    option_default_specs[i].spec);
1026138fd1498Szrj 
1026238fd1498Szrj   for (i = 0; (int) i < n_switches; i++)
1026338fd1498Szrj     {
1026438fd1498Szrj       gcc_assert (switches[i].part1);
1026538fd1498Szrj       (*cb) (switches[i].part1, user_data);
1026638fd1498Szrj     }
1026738fd1498Szrj 
1026838fd1498Szrj   obstack_free (&opts_obstack, NULL);
1026938fd1498Szrj   obstack_free (&obstack, NULL);
1027038fd1498Szrj   n_switches = 0;
1027138fd1498Szrj }
10272