diff mbox

[RFC] Add configuration support for additional executable/library directories

Message ID 20120531165330.GA13831@ibm-tiger.the-meissners.org
State New
Headers show

Commit Message

Michael Meissner May 31, 2012, 4:53 p.m. UTC
For some time now, I've wanted to add configuration support to add additional
directories for the compiler to search automatically, without having to edit
local files in my directory.

I have some questions about these patches, that I will put after the
explanation of the functionality.

One of the motivations is to tie into the installed IBM Advance Toolchain (AT),
which provides newer compilers and libraries to Power customers who need
facilities in the newer compilers, that aren't yet a part of the standard GCC
that is shipped with the distribution.  While the AT is a motivation, I'm
trying to write these patches to be more general.

The AT provides its own libraries, both static and shared that are built for
serveral different targets (power5, power6, power7, etc.).  It is not a
--sysroot type of release, because if a given library is not provided, it will
default to using the host libraries on the system.  The AT has its own dynamic
linker as well as the normal binutils and compiler binaries.

These patches add 4 configuration switches that add additional directories to
the search paths:

--with-extra-exec-prefix=<dirs>

	Add extra directories to the executable search path.  You can have more
	that one directory, separated by colon's (":").  For example, to use
	the binaries in /opt/at5.0/bin, I would do:

		--with-extra-exec-prefix=/opt/at5.0/bin

--with-extra-startfile-prefix=<dirs>

	Add extra directories to the startfile and library search path.  You
	can have more than one directory, separated by colon's.  In multilib
	systems, the multilib prefix will be appended to this prefix to find
	the correct multilib.  For example to use the libraries and startfiles
	in /opt/at5.0/lib, I would do:

		--with-extra-startfile-prefix=/opt/at5.0/lib

--with-extra-rpath-prefix=<dirs>

	Add extra directories via -rpath unless -static is used when linking.
	Like the startfile prefix, this is appended with the current multilib
	prefix to get the appropriate directory.  For example, with the Advance
	Toolchain 5.0, I would use:

		--with-extra-rpath-prefix=/opt/at5.0/lib

--with-extra-prefixes=<dirs>

	This is a combination option, that sets --with-extra-exec-prefixes,
	--with-extra-startfile-prefixes, and --with-extra-rpath-prefixes if
	they were not already set.  For example:

		--with-extra-prefix=/opt/at5.0:/opt/at4.0

	would be equivalent to:

		--with-extra-exec-prefix=/opt/at5.0/bin:/opt/at4.0/bin
		--with-extra-startfile-prefix=/opt/at5.0/lib:/opt/at4.0/lib
		--with-extra-rpath-prefix=/opt/at5.0/lib:/opt/at4.0/lib

In the machine independent part of the patches, it will use the exec prefixes
to look up executables, it will add -L <dir> for each of the startfile prefixed
directories when linking, and if -static is not used will add -rpath for each
of the directories in the rpath directories.

In the powerpc part of the patches, it will add code to look up the dynamic
linker in the prefixes, and to add -L<dir>/<machine> if the user did
-mcpu=<machine> and -static to pick up the machine specific static libraries.
This code uses spec functions provided by gcc.c, so it is fairly easy to add
similar support to other targets.

My questions are:

1) Do people want this functionality in GCC?  If it isn't desirable to put in
   the general options, would people have objections if I put in
   powerpc64-linux specific configure options to accomplish the same thing?

2) In terms of the shared library paths, I am not up on all of the ins and outs
   of the various ways these paths get set (via -rpath=, -rpath-dir=, looking
   at LD_RUN_PATH if -rpath is not specified, and with/without the option
   --enable-new-dtags).  Is the current patch appropriate, or are there better
   ways to add directories to the path?  The current path adds the directories
   via -rpath.  If LD_RUN_PATH is set, it will also add the directories in
   LD_RUN_PATH, since the linker will only look at LD_RUN_PATH if -rpath is not
   set. 

3) Should I include a prefix option for finding include files?

4) Did we want to update other backends to look at dynamic linkers and machine
   dependent static libraries like I did for the powerpc.

Here is the ChangeLog.

2012-05-30  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* doc/install.texi (--with-extra-prefix=): Add new configuration
	switches to specify alternate compiler binary, startfile and
	library directories at configure time.  This allows the configured
	compiler to use these alternate paths ahead of the standard paths,
	but to fall back to using the standard paths if the executable or
	library doesn't exist.  For static links, support a new spec
	function to allow the backend to specify machine dependent
	subdirectories to get access to a library compiled for a
	particular machine.  For dynamic libraries, add the extra library
	directories to the dynamic linker search path via -rpath.  On the
	powerpc, find the dynamic linker in the extra search paths.  Merge
	common code together in gcc.c for doing path lookups on colon
	separated environment variables.
	(--with-extra-exec-prefix=): Likewise.
	(--with-extra-startfile-prefix=): Likewise.
	(--with-extra-rpath-prefix=): Likewise.
	* gcc.c (find_dynamic_linker_spec_function): Likewise.
	(extra_rpath_dirs_spec_function): Likewise.
	(extra_cpu_dirs_spec_function): Likewise.
	(LINK_COMMAND_SPEC): Likewise.
	(configure_startfile_prefix): Likewise.
	(configure_exec_prefix): Likewise.
	(static_spec_functions): Likewise.
	(add_multiple_prefix): Likewise.
	(process_command): Likewise.
	(config_rpath): Likewise.
	(build_rpath_or_cpu_dirs): Likewise.
	* gcc.h (extra_cpu_dirs_spec_function): Likewise.
	* config.in (CONFIGURE_EXEC_PREFIX): Likewise.
	(CONFIGURE_STARTFILE_PREFIX): Likewise.
	* configure.ac (--with-extra-prefix=): Likewise.
	(--with-extra-exec-prefix=): Likewise.
	(--with-extra-startfile-prefix=): Likewise.
	(--with-extra-rpath-prefix=): Likewise.
	* config/rs6000/x-rs6000 (driver-rs6000.o): Likewise.
	* config/rs6000/linux64.h (GLIBC_DYNAMIC_LINKER32) Likewise.
	(GLIBC_DYNAMIC_LINKER64): Likewise.
	(LINUX_EXTRA_STATIC_LIBDIRS64): Likewise.
	(LINUX_EXTRA_STATIC_LIBDIRS32): Likewise.
	(LINK_OS_LINUX_SPEC32): Likewise.
	(LINK_OS_LINUX_SPEC64): Likewise.
	* config/rs6000/rs6000.h (LOCAL_CPU_EXTRA_SPEC_FUNCTIONS):
	Likewise.
	(EXTRA_SPEC_FUNCTIONS): Likewise.
	* config/rs6000/driver-rs6000.c (rs6000_extra_static_libdirs):
	Likewise.
	* config/rs6000/sysv4.h (GLIBC_DYNAMIC_LINKER): Likewise.
	(LINK_OS_LINUX_SPEC): Likewise.
	(LINUX_EXTRA_STATIC_LIBDIRS32): Likewise.
	(LINK_OS_LINUX_SPEC): Likewise.
	(rs6000_extra_static_libdirs): Likewise.
	(SUBTARGET_EXTRA_SPEC_FUNCTIONS): Likewise.
diff mbox

Patch

Index: gcc/doc/install.texi
===================================================================
--- gcc/doc/install.texi	(revision 188026)
+++ gcc/doc/install.texi	(working copy)
@@ -767,6 +767,44 @@  from the full GCC manuals, which are pro
 are derived by an automatic conversion process from parts of the full
 manual.)
 
+@item --with-extra-prefix=@var{prefix}
+Specify an additional prefix for finding executables, libraries, and
+startfiles when the compiler is run.  By default no extra
+prefixes are used.  This option sets the options
+@option{--with-extra-exec-prefix=},
+@option{--with-extra-startfiles-prefix=},
+and @option{--with-extra-rpath-prefix=} if they are not specified.
+
+@item --with-extra-exec-prefix=@var{prefixes}
+Specify additional prefixes for finding executables when the compiler
+is run.  Each prefix is separated by the standard path sepator
+(usually colon, @option{:}).  By default no extra prefixes are used.
+
+@item --with-extra-startfile-prefix=@var{prefixes}
+Specify additional prefixes for finding libraries, and startfiles when
+the compiler is run.  Each prefix is separated by the standard path
+sepator (usually colon, @option{:}).  By default no extra prefixes are
+used.
+
+On powerpc64-linux systems, the dynamic linker will be searched for in
+the directories specified by the prefixed, that is used instead of the
+standard system dynamic linker.
+
+In addition on powerpc64-linux systems, if the user used static
+linking, as well as the @option{-mcpu=} option, the linker will be
+told to search in appropriate directories for libraries that are built
+for that particular machine.  If dynamic linking is used, these cpu
+tuned libraries will not be searched, since the dynamic linker will
+load the appropriate cpu tuned library, based on the system that is
+executing the code.
+
+@item --with-extra-rpath-prefix=@var{prefixes}
+Specify additional directories for finding shared libraries when
+the compiler is run.  Each prefix is separated by the standard path
+sepator (usually colon, @option{:}).  By default no extra prefixes are
+used.  If this option is used, each of the directories if they exist
+will be specified to the linker via the @option{-rpath=} option.
+
 @item --with-gxx-include-dir=@var{dirname}
 Specify
 the installation directory for G++ header files.  The default depends
Index: gcc/configure
===================================================================
--- gcc/configure	(revision 188026)
+++ gcc/configure	(working copy)
@@ -893,6 +893,10 @@  with_multilib_list
 enable_rpath
 with_libiconv_prefix
 enable_sjlj_exceptions
+with_extra_prefix
+with_extra_exec_prefix
+with_extra_startfile_prefix
+with_extra_rpath_prefix
 enable_secureplt
 enable_leading_mingw64_underscores
 enable_cld
@@ -1660,6 +1664,18 @@  Optional Packages:
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
   --without-libiconv-prefix     don't search for libiconv in includedir and libdir
+  --with-extra-prefix={prefixes}
+                          Add extra prefixes to the list of locations to
+                          search for all files
+  --with-extra-exec-prefix={prefixes}
+                          Add extra prefixes to the list of locations to
+                          search for executables
+  --with-extra-startfile-prefix={prefix}
+                          Add extra prefixes to the list of locations to
+                          search for startfiles
+  --with-extra-rpath-prefix={prefixes}
+                          Specify prefixes to pass to the linker via
+                          -rpath=dir to locate shared libraries
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
@@ -11507,6 +11523,78 @@  case "$LIBINTL" in *$LIBICONV*)
 	LIBICONV= ;;
 esac
 
+
+# Check whether --with-extra-prefix was given.
+if test "${with_extra_prefix+set}" = set; then :
+  withval=$with_extra_prefix; EXTRA_PREFIX="$withval"
+else
+  EXTRA_PREFIX=''
+fi
+
+
+
+# Check whether --with-extra-exec-prefix was given.
+if test "${with_extra_exec_prefix+set}" = set; then :
+  withval=$with_extra_exec_prefix; EXTRA_EXEC_PREFIX="$withval"
+else
+  if test x"${EXTRA_PREFIX}" != x; then
+    EXTRA_EXEC_PREFIX="`echo ${EXTRA_PREFIX} | sed 's/:/\\/bin:/g'`/bin"
+  else
+    EXTRA_EXEC_PREFIX=""
+  fi
+fi
+
+
+if test x"${EXTRA_EXEC_PREFIX}" != x; then
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGURE_EXEC_PREFIX "$EXTRA_EXEC_PREFIX"
+_ACEOF
+
+fi
+
+
+# Check whether --with-extra-startfile-prefix was given.
+if test "${with_extra_startfile_prefix+set}" = set; then :
+  withval=$with_extra_startfile_prefix; EXTRA_STARTFILE_PREFIX="$withval"
+else
+  if test x"${EXTRA_PREFIX}" != x; then
+    EXTRA_STARTFILE_PREFIX="`echo ${EXTRA_PREFIX} | sed 's/:/\\/lib:/g'`/lib"
+  else
+    EXTRA_STARTFILE_PREFIX=""
+  fi
+fi
+
+
+if test x"${EXTRA_STARTFILE_PREFIX}" != x; then
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGURE_STARTFILE_PREFIX "$EXTRA_STARTFILE_PREFIX"
+_ACEOF
+
+fi
+
+
+# Check whether --with-extra-rpath-prefix was given.
+if test "${with_extra_rpath_prefix+set}" = set; then :
+  withval=$with_extra_rpath_prefix; EXTRA_RPATH_PREFIX="$withval"
+else
+  if test x"${EXTRA_PREFIX}" != x; then
+    EXTRA_RPATH_PREFIX="${prefix}/lib:`echo ${EXTRA_PREFIX} | sed 's/:/\\/lib:/g'`/lib"
+  else
+    EXTRA_RPATH_PREFIX=""
+  fi
+fi
+
+
+if test x"${EXTRA_RPATH_PREFIX}" != x; then
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGURE_RPATH_PREFIX "$EXTRA_RPATH_PREFIX"
+_ACEOF
+
+fi
+
 # Check whether --enable-secureplt was given.
 if test "${enable_secureplt+set}" = set; then :
   enableval=$enable_secureplt;
@@ -17967,7 +18055,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 17970 "configure"
+#line 18058 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18073,7 +18161,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18076 "configure"
+#line 18164 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 188026)
+++ gcc/gcc.c	(working copy)
@@ -202,6 +202,8 @@  static int access_check (const char *, i
 static char *find_a_file (const struct path_prefix *, const char *, int, bool);
 static void add_prefix (struct path_prefix *, const char *, const char *,
 			int, int, int);
+static void add_multiple_prefix (struct path_prefix *, const char *,
+				 const char *, int, int, int);
 static void add_sysrooted_prefix (struct path_prefix *, const char *,
 				  const char *, int, int, int);
 static char *skip_whitespace (char *);
@@ -261,12 +263,15 @@  static const char *remove_outfile_spec_f
 static const char *version_compare_spec_function (int, const char **);
 static const char *include_spec_function (int, const char **);
 static const char *find_file_spec_function (int, const char **);
+static const char *find_dynamic_linker_spec_function (int, const char **);
 static const char *find_plugindir_spec_function (int, const char **);
 static const char *print_asm_header_spec_function (int, const char **);
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
 static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
 static const char *pass_through_libs_spec_func (int, const char **);
+static const char *extra_rpath_dirs_spec_function (int, const char **);
+const char *extra_cpu_dirs_spec_function (int, const char **);
 
 /* The Specs Language
 
@@ -656,6 +661,16 @@  proper position among the other output f
 #endif
 
 
+#ifndef LINK_RPATH_DIRS_SPEC
+#ifdef CONFIGURE_RPATH_PREFIX
+/* Add extra -rpath= options if configured.  */
+#define LINK_RPATH_DIRS_SPEC \
+  "%{!nostdlib:%{!nodefaultlibs:%{!static: %:extra-rpath-dirs()}}}"
+#else
+#define LINK_RPATH_DIRS_SPEC
+#endif
+#endif
+
 /* -u* was put back because both BSD and SysV seem to support it.  */
 /* %{static:} simply prevents an error message if the target machine
    doesn't handle -static.  */
@@ -669,6 +684,7 @@  proper position among the other output f
 #define LINK_COMMAND_SPEC "\
 %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
     %(linker) " \
+    LINK_RPATH_DIRS_SPEC \
     LINK_PLUGIN_SPEC \
     "%{flto|flto=*:%<fcompare-debug*} \
     %{flto} %{flto=*} %l " LINK_PIE_SPEC \
@@ -1102,6 +1118,14 @@  static const char *gcc_libexec_prefix;
 #define STANDARD_STARTFILE_PREFIX_2 "/usr/lib/"
 #endif
 
+/* Additional directories added at configure time.  */
+#ifndef CONFIGURE_STARTFILE_PREFIX
+#define CONFIGURE_STARTFILE_PREFIX ""
+#endif
+#ifndef CONFIGURE_EXEC_PREFIX
+#define CONFIGURE_EXEC_PREFIX ""
+#endif
+
 #ifdef CROSS_DIRECTORY_STRUCTURE  /* Don't use these prefixes for a cross compiler.  */
 #undef MD_EXEC_PREFIX
 #undef MD_STARTFILE_PREFIX
@@ -1140,6 +1164,10 @@  static const char *const standard_startf
   = STANDARD_STARTFILE_PREFIX_1;
 static const char *const standard_startfile_prefix_2
   = STANDARD_STARTFILE_PREFIX_2;
+static const char *const configure_startfile_prefix
+  = CONFIGURE_STARTFILE_PREFIX;
+static const char *const configure_exec_prefix
+  = CONFIGURE_EXEC_PREFIX;
 
 /* A relative path to be used in finding the location of tools
    relative to the driver.  */
@@ -1255,12 +1283,15 @@  static const struct spec_function static
   { "version-compare",		version_compare_spec_function },
   { "include",			include_spec_function },
   { "find-file",		find_file_spec_function },
+  { "find-dynamic-linker",	find_dynamic_linker_spec_function },
   { "find-plugindir",		find_plugindir_spec_function },
   { "print-asm-header",		print_asm_header_spec_function },
   { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
   { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
   { "pass-through-libs",	pass_through_libs_spec_func },
+  { "extra-rpath-dirs",		extra_rpath_dirs_spec_function },
+  { "extra-cpu-dirs",		extra_cpu_dirs_spec_function },
 #ifdef EXTRA_SPEC_FUNCTIONS
   EXTRA_SPEC_FUNCTIONS
 #endif
@@ -2439,6 +2470,44 @@  add_prefix (struct path_prefix *pprefix,
   (*prev) = pl;
 }
 
+/* Same as add_prefix, but split the prefix at each PATH_SEPARATOR.  */
+static void
+add_multiple_prefix (struct path_prefix *pprefix, const char *prefix,
+		     const char *component,
+		     /* enum prefix_priority */ int priority,
+		     int require_machine_suffix, int os_multilib)
+{
+  const char *startp, *endp;
+  char *nstore = (char *) alloca (strlen (prefix) + 3);
+
+  startp = endp = prefix;
+  while (1)
+    {
+      if (*endp == PATH_SEPARATOR || *endp == 0)
+	{
+	  strncpy (nstore, startp, endp - startp);
+	  if (endp == startp)
+	    strcpy (nstore, concat (".", dir_separator_str, NULL));
+	  else if (!IS_DIR_SEPARATOR (endp[-1]))
+	    {
+	      nstore[endp - startp] = DIR_SEPARATOR;
+	      nstore[endp - startp + 1] = 0;
+	    }
+	  else
+	    nstore[endp - startp] = 0;
+	  add_prefix (pprefix, nstore, component, priority,
+		      require_machine_suffix, os_multilib);
+	  if (*endp == 0)
+	    break;
+	  endp = startp = endp + 1;
+	}
+      else
+	endp++;
+    }
+
+  return;
+}
+
 /* Same as add_prefix, but prepending target_system_root to prefix.  */
 /* The target_system_root prefix has been relocated by gcc_exec_prefix.  */
 static void
@@ -3672,101 +3741,22 @@  process_command (unsigned int decoded_op
   temp = getenv ("COMPILER_PATH");
   if (temp)
     {
-      const char *startp, *endp;
-      char *nstore = (char *) alloca (strlen (temp) + 3);
-
-      startp = endp = temp;
-      while (1)
-	{
-	  if (*endp == PATH_SEPARATOR || *endp == 0)
-	    {
-	      strncpy (nstore, startp, endp - startp);
-	      if (endp == startp)
-		strcpy (nstore, concat (".", dir_separator_str, NULL));
-	      else if (!IS_DIR_SEPARATOR (endp[-1]))
-		{
-		  nstore[endp - startp] = DIR_SEPARATOR;
-		  nstore[endp - startp + 1] = 0;
-		}
-	      else
-		nstore[endp - startp] = 0;
-	      add_prefix (&exec_prefixes, nstore, 0,
-			  PREFIX_PRIORITY_LAST, 0, 0);
-	      add_prefix (&include_prefixes, nstore, 0,
-			  PREFIX_PRIORITY_LAST, 0, 0);
-	      if (*endp == 0)
-		break;
-	      endp = startp = endp + 1;
-	    }
-	  else
-	    endp++;
-	}
+      add_multiple_prefix (&exec_prefixes, temp, 0,
+			   PREFIX_PRIORITY_LAST, 0, 0);
+      add_multiple_prefix (&include_prefixes, temp, 0,
+			   PREFIX_PRIORITY_LAST, 0, 0);
     }
 
   temp = getenv (LIBRARY_PATH_ENV);
   if (temp && *cross_compile == '0')
-    {
-      const char *startp, *endp;
-      char *nstore = (char *) alloca (strlen (temp) + 3);
-
-      startp = endp = temp;
-      while (1)
-	{
-	  if (*endp == PATH_SEPARATOR || *endp == 0)
-	    {
-	      strncpy (nstore, startp, endp - startp);
-	      if (endp == startp)
-		strcpy (nstore, concat (".", dir_separator_str, NULL));
-	      else if (!IS_DIR_SEPARATOR (endp[-1]))
-		{
-		  nstore[endp - startp] = DIR_SEPARATOR;
-		  nstore[endp - startp + 1] = 0;
-		}
-	      else
-		nstore[endp - startp] = 0;
-	      add_prefix (&startfile_prefixes, nstore, NULL,
-			  PREFIX_PRIORITY_LAST, 0, 1);
-	      if (*endp == 0)
-		break;
-	      endp = startp = endp + 1;
-	    }
-	  else
-	    endp++;
-	}
-    }
+    add_multiple_prefix (&startfile_prefixes, temp, NULL,
+			 PREFIX_PRIORITY_LAST, 0, 1);
 
   /* Use LPATH like LIBRARY_PATH (for the CMU build program).  */
   temp = getenv ("LPATH");
   if (temp && *cross_compile == '0')
-    {
-      const char *startp, *endp;
-      char *nstore = (char *) alloca (strlen (temp) + 3);
-
-      startp = endp = temp;
-      while (1)
-	{
-	  if (*endp == PATH_SEPARATOR || *endp == 0)
-	    {
-	      strncpy (nstore, startp, endp - startp);
-	      if (endp == startp)
-		strcpy (nstore, concat (".", dir_separator_str, NULL));
-	      else if (!IS_DIR_SEPARATOR (endp[-1]))
-		{
-		  nstore[endp - startp] = DIR_SEPARATOR;
-		  nstore[endp - startp + 1] = 0;
-		}
-	      else
-		nstore[endp - startp] = 0;
-	      add_prefix (&startfile_prefixes, nstore, NULL,
-			  PREFIX_PRIORITY_LAST, 0, 1);
-	      if (*endp == 0)
-		break;
-	      endp = startp = endp + 1;
-	    }
-	  else
-	    endp++;
-	}
-    }
+    add_multiple_prefix (&startfile_prefixes, temp, NULL,
+			 PREFIX_PRIORITY_LAST, 0, 1);
 
   /* Process the options and store input files and switches in their
      vectors.  */
@@ -3942,6 +3932,16 @@  process_command (unsigned int decoded_op
     }
 #endif
 
+  /* Add prefixes specified by configure's --with-prefix.  */
+  if (*configure_exec_prefix)
+    add_multiple_prefix (&exec_prefixes, configure_exec_prefix, "GCC",
+			 PREFIX_PRIORITY_LAST, 0, 0);
+
+
+  if (*configure_startfile_prefix)
+    add_multiple_prefix (&startfile_prefixes, configure_startfile_prefix,
+			 "GCC", PREFIX_PRIORITY_LAST, 0, 1);
+
   /* More prefixes are enabled in main, after we read the specs file
      and determine whether this is cross-compilation or not.  */
 
@@ -8085,7 +8085,6 @@  find_file_spec_function (int argc, const
   return file;
 }
 
-
 /* %:find-plugindir spec function.  This function replaces its argument
     by the -iplugindir=<dir> option.  `dir' is found through find_file, that
     is the -print-file-name gcc program option. */
@@ -8340,3 +8339,208 @@  pass_through_libs_spec_func (int argc, c
     }
   return prepended;
 }
+
+#define IS_STD_DIR(PATH,STD) (strncmp (PATH, STD, sizeof (STD)-1) == 0)
+
+#ifdef CONFIGURE_RPATH_PREFIX
+
+static const char config_rpath[] = CONFIGURE_RPATH_PREFIX;
+
+/* Common code for extra_rpath_dirs_spec_function and
+   extra_cpu_dirs_spec_function to build up a list of -rpath=<dir> or -L<dir>
+   options, based on the extra rpath directories that were configured in.  */
+
+static char *
+build_rpath_or_cpu_dirs (const char *rpath_dirs,
+			 const char *prefix,
+			 const char *subdir)
+{
+  char *ret = NULL;
+  char *tmpstr, *endp, *prev_dir;
+  size_t rpath_len = strlen (rpath_dirs);
+  size_t subdir_len = (subdir) ? strlen (subdir) : 0;
+  size_t mlib_len = (multilib_os_dir) ? strlen (multilib_os_dir) : 0;
+  bool mlib_updir;
+  size_t i;
+
+  mlib_updir = (DIR_SEPARATOR == '/'
+		&& mlib_len > sizeof ("../") - 1
+		&& multilib_os_dir[0] == '.'
+		&& multilib_os_dir[1] == '.'
+		&& multilib_os_dir[2] == '/');
+
+  endp = tmpstr = XALLOCAVEC (char, rpath_len + subdir_len + mlib_len + 4);
+  prev_dir = NULL;
+  for (i = 0; i <= rpath_len; i++)
+    {
+      int ch = rpath_dirs[i];
+      if (ch != PATH_SEPARATOR && ch != '\0')
+	{
+	  *endp++ = ch;
+	  if (ch == DIR_SEPARATOR)
+	    prev_dir = endp;
+	}
+      else if (endp > tmpstr)
+	{
+	  /* Add current multlib directory.  Convert <stuff>/lib/../lib64 into
+	     <stuff>/lib64.  */
+	  if (mlib_len > 0)
+	    {
+	      if (mlib_updir && prev_dir)
+		{
+		  memcpy (prev_dir, multilib_os_dir + 3, mlib_len - 3);
+		  endp = prev_dir + mlib_len - 3;
+		}
+	      else
+		{
+		  *endp = DIR_SEPARATOR;
+		  memcpy (endp+1, multilib_os_dir, mlib_len);
+		  endp += mlib_len + 1;
+		}
+	    }
+
+	  /* Look for machine specific subdir?  */
+	  if (subdir)
+	    {
+	      *endp = DIR_SEPARATOR;
+	      memcpy (endp+1, subdir, subdir_len);
+	      endp += subdir_len + 1;
+	    }
+
+	  endp[0] = DIR_SEPARATOR;
+	  endp[1] = '.';
+	  endp[2] = '\0';
+
+	  if (is_directory (tmpstr, false))
+	    {
+	      *endp = '\0';
+	      if (ret)
+		ret = reconcat (ret, ret, " ", prefix, tmpstr, NULL);
+	      else
+		ret = concat (prefix, tmpstr, NULL);
+	    }
+
+	  endp = tmpstr;
+	}
+    }
+
+  return ret;
+}
+
+/* %:extra-rpath-dirs spec function.  If we have alternate rpath directories
+    (install lib directory + alternate startfile prefix directories), build a
+    string with all of the directories that are found with appropriate -rpath
+    options for the linker.  If the LD_RUN_PATH environment variable is
+    specified, include this into the -rpath arguments, since LD_RUN_PATH is
+    only used if -rpath is not specified.  */
+
+static const char *
+extra_rpath_dirs_spec_function (int argc, const char **argv ATTRIBUTE_UNUSED)
+{
+  static const char path_sep[2] = { PATH_SEPARATOR, '\0' };
+  const char *ld_run_path = getenv ("LD_RUN_PATH");
+  const char *ret;
+
+  if (argc != 0)
+    abort ();
+
+  if (ld_run_path)
+    {
+      char *new_rpath = concat (config_rpath, path_sep, ld_run_path, NULL);
+      ret = build_rpath_or_cpu_dirs (new_rpath, "-rpath=", NULL);
+      free (new_rpath);
+    }
+  else
+    ret = build_rpath_or_cpu_dirs (config_rpath, "-rpath=", NULL);
+
+  return ret;
+}
+
+/* %:extra-cpu-dirs spec function.  If we have alternate rpath directories,
+    search them to see if there are subdirectories that hold the static
+    libraries built for a particular machines, and return appropriate -L<dir>
+    to those directories.  */
+
+const char *
+extra_cpu_dirs_spec_function (int argc, const char **argv)
+{
+  if (argc != 1)
+    abort ();
+
+  return build_rpath_or_cpu_dirs (config_rpath, "-L", argv[0]);
+}
+
+/* %:find-dynamic-linker spec function.  Find the dynamic linker if we have
+    extra search paths configured.  */
+
+static const char *
+find_dynamic_linker_spec_function (int argc, const char **argv)
+{
+  const char *file;
+  char *tmpstr;
+  char *endp;
+  char *prev_dir;
+  size_t len;
+  size_t i;
+  int ch;
+
+  if (argc < 1)
+    abort ();
+
+  file = argv[0];
+  len = strlen (file);
+  gcc_assert (file[0] == DIR_SEPARATOR);
+
+  endp = tmpstr = XALLOCAVEC (char, ARRAY_SIZE (config_rpath) + len + 1);
+  prev_dir = NULL;
+  for (i = 0; i <= ARRAY_SIZE (config_rpath); i++)
+    {
+      ch = config_rpath[i];
+      if (ch != PATH_SEPARATOR && ch != '\0')
+	{
+	  if (ch == DIR_SEPARATOR)
+	    prev_dir = endp;
+
+	  *endp++ = ch;
+	}
+      else if (endp > tmpstr)
+	{
+	  *endp = '\0';
+	  if (prev_dir && strncmp (prev_dir, "/lib", sizeof ("/lib")-1) == 0)
+	    endp = prev_dir;
+	  memcpy (endp, file, len);
+	  endp[len] = '\0';
+	  if (access (tmpstr, X_OK) == 0)
+	    return xstrdup (tmpstr);
+
+	  endp = tmpstr;
+	}
+    }
+
+  return xstrdup (file);
+}
+
+#else
+const char *
+extra_rpath_dirs_spec_function (int argc ATTRIBUTE_UNUSED,
+				const char **argv ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
+const char *
+extra_cpu_dirs_spec_function (int argc ATTRIBUTE_UNUSED,
+			      const char **argv ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
+static const char *
+find_dynamic_linker_spec_function (int argc, const char **argv)
+{
+  if (argc != 1)
+    abort ();
+
+  return xstrdup (argv[0]);
+}
+#endif
Index: gcc/gcc.h
===================================================================
--- gcc/gcc.h	(revision 188026)
+++ gcc/gcc.h	(working copy)
@@ -37,6 +37,7 @@  extern int do_spec (const char *);
 extern void record_temp_file (const char *, int, int);
 extern void pfatal_with_name (const char *) ATTRIBUTE_NORETURN;
 extern void set_input (const char *);
+extern const char *extra_cpu_dirs_spec_function (int, const char **);
 
 /* Spec files linked with gcc.c must provide definitions for these.  */
 
Index: gcc/config.in
===================================================================
--- gcc/config.in	(revision 188026)
+++ gcc/config.in	(working copy)
@@ -2023,3 +2023,20 @@ 
 #undef vfork
 #endif
 
+
+/* Define extra executable prefixes at configure time.  */
+#ifndef USED_FOR_TARGET
+#undef CONFIGURE_EXEC_PREFIX
+#endif
+
+
+/* Define extra startfile prefixes at configure time.  */
+#ifndef USED_FOR_TARGET
+#undef CONFIGURE_STARTFILE_PREFIX
+#endif
+
+
+/* Define extra rpath prefixes at configure time.  */
+#ifndef USED_FOR_TARGET
+#undef CONFIGURE_RPATH_PREFIX
+#endif
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac	(revision 188026)
+++ gcc/configure.ac	(working copy)
@@ -1585,6 +1585,57 @@  case "$LIBINTL" in *$LIBICONV*)
 	LIBICONV= ;;
 esac
 
+AC_ARG_WITH([extra-prefix],
+[AC_HELP_STRING([--with-extra-prefix={prefixes}],
+ [Add extra prefixes to the list of locations to search for all files])],
+ [EXTRA_PREFIX="$withval"],
+ [EXTRA_PREFIX=''])
+
+AC_ARG_WITH([extra-exec-prefix],
+[AC_HELP_STRING([--with-extra-exec-prefix={prefixes}],
+ [Add extra prefixes to the list of locations to search for executables])],
+ [EXTRA_EXEC_PREFIX="$withval"],
+ [if test x"${EXTRA_PREFIX}" != x; then
+    EXTRA_EXEC_PREFIX="`echo ${EXTRA_PREFIX} | sed 's/:/\\/bin:/g'`/bin"
+  else
+    EXTRA_EXEC_PREFIX=""
+  fi])
+
+if test x"${EXTRA_EXEC_PREFIX}" != x; then
+  AC_DEFINE_UNQUOTED(CONFIGURE_EXEC_PREFIX, "$EXTRA_EXEC_PREFIX",
+		     [Extra executable prefixes])
+fi
+
+AC_ARG_WITH([extra-startfile-prefix],
+[AC_HELP_STRING([--with-extra-startfile-prefix={prefix}],
+ [Add extra prefixes to the list of locations to search for startfiles])],
+ [EXTRA_STARTFILE_PREFIX="$withval"],
+ [if test x"${EXTRA_PREFIX}" != x; then
+    EXTRA_STARTFILE_PREFIX="`echo ${EXTRA_PREFIX} | sed 's/:/\\/lib:/g'`/lib"
+  else
+    EXTRA_STARTFILE_PREFIX=""
+  fi])
+
+if test x"${EXTRA_STARTFILE_PREFIX}" != x; then
+  AC_DEFINE_UNQUOTED(CONFIGURE_STARTFILE_PREFIX, "$EXTRA_STARTFILE_PREFIX",
+		     [Extra startfile prefix])
+fi
+
+AC_ARG_WITH([extra-rpath-prefix],
+[AC_HELP_STRING([--with-extra-rpath-prefix={prefixes}],
+ [Specify prefixes to pass to the linker via -rpath=dir to locate shared libraries])],
+ [EXTRA_RPATH_PREFIX="$withval"],
+ [if test x"${EXTRA_PREFIX}" != x; then
+    EXTRA_RPATH_PREFIX="${prefix}/lib:`echo ${EXTRA_PREFIX} | sed 's/:/\\/lib:/g'`/lib"
+  else
+    EXTRA_RPATH_PREFIX=""
+  fi])
+
+if test x"${EXTRA_RPATH_PREFIX}" != x; then
+  AC_DEFINE_UNQUOTED(CONFIGURE_RPATH_PREFIX, "$EXTRA_RPATH_PREFIX",
+		     [Extra rpath prefix])
+fi
+
 AC_ARG_ENABLE(secureplt,
 [AS_HELP_STRING([--enable-secureplt],
 		[enable -msecure-plt by default for PowerPC])],
Index: gcc/config/rs6000/x-rs6000
===================================================================
--- gcc/config/rs6000/x-rs6000	(revision 188026)
+++ gcc/config/rs6000/x-rs6000	(working copy)
@@ -1,3 +1,3 @@ 
 driver-rs6000.o : $(srcdir)/config/rs6000/driver-rs6000.c \
-  $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h
+  $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(GCC_H)
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
Index: gcc/config/rs6000/linux64.h
===================================================================
--- gcc/config/rs6000/linux64.h	(revision 188026)
+++ gcc/config/rs6000/linux64.h	(working copy)
@@ -1,7 +1,7 @@ 
 /* Definitions of target machine for GNU compiler,
    for 64 bit PowerPC linux.
    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009, 2010, 2011  Free Software Foundation, Inc.
+   2009, 2010, 2011, 2012  Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -358,8 +358,14 @@  extern int dot_symbols;
 #undef	LINK_OS_DEFAULT_SPEC
 #define LINK_OS_DEFAULT_SPEC "%(link_os_linux)"
 
+#ifdef CONFIGURE_STARTFILE_PREFIX
+#define GLIBC_DYNAMIC_LINKER32 "%:find-dynamic-linker(/lib/ld.so.1)"
+#define GLIBC_DYNAMIC_LINKER64 "%:find-dynamic-linker(/lib64/ld64.so.1)"
+#else
 #define GLIBC_DYNAMIC_LINKER32 "/lib/ld.so.1"
 #define GLIBC_DYNAMIC_LINKER64 "/lib64/ld64.so.1"
+#endif
+
 #define UCLIBC_DYNAMIC_LINKER32 "/lib/ld-uClibc.so.0"
 #define UCLIBC_DYNAMIC_LINKER64 "/lib/ld64-uClibc.so.0"
 #if DEFAULT_LIBC == LIBC_UCLIBC
@@ -369,17 +375,39 @@  extern int dot_symbols;
 #else
 #error "Unsupported DEFAULT_LIBC"
 #endif
+
 #define GNU_USER_DYNAMIC_LINKER32 \
   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER32, UCLIBC_DYNAMIC_LINKER32)
 #define GNU_USER_DYNAMIC_LINKER64 \
   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER64, UCLIBC_DYNAMIC_LINKER64)
 
+#ifdef CONFIGURE_STARTFILE_PREFIX
+#ifdef HAVE_LOCAL_CPU_DETECT
+#define LINUX_EXTRA_STATIC_LIBDIRS64 \
+"%{static: \
+%{mcpu=native: %:linux_extra_static_libdirs(%:local_cpu_detect(cpu))} \
+%{!mcpu=native: %{mcpu=*: %:linux_extra_static_libdirs(%{mcpu=*}) }}} "
+
+#else
+#define LINUX_EXTRA_STATIC_LIBDIRS64 \
+"%{static: \
+%{mcpu=: %:linux_extra_static_libdirs(%{mcpu=*}) }} "
+#endif
+
+#else
+#define LINUX_EXTRA_STATIC_LIBDIRS64
+#endif
+
 
-#define LINK_OS_LINUX_SPEC32 "-m elf32ppclinux %{!shared: %{!static: \
+#define LINK_OS_LINUX_SPEC32 "-m elf32ppclinux " \
+LINUX_EXTRA_STATIC_LIBDIRS32 \
+"%{!shared: %{!static: \
   %{rdynamic:-export-dynamic} \
   -dynamic-linker " GNU_USER_DYNAMIC_LINKER32 "}}"
 
-#define LINK_OS_LINUX_SPEC64 "-m elf64ppc %{!shared: %{!static: \
+#define LINK_OS_LINUX_SPEC64 "-m elf64ppc " \
+LINUX_EXTRA_STATIC_LIBDIRS64 \
+"%{!shared: %{!static: \
   %{rdynamic:-export-dynamic} \
   -dynamic-linker " GNU_USER_DYNAMIC_LINKER64 "}}"
 
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 188026)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -1,7 +1,7 @@ 
 /* Definitions of target machine for GNU compiler, for IBM RS/6000.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011
+   2010, 2011, 2012
    Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
@@ -206,15 +206,21 @@ 
 #if defined(__powerpc__) || defined(__POWERPC__) || defined(_AIX)
 /* In driver-rs6000.c.  */
 extern const char *host_detect_local_cpu (int argc, const char **argv);
-#define EXTRA_SPEC_FUNCTIONS \
+#define LOCAL_CPU_EXTRA_SPEC_FUNCTIONS \
   { "local_cpu_detect", host_detect_local_cpu },
 #define HAVE_LOCAL_CPU_DETECT
 #define ASM_CPU_NATIVE_SPEC "%:local_cpu_detect(asm)"
 
 #else
 #define ASM_CPU_NATIVE_SPEC "%(asm_default)"
+#define LOCAL_CPU_EXTR_SPEC_FUNCTIONS
 #endif
 
+#define SUBTARGET_EXTRA_SPEC_FUNCTIONS
+#define EXTRA_SPEC_FUNCTIONS						\
+  SUBTARGET_EXTRA_SPEC_FUNCTIONS					\
+  LOCAL_CPU_EXTRA_SPEC_FUNCTIONS
+
 #ifndef CC1_CPU_SPEC
 #ifdef HAVE_LOCAL_CPU_DETECT
 #define CC1_CPU_SPEC \
Index: gcc/config/rs6000/driver-rs6000.c
===================================================================
--- gcc/config/rs6000/driver-rs6000.c	(revision 188026)
+++ gcc/config/rs6000/driver-rs6000.c	(working copy)
@@ -1,5 +1,5 @@ 
 /* Subroutines for the gcc driver.
-   Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009, 2012 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,6 +22,7 @@  along with GCC; see the file COPYING3.  
 #include "coretypes.h"
 #include "tm.h"
 #include <stdlib.h>
+#include "gcc.h"
 
 #ifdef _AIX
 # include <sys/systemcfg.h>
@@ -545,3 +546,32 @@  host_detect_local_cpu (int argc, const c
 
 #endif /* GCC_VERSION */
 
+
+#ifdef CONFIGURE_STARTFILE_PREFIX
+/* Add -L for all of the machine dependent directories found in the extra rpath
+   directories.  We don't need to do this for dynamic links, since the dynamic
+   linker will pick up the right library based on the machine that is currently
+   running.  */
+
+const char *
+rs6000_extra_static_libdirs (int argc, const char **argv)
+{
+  const char *new_argv[2];
+  const char *cpu;
+
+  if (argc == 1 && strncmp (argv[0], "mcpu=", sizeof ("-mcpu=")-1) == 0)
+    cpu = argv[0] + sizeof ("-mcpu=") - 1;
+
+  else if (argc == 2 && strcmp (argv[0], "-") == 0
+	   && strncmp (argv[1], "mcpu=", sizeof ("mcpu=")-1) == 0)
+    cpu = argv[1] + sizeof ("mcpu=") - 1;
+
+  else
+    abort ();
+
+  new_argv[0] = cpu;
+  new_argv[1] = NULL;
+  return extra_cpu_dirs_spec_function (1, new_argv);
+}
+
+#endif /* !CONFIGURE_STARTFILE_PREFIX */
Index: gcc/config/rs6000/sysv4.h
===================================================================
--- gcc/config/rs6000/sysv4.h	(revision 188026)
+++ gcc/config/rs6000/sysv4.h	(working copy)
@@ -792,7 +792,12 @@  extern int fixuplabelno;
 
 #define LINK_START_LINUX_SPEC ""
 
+#ifdef CONFIGURE_STARTFILE_PREFIX
+#define GLIBC_DYNAMIC_LINKER "%:find-dynamic-linker(/lib/ld.so.1)"
+#else
 #define GLIBC_DYNAMIC_LINKER "/lib/ld.so.1"
+#endif
+
 #define UCLIBC_DYNAMIC_LINKER "/lib/ld-uClibc.so.0"
 #if DEFAULT_LIBC == LIBC_UCLIBC
 #define CHOOSE_DYNAMIC_LINKER(G, U) "%{mglibc:" G ";:" U "}"
@@ -801,10 +806,30 @@  extern int fixuplabelno;
 #else
 #error "Unsupported DEFAULT_LIBC"
 #endif
+
 #define GNU_USER_DYNAMIC_LINKER \
   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER, UCLIBC_DYNAMIC_LINKER)
 
-#define LINK_OS_LINUX_SPEC "-m elf32ppclinux %{!shared: %{!static: \
+#ifdef CONFIGURE_STARTFILE_PREFIX
+#ifdef HAVE_LOCAL_CPU_DETECT
+#define LINUX_EXTRA_STATIC_LIBDIRS32 \
+"%{static: \
+%{mcpu=native: %:linux_extra_static_libdirs(%:local_cpu_detect(cpu))} \
+%{!mcpu=native: %{mcpu=*: %:linux_extra_static_libdirs(%{mcpu=*}) }}} "
+
+#else
+#define LINUX_EXTRA_STATIC_LIBDIRS32 \
+"%{static: \
+%{mcpu=: %:linux_extra_static_libdirs(%{mcpu=*}) }} "
+#endif
+
+#else
+#define LINUX_EXTRA_STATIC_LIBDIRS32 ""
+#endif
+
+#define LINK_OS_LINUX_SPEC "-m elf32ppclinux " \
+LINUX_EXTRA_STATIC_LIBDIRS32 \
+"%{!shared: %{!static: \
   %{rdynamic:-export-dynamic} \
   -dynamic-linker " GNU_USER_DYNAMIC_LINKER "}}"
 
@@ -870,6 +895,22 @@  ncrtn.o%s"
 #define CPP_OS_OPENBSD_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_POSIX_THREADS}"
 #endif
 
+/* If we have additional startfiles, we want to use the dynamic linker from the
+   directories those startfiles are in.  We also want to set the -rpath for
+   those directories.
+
+   Also if this is a static link, see if we have any processor specific
+   directories in the extra startfiles directories.  We don't have to worry
+   about dynamic libraries, since the dynamic linker will include them
+   automatically. */
+#ifdef CONFIGURE_STARTFILE_PREFIX
+extern const char *rs6000_extra_static_libdirs (int argc, const char **argv);
+
+#undef SUBTARGET_EXTRA_SPEC_FUNCTIONS
+#define SUBTARGET_EXTRA_SPEC_FUNCTIONS \
+  { "linux_extra_static_libdirs",	rs6000_extra_static_libdirs },
+#endif
+
 /* Define any extra SPECS that the compiler needs to generate.  */
 /* Override rs6000.h definition.  */
 #undef	SUBTARGET_EXTRA_SPECS