Patchwork support for multiarch systems

login
register
mail settings
Submitter Matthias Klose
Date Aug. 20, 2011, 7:51 p.m.
Message ID <4E501045.40102@ubuntu.com>
Download mbox | patch
Permalink /patch/110785/
State New
Headers show

Comments

Matthias Klose - Aug. 20, 2011, 7:51 p.m.
Multiarch [1] is the term being used to refer to the capability of a system to
install and run applications of multiple different binary targets on the same
system.  The idea and name of multiarch dates back to 2004/2005 [2] (to be
confused with multiarch in glibc).

Multiarch defines new system directories for headers and libraries/object files:

  /usr/include/<multiarch>
  /lib/<multiarch>
  /usr/lib/<multiarch>

  /usr/local/include/<multiarch>
  /usr/local/lib/<multiarch>

The attached patch

 - searches for multiarch subdirectories in the list of
   startfile_prefixes
 - passes the option -imultiarch to the compiler binaries
 - the compiler binaries add the multiarch include paths
   to the system include path.
 - adds a driver option -print-multiarch

The multiarch triplets are defined in the target specific tmake files, and
provided for all known existing multiarch implementations (currently Debian,
Ubuntu and derivatives).  For non-multilib'd configurations, the triplet is
defined in MULTIARCH_DIRNAME, for multilib'd configurations each directory in
MULTILIB_OSDIRNAMES gets an multiarch directory associated, separated by a colon
(e.g. ../lib:x86_64-linux-gnu).  The multiarch names are as used by Debian, the
mips names go back to a discussion from 2006 [3] to match the ones for glibc.

Tested on non-multilib'd and multilib'd systems, both native and cross builds.
Ok for the trunk?

  Matthias

[1] http://wiki.debian.org/Multiarch
[2] http://debconf5.debconf.org/comas/general/proposals/27.html
[3] http://lists.debian.org/debian-mips/2006/03/msg00004.html
2011-08-20  Matthias Klose  <doko@ubuntu.com>

	* doc/invoke.texi: Document -print-multiarch.
	* Makefile.in (s-mlib): Pass MULTIARCH_DIRNAME to genmultilib.
	* genmultilib: Add new option for the multiarch name.
	* gcc.c (multiarch_dir): Define.
	(for_each_path): Search for multiarch suffixes.
	(driver_handle_option): Handle multiarch option.
	(do_spec_1): Pass -imultiarch if defined.
	(main): Print multiarch.
	(set_multilib_dir): Separate multilib and multiarch names
	from multilib_select.
	(print_multilib_info): Ignore multiarch names in multilib_select.
	* incpath.c (add_standard_paths): Search the multiarch include dirs.
	* cppdeault.h (default_include): Document multiarch in multilib
	member.
	* cppdefault.c: [LOCAL_INCLUDE_DIR, STANDARD_INCLUDE_DIR] Add an
        include directory for multiarch directories.
	* common.opt: New options --print-multiarch and -imultilib.
	* config/s390/t-linux64: Add multiarch names in MULTILIB_OSDIRNAMES.
	* config/sparc/t-linux64: Likewise.
	* config/powerpc/t-linux64: Likewise.
	* config/i386/t-linux64: Likewise.
	* config/mips/t-linux64: Likewise.
	* config/alpha/t-linux: Define MULTIARCH_DIRNAME.
	* config/arm/t-linux: Likewise.
	* config/i386/t-linux: Likewise.
	* config/pa/t-linux: Likewise.
	* config/sparc/t-linux: Likewise.
	* config/ia64/t-glibc: Define MULTIARCH_DIRNAME for linux target.
	* gcc/config/i386/t-gnu: New, Define MULTIARCH_DIRNAME.
	* gcc/config/i386/t-kfreebsd: New, Define MULTIARCH_DIRNAME and
	MULTILIB_OSDIRNAMES.
Jakub Jelinek - Aug. 20, 2011, 8:07 p.m.
On Sat, Aug 20, 2011 at 09:51:33PM +0200, Matthias Klose wrote:
> Tested on non-multilib'd and multilib'd systems, both native and cross builds.
> Ok for the trunk?

I don't think we want to do this unconditionally, we already search way too
many directories by default.  This is a Debian/Ubuntu specific setup, I
don't think many others are going to use such a setup.
So, IMHO you should make it configure time selectable whether those extra
dirs are searched or not.  And by default either don't enable it, or enable
it only on Debian/Ubuntu.

	Jakub
Joseph S. Myers - Aug. 20, 2011, 8:39 p.m.
On Sat, 20 Aug 2011, Matthias Klose wrote:

> The multiarch triplets are defined in the target specific tmake files, and
> provided for all known existing multiarch implementations (currently Debian,
> Ubuntu and derivatives).  For non-multilib'd configurations, the triplet is

Is there a specification somewhere of what the various triplets mean?

> defined in MULTIARCH_DIRNAME, for multilib'd configurations each directory in
> MULTILIB_OSDIRNAMES gets an multiarch directory associated, separated by a colon

I don't see any documentation in fragments.texi for this 
(MULTIARCH_DIRNAME is new so certainly needs documenting, even if you get 
away with not adding to the nonexistent documentation for 
MULTILIB_OSDIRNAMES (PR 25508)).

> (e.g. ../lib:x86_64-linux-gnu).  The multiarch names are as used by Debian, the

Does this work with the "gccdir=osdir" and "gccdir=!osdir" cases before 
the colon?

> mips names go back to a discussion from 2006 [3] to match the ones for glibc.

For x86, shouldn't a name be allocated for x32?

For m68k, classic m68k and ColdFire have incompatible ABIs.  So you need 
to define what m68k-linux-gnu means of the two ABIs.  Unfortunately 
building for ColdFire has been broken for some time, since 
<http://gcc.gnu.org/ml/gcc-patches/2010-12/msg01845.html> (this ought to 
have been dependent on the --with-arch configurey).

For 32-bit Power, hard-float and soft-float ABIs are incompatible.  
Furthermore, the soft-float ABI is used at function-calling level for 
e500v1 and e500v2 - but there are differences in the details of the glibc 
symbols exported (and at least the fenv.h ABI is incompatible between 
soft-float and e500).  So actually there are four variants at the glibc 
level.  You need to define what powerpc-linux-gnu means and avoid it being 
used for anything incompatible.

For MIPS, the hard-float and soft-float ABIs are incompatible.  So you 
need twelve triplets, not six.

For ARM, you have a ChangeLog entry with no corresponding patch.  You need 
to distinguish big and little endian; old ABI, EABI soft-float ABI and 
EABI hard-float ABI (six triplets).

Not all of those variants necessarily are configurable in a multilib 
configuration in the FSF tree (the e500 variants can be achieved with 
powerpc-linux-gnuspe triplets, for example, but those don't have other 
multilibs).  So maybe some of the names won't actually appear in the FSF 
sources - but you still need to define the semantics of the names that do 
appear (whether in the manuals, on the GCC wiki or elsewhere) and 
preferably have somewhere to define semantics for the names not used in 
multilib configurations in FSF GCC.
Matthias Klose - Aug. 20, 2011, 11:50 p.m.
On 08/20/2011 10:07 PM, Jakub Jelinek wrote:
> On Sat, Aug 20, 2011 at 09:51:33PM +0200, Matthias Klose wrote:
>> Tested on non-multilib'd and multilib'd systems, both native and cross builds.
>> Ok for the trunk?
> 
> I don't think we want to do this unconditionally, we already search way too
> many directories by default.  This is a Debian/Ubuntu specific setup, I
> don't think many others are going to use such a setup.
> So, IMHO you should make it configure time selectable whether those extra
> dirs are searched or not.  And by default either don't enable it, or enable
> it only on Debian/Ubuntu.

Ok, I made it conditional, enabled only if the crti.o file is found in a
multiarch path.
Matthias Klose - Aug. 21, 2011, 12:11 a.m.
On 08/20/2011 10:39 PM, Joseph S. Myers wrote:
> On Sat, 20 Aug 2011, Matthias Klose wrote:
> 
>> The multiarch triplets are defined in the target specific tmake files, and
>> provided for all known existing multiarch implementations (currently Debian,
>> Ubuntu and derivatives).  For non-multilib'd configurations, the triplet is
> 
> Is there a specification somewhere of what the various triplets mean?

there is
https://lists.linux-foundation.org/pipermail/lsb-discuss/2011-February/006674.html
http://wiki.debian.org/Multiarch/Tuples

but the documentation is not up to date. The tuples in use are:

$ for a in alpha amd64 armel armhf hppa i386 ia64 mips mipsel powerpc powerpcspe
ppc64 s390 s390x sh4 sparc sparc64 kfreebsd-i386 kfreebsd-amd64 hurd-i386; do
dpkg-architecture -a$a -qDEB_HOST_MULTIARCH 2>/dev/null; done
alpha-linux-gnu
x86_64-linux-gnu
arm-linux-gnueabi
arm-linux-gnueabihf
hppa-linux-gnu
i386-linux-gnu
ia64-linux-gnu
mips-linux-gnu
mipsel-linux-gnu
powerpc-linux-gnu
powerpc-linux-gnuspe
powerpc64-linux-gnu
s390-linux-gnu
s390x-linux-gnu
sh4-linux-gnu
sparc-linux-gnu
sparc64-linux-gnu
i386-kfreebsd-gnu
x86_64-kfreebsd-gnu
i386-gnu

>> defined in MULTIARCH_DIRNAME, for multilib'd configurations each directory in
>> MULTILIB_OSDIRNAMES gets an multiarch directory associated, separated by a colon
> 
> I don't see any documentation in fragments.texi for this 
> (MULTIARCH_DIRNAME is new so certainly needs documenting, even if you get 
> away with not adding to the nonexistent documentation for 
> MULTILIB_OSDIRNAMES (PR 25508)).

well, I hope I get away with copying it from genmultilib without closing the
report ;)

>> (e.g. ../lib:x86_64-linux-gnu).  The multiarch names are as used by Debian, the
> 
> Does this work with the "gccdir=osdir" and "gccdir=!osdir" cases before 
> the colon?

amd64 is configured this way, and I don't handle the !osdir case other than for
the multilib osdir.

>> mips names go back to a discussion from 2006 [3] to match thee, ones for glibc.
> 
> For x86, shouldn't a name be allocated for x32?

maybe, but I didn't see a port yet.

> For m68k, classic m68k and ColdFire have incompatible ABIs.  So you need 
> to define what m68k-linux-gnu means of the two ABIs.  Unfortunately 
> building for ColdFire has been broken for some time, since 
> <http://gcc.gnu.org/ml/gcc-patches/2010-12/msg01845.html> (this ought to 
> have been dependent on the --with-arch configurey).

it's the classic m68k. yes, it has to be defined.

> For 32-bit Power, hard-float and soft-float ABIs are incompatible.  
> Furthermore, the soft-float ABI is used at function-calling level for 
> e500v1 and e500v2 - but there are differences in the details of the glibc 
> symbols exported (and at least the fenv.h ABI is incompatible between 
> soft-float and e500).  So actually there are four variants at the glibc 
> level.  You need to define what powerpc-linux-gnu means and avoid it being 
> used for anything incompatible.

same here. powerpc-linux-gnu is the hard-float one. Debian has an e500 port in
development which currently uses powerpc-linux-gnuspe

> For MIPS, the hard-float and soft-float ABIs are incompatible.  So you 
> need twelve triplets, not six.

yes. but I didn't see a soft-float mips port yet.

> For ARM, you have a ChangeLog entry with no corresponding patch.  You need 
> to distinguish big and little endian; old ABI, EABI soft-float ABI and 
> EABI hard-float ABI (six triplets).

ok, added. Debian has little endian ports only. I see that dpkg treats the
obsolete armeb port as armeb-linux-gnu.

> Not all of those variants necessarily are configurable in a multilib 
> configuration in the FSF tree (the e500 variants can be achieved with 
> powerpc-linux-gnuspe triplets, for example, but those don't have other 
> multilibs).  So maybe some of the names won't actually appear in the FSF 
> sources - but you still need to define the semantics of the names that do 
> appear (whether in the manuals, on the GCC wiki or elsewhere) and 
> preferably have somewhere to define semantics for the names not used in 
> multilib configurations in FSF GCC.

For now, the multiarch documentation should be consolidated; I would like to add
a link from the FCC wiki to this documentation mentioned above.

  Matthias
Andrew Pinski - Aug. 21, 2011, 4:23 a.m.
On Sat, Aug 20, 2011 at 5:11 PM, Matthias Klose <doko@ubuntu.com> wrote:
>> For MIPS, the hard-float and soft-float ABIs are incompatible.  So you
>> need twelve triplets, not six.
>
> yes. but I didn't see a soft-float mips port yet.

We at Cavium has a soft-float mips port and in fact use debian as a
base OS for o32 (but hard float) and have our own n32/n64 libraries
which are soft-float.  mips64octeon-linux-gnu is a soft-float port
which can be used right now; I use that triplet right now to build GCC
on this soft-float based port.

Thanks,
Andrew Pinski
Joseph S. Myers - Aug. 21, 2011, 11:14 a.m.
On Sun, 21 Aug 2011, Matthias Klose wrote:

> powerpc-linux-gnuspe

As noted, that's ambiguous; --enable-e500-double determines whether it's 
e500v1 or e500v2, and since those have slightly different symbols exported 
from libc I think they should be considered different here.

> > For MIPS, the hard-float and soft-float ABIs are incompatible.  So you 
> > need twelve triplets, not six.
> 
> yes. but I didn't see a soft-float mips port yet.

You can configure MIPS targets (including multilib MIPS64 ones) using 
--with-float=soft, so need to allow for that.

> > For ARM, you have a ChangeLog entry with no corresponding patch.  You need 
> > to distinguish big and little endian; old ABI, EABI soft-float ABI and 
> > EABI hard-float ABI (six triplets).
> 
> ok, added. Debian has little endian ports only. I see that dpkg treats the
> obsolete armeb port as armeb-linux-gnu.

The arm*-*-linux* config.gcc code has

        arm*b-*)
                tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1"
                ;;
        esac

so again this should affect whether "eb" goes in the name.

Patch

Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 177846)
+++ gcc/doc/invoke.texi	(working copy)
@@ -5937,6 +5937,11 @@ 
 @file{../lib32}, or if OS libraries are present in @file{lib/@var{subdir}}
 subdirectories it prints e.g.@: @file{amd64}, @file{sparcv9} or @file{ev6}.
 
+@item -print-multiarch
+@opindex print-multiarch
+Print the path to OS libraries for the selected multiarch,
+relative to some @file{lib} subdirectory.
+
 @item -print-prog-name=@var{program}
 @opindex print-prog-name
 Like @option{-print-file-name}, but searches for a program such as @samp{cpp}.
Index: gcc/incpath.c
===================================================================
--- gcc/incpath.c	(revision 177846)
+++ gcc/incpath.c	(working copy)
@@ -150,8 +150,14 @@ 
 	      if (!filename_ncmp (p->fname, cpp_GCC_INCLUDE_DIR, len))
 		{
 		  char *str = concat (iprefix, p->fname + len, NULL);
-		  if (p->multilib && imultilib)
+		  if (p->multilib == 1 && imultilib)
 		    str = concat (str, dir_separator_str, imultilib, NULL);
+		  else if (p->multilib == 2)
+		    {
+		      if (!imultiarch)
+			continue;
+		      str = concat (str, dir_separator_str, imultiarch, NULL);
+		    }
 		  add_path (str, SYSTEM, p->cxx_aware, false);
 		}
 	    }
@@ -195,8 +201,14 @@ 
 	  else
 	    str = update_path (p->fname, p->component);
 
-	  if (p->multilib && imultilib)
+	  if (p->multilib == 1 && imultilib)
 	    str = concat (str, dir_separator_str, imultilib, NULL);
+	  else if (p->multilib == 2)
+	    {
+	      if (!imultiarch)
+		continue;
+	      str = concat (str, dir_separator_str, imultiarch, NULL);
+	    }
 
 	  add_path (str, SYSTEM, p->cxx_aware, false);
 	}
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 177846)
+++ gcc/gcc.c	(working copy)
@@ -1147,6 +1147,11 @@ 
    set_multilib_dir based on the compilation options.  */
 
 static const char *multilib_os_dir;
+
+/* Subdirectory to use for locating libraries in multiarch conventions.  Set by
+   set_multilib_dir based on the compilation options.  */
+
+static const char *multiarch_dir;
 
 /* Structure to keep track of the specs that have been defined so far.
    These are accessed using %(specname) in a compiler or link
@@ -2072,6 +2077,7 @@ 
   struct prefix_list *pl;
   const char *multi_dir = NULL;
   const char *multi_os_dir = NULL;
+  const char *multiarch_suffix = NULL;
   const char *multi_suffix;
   const char *just_multi_suffix;
   char *path = NULL;
@@ -2089,11 +2095,14 @@ 
     }
   if (do_multi && multilib_os_dir && strcmp (multilib_os_dir, ".") != 0)
     multi_os_dir = concat (multilib_os_dir, dir_separator_str, NULL);
+  if (multiarch_dir)
+    multiarch_suffix = concat (multiarch_dir, dir_separator_str, NULL);
 
   while (1)
     {
       size_t multi_dir_len = 0;
       size_t multi_os_dir_len = 0;
+      size_t multiarch_len = 0;
       size_t suffix_len;
       size_t just_suffix_len;
       size_t len;
@@ -2102,6 +2111,8 @@ 
 	multi_dir_len = strlen (multi_dir);
       if (multi_os_dir)
 	multi_os_dir_len = strlen (multi_os_dir);
+      if (multiarch_suffix)
+	multiarch_len = strlen (multiarch_suffix);
       suffix_len = strlen (multi_suffix);
       just_suffix_len = strlen (just_multi_suffix);
 
@@ -2140,6 +2151,16 @@ 
 		break;
 	    }
 
+	  /* Now try the multiarch path.  */
+	  if (!skip_multi_dir
+	      && !pl->require_machine_suffix && multiarch_dir)
+	    {
+	      memcpy (path + len, multiarch_suffix, multiarch_len + 1);
+	      ret = callback (path, callback_info);
+	      if (ret)
+		break;
+	    }
+
 	  /* Now try the base path.  */
 	  if (!pl->require_machine_suffix
 	      && !(pl->os_multilib ? skip_multi_os_dir : skip_multi_dir))
@@ -3238,6 +3259,7 @@ 
     case OPT_print_multi_directory:
     case OPT_print_sysroot:
     case OPT_print_multi_os_directory:
+    case OPT_print_multiarch:
     case OPT_print_sysroot_headers_suffix:
     case OPT_time:
     case OPT_wrapper:
@@ -4891,6 +4913,15 @@ 
 		  do_spec_1 (" ", 0, NULL);
 		}
 
+	      if (multiarch_dir)
+		{
+		  do_spec_1 ("-imultiarch", 1, NULL);
+		  /* Make this a separate argument.  */
+		  do_spec_1 (" ", 0, NULL);
+		  do_spec_1 (multiarch_dir, 1, NULL);
+		  do_spec_1 (" ", 0, NULL);
+		}
+
 	      if (gcc_exec_prefix)
 		{
 		  do_spec_1 ("-iprefix", 1, NULL);
@@ -6508,6 +6539,15 @@ 
       return (0);
     }
 
+  if (print_multiarch)
+    {
+      if (multiarch_dir == NULL)
+	printf ("\n");
+      else
+	printf ("%s\n", multiarch_dir);
+      return (0);
+    }
+
   if (print_sysroot)
     {
       if (target_system_root)
@@ -7483,10 +7523,26 @@ 
 	    q++;
 	  if (q < end)
 	    {
-	      char *new_multilib_os_dir = XNEWVEC (char, end - q);
+	      const char *q2 = q + 1;
+	      char *new_multilib_os_dir;
+
+	      while (q2 < end && *q2 != ':')
+		q2++;
+	      if (*q2 == ':')
+		end = q2;
+	      new_multilib_os_dir = XNEWVEC (char, end - q);
 	      memcpy (new_multilib_os_dir, q + 1, end - q - 1);
 	      new_multilib_os_dir[end - q - 1] = '\0';
 	      multilib_os_dir = new_multilib_os_dir;
+
+	      end = this_path + this_path_len;
+	      if (q2 < end && *q2 == ':')
+		{
+		  char *new_multiarch_dir = XNEWVEC (char, end - q2);
+		  memcpy (new_multiarch_dir, q2 + 1, end - q2 - 1);
+		  new_multiarch_dir[end - q2 - 1] = '\0';
+		  multiarch_dir = new_multiarch_dir;
+		}
 	      break;
 	    }
 	}
@@ -7548,7 +7604,7 @@ 
       /* When --disable-multilib was used but target defines
 	 MULTILIB_OSDIRNAMES, entries starting with .: are there just
 	 to find multilib_os_dir, so skip them from output.  */
-      if (this_path[0] == '.' && this_path[1] == ':')
+      if (this_path[0] == '.' && this_path[1] == ':' && this_path[2] != ':')
 	skip = 1;
 
       /* Check for matches with the multilib_exclusions. We don't bother
Index: gcc/genmultilib
===================================================================
--- gcc/genmultilib	(revision 177846)
+++ gcc/genmultilib	(working copy)
@@ -73,6 +73,8 @@ 
 # the os directory names are used exclusively.  Use the mapping when
 # there is no one-to-one equivalence between GCC levels and the OS.
 
+# The optional eight argument is the multiarch name.
+
 # The last option should be "yes" if multilibs are enabled.  If it is not
 # "yes", all GCC multilib dir names will be ".".
 
@@ -121,7 +123,8 @@ 
 extra=$5
 exclusions=$6
 osdirnames=$7
-enable_multilib=$8
+multiarch=$8
+enable_multilib=$9
 
 echo "static const char *const multilib_raw[] = {"
 
@@ -222,6 +225,9 @@ 
 # names.
 toosdirnames=
 defaultosdirname=
+if [ -n "${multiarch}" ]; then
+  defaultosdirname=::${multiarch}
+fi
 if [ -n "${osdirnames}" ]; then
   set x ${osdirnames}
   shift
@@ -229,6 +235,9 @@ 
     case "$1" in
       .=*)
         defaultosdirname=`echo $1 | sed 's|^.=|:|'`
+	if [ -n "${multiarch}" ]; then
+	  defaultosdirname=${defaultosdirname}:${multiarch}
+	fi
 	shift
 	;;
       *=*)
@@ -314,13 +323,13 @@ 
     dirout=`echo ${combo} | sed -e 's/=/-/g'`
   fi
   # Remove the leading and trailing slashes.
-  dirout=`echo ${dirout} | sed -e 's|^/||' -e 's|/$||g'`
+  dirout=`echo ${dirout} | sed -e 's|^/||' -e 's|/*:/*|:|' -e 's|/$||g'`
 
   # Use the OS directory names rather than the option names.
   if [ -n "${toosdirnames}" ]; then
     osdirout=`echo ${combo} | sed ${toosdirnames}`
     # Remove the leading and trailing slashes.
-    osdirout=`echo ${osdirout} | sed -e 's|^/||' -e 's|/$||g'`
+    osdirout=`echo ${osdirout} | sed -e 's|^/||' -e 's|/*:/*|:|' -e 's|/$||g'`
     if [ "x${enable_multilib}" != xyes ]; then
       dirout=".:${osdirout}"
       disable_multilib=yes
Index: gcc/cppdefault.c
===================================================================
--- gcc/cppdefault.c	(revision 177846)
+++ gcc/cppdefault.c	(working copy)
@@ -64,6 +64,7 @@ 
 #endif
 #ifdef LOCAL_INCLUDE_DIR
     /* /usr/local/include comes before the fixincluded header files.  */
+    { LOCAL_INCLUDE_DIR, 0, 0, 1, 1, 2 },
     { LOCAL_INCLUDE_DIR, 0, 0, 1, 1, 0 },
 #endif
 #ifdef PREFIX_INCLUDE_DIR
@@ -95,6 +96,7 @@ 
 #endif
 #ifdef STANDARD_INCLUDE_DIR
     /* /usr/include comes dead last.  */
+    { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0, 1, 2 },
     { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0, 1, 0 },
 #endif
     { 0, 0, 0, 0, 0, 0 }
Index: gcc/cppdefault.h
===================================================================
--- gcc/cppdefault.h	(revision 177846)
+++ gcc/cppdefault.h	(working copy)
@@ -43,9 +43,11 @@ 
 				   C++.  */
   const char add_sysroot;	/* FNAME should be prefixed by
 				   cpp_SYSROOT.  */
-  const char multilib;		/* FNAME should have the multilib path
-				   specified with -imultilib
-				   appended.  */
+  const char multilib;		/* FNAME should have appended
+				   - the multilib path specified with -imultilib
+				     when 1 is passed,
+				   - the multiarch path specified with
+				     -imultiarch, when 2 is passed.  */
 };
 
 extern const struct default_include cpp_include_defaults[];
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 177846)
+++ gcc/common.opt	(working copy)
@@ -345,6 +345,9 @@ 
 -print-multi-os-directory
 Driver Alias(print-multi-os-directory)
 
+-print-multiarch
+Driver Alias(print-multiarch)
+
 -print-prog-name
 Driver Separate Alias(print-prog-name=)
 
@@ -2231,6 +2234,10 @@ 
 Common Joined Var(plugindir_string) Init(0)
 -iplugindir=<dir>	Set <dir> to be the default plugin directory
 
+imultiarch
+Common Joined Separate RejectDriver Var(imultiarch) Init(0)
+-imultiarch <dir>	Set <dir> to be the multiarch include subdirectory
+
 l
 Driver Joined Separate
 
@@ -2288,6 +2295,9 @@ 
 
 print-multi-os-directory
 Driver Var(print_multi_os_directory)
+ 
+print-multiarch
+Driver Var(print_multiarch)
 
 print-prog-name=
 Driver JoinedOrMissing Var(print_prog_name)
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 177846)
+++ gcc/config.gcc	(working copy)
@@ -1315,12 +1315,14 @@ 
 		;;
 	i[34567]86-*-kfreebsd*-gnu)
 		tm_file="${tm_file} i386/gnu-user.h kfreebsd-gnu.h i386/kfreebsd-gnu.h"
+		tmake_file="${tmake_file} i386/t-kfreebsd"
 		;;
 	i[34567]86-*-kopensolaris*-gnu)
 		tm_file="${tm_file} i386/gnu-user.h kopensolaris-gnu.h i386/kopensolaris-gnu.h"
 		;;
 	i[34567]86-*-gnu*)
 		tm_file="$tm_file i386/gnu-user.h gnu.h i386/gnu.h"
+		tmake_file="${tmake_file} i386/t-gnu"
 		;;
 	esac
 	tmake_file="${tmake_file} i386/t-crtstuff"
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 177846)
+++ gcc/Makefile.in	(working copy)
@@ -1935,10 +1935,11 @@ 
 	    "$(MULTILIB_EXTRA_OPTS)" \
 	    "$(MULTILIB_EXCLUSIONS)" \
 	    "$(MULTILIB_OSDIRNAMES)" \
+	    "$(MULTIARCH_DIRNAME)" \
 	    "@enable_multilib@" \
 	    > tmp-mlib.h; \
 	else \
-	  $(SHELL) $(srcdir)/genmultilib '' '' '' '' '' '' '' no \
+	  $(SHELL) $(srcdir)/genmultilib '' '' '' '' '' '' '' "$(MULTIARCH_DIRNAME)" no \
 	    > tmp-mlib.h; \
 	fi
 	$(SHELL) $(srcdir)/../move-if-change tmp-mlib.h multilib.h
Index: gcc/config/alpha/t-linux
===================================================================
--- gcc/config/alpha/t-linux	(revision 177846)
+++ gcc/config/alpha/t-linux	(working copy)
@@ -1 +1,3 @@ 
 SHLIB_MAPFILES += $(srcdir)/config/alpha/libgcc-alpha-ldbl.ver
+
+MULTIARCH_DIRNAME = alpha-linux-gnu
Index: gcc/config/s390/t-linux64
===================================================================
--- gcc/config/s390/t-linux64	(revision 177846)
+++ gcc/config/s390/t-linux64	(working copy)
@@ -7,4 +7,4 @@ 
 
 MULTILIB_OPTIONS = m64/m31
 MULTILIB_DIRNAMES = 64 32
-MULTILIB_OSDIRNAMES = ../lib64 $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib)
+MULTILIB_OSDIRNAMES = ../lib64:s390x-linux-gnu $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib):s390-linux-gnu
Index: gcc/config/sparc/t-linux64
===================================================================
--- gcc/config/sparc/t-linux64	(revision 177846)
+++ gcc/config/sparc/t-linux64	(working copy)
@@ -26,7 +26,7 @@ 
 
 MULTILIB_OPTIONS = m64/m32
 MULTILIB_DIRNAMES = 64 32
-MULTILIB_OSDIRNAMES = ../lib64 $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib)
+MULTILIB_OSDIRNAMES = ../lib64:sparc64-linux-gnu $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib):sparc-linux-gnu
 
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib
Index: gcc/config/sparc/t-linux
===================================================================
--- gcc/config/sparc/t-linux	(revision 177846)
+++ gcc/config/sparc/t-linux	(working copy)
@@ -3,3 +3,5 @@ 
 # Avoid the t-linux version file.
 SHLIB_MAPFILES = $$(libgcc_objdir)/libgcc-std.ver \
 		 $(srcdir)/config/sparc/libgcc-sparc-glibc.ver
+
+MULTIARCH_DIRNAME = sparc-linux-gnu
Index: gcc/config/i386/t-kfreebsd
===================================================================
--- gcc/config/i386/t-kfreebsd	(revision 0)
+++ gcc/config/i386/t-kfreebsd	(revision 0)
@@ -0,0 +1,5 @@ 
+MULTIARCH_DIRNAME = i386-kfreebsd-gnu
+
+# MULTILIB_OSDIRNAMES are set in t-linux64.
+KFREEBSD_OS = $(filter kfreebsd%, $(word 3, $(subst -, ,$(arch2))))
+MULTILIB_OSDIRNAMES := $(subst linux,$(KFREEBSD_OS),$(MULTILIB_OSDIRNAMES))
Index: gcc/config/i386/t-gnu
===================================================================
--- gcc/config/i386/t-gnu	(revision 0)
+++ gcc/config/i386/t-gnu	(revision 0)
@@ -0,0 +1 @@ 
+MULTIARCH_DIRNAME = i386-gnu
Index: gcc/config/i386/t-linux
===================================================================
--- gcc/config/i386/t-linux	(revision 177846)
+++ gcc/config/i386/t-linux	(working copy)
@@ -3,3 +3,5 @@ 
 # t-slibgcc-elf-ver and t-linux
 SHLIB_MAPFILES = $$(libgcc_objdir)/libgcc-std.ver \
 		 $(srcdir)/config/i386/libgcc-glibc.ver
+
+MULTIARCH_DIRNAME = i386-linux-gnu
Index: gcc/config/i386/t-linux64
===================================================================
--- gcc/config/i386/t-linux64	(revision 177846)
+++ gcc/config/i386/t-linux64	(working copy)
@@ -34,8 +34,8 @@ 
 comma=,
 MULTILIB_OPTIONS    = $(subst $(comma),/,$(TM_MULTILIB_CONFIG))
 MULTILIB_DIRNAMES   = $(patsubst m%, %, $(subst /, ,$(MULTILIB_OPTIONS)))
-MULTILIB_OSDIRNAMES = m64=../lib64
-MULTILIB_OSDIRNAMES+= m32=$(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib)
+MULTILIB_OSDIRNAMES = m64=../lib64:x86_64-linux-gnu
+MULTILIB_OSDIRNAMES+= m32=$(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib):i386-linux-gnu
 MULTILIB_OSDIRNAMES+= mx32=../libx32
 
 LIBGCC = stmp-multilib
Index: gcc/config/ia64/t-glibc
===================================================================
--- gcc/config/ia64/t-glibc	(revision 177846)
+++ gcc/config/ia64/t-glibc	(working copy)
@@ -1 +1,5 @@ 
 SHLIB_MAPFILES += $(srcdir)/config/ia64/libgcc-glibc.ver
+
+ifneq (,$(findstring linux, $(target)))
+MULTIARCH_DIRNAME = ia64-linux-gnu
+endif
Index: gcc/config/m68k/t-linux
===================================================================
--- gcc/config/m68k/t-linux	(revision 177846)
+++ gcc/config/m68k/t-linux	(working copy)
@@ -21,6 +21,8 @@ 
 # Only include multilibs for 680x0 CPUs with an MMU.
 M68K_MLIB_CPU += && (CPU ~ "^m680") && (FLAGS ~ "FL_MMU")
 
+MULTIARCH_DIRNAME = m68k-linux-gnu
+
 # This rule uses MULTILIB_MATCHES to generate a definition of
 # SYSROOT_SUFFIX_SPEC.
 sysroot-suffix.h: $(srcdir)/config/m68k/print-sysroot-suffix.sh
Index: gcc/config/rs6000/t-linux64
===================================================================
--- gcc/config/rs6000/t-linux64	(revision 177846)
+++ gcc/config/rs6000/t-linux64	(working copy)
@@ -33,5 +33,5 @@ 
 MULTILIB_EXTRA_OPTS     = fPIC mstrict-align
 MULTILIB_EXCEPTIONS     = m64/msoft-float
 MULTILIB_EXCLUSIONS     = m64/!m32/msoft-float
-MULTILIB_OSDIRNAMES	= ../lib64 $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib) nof
+MULTILIB_OSDIRNAMES	= ../lib64:powerpc64-linux-gnu $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib):powerpc-linux-gnu nof
 MULTILIB_MATCHES        = $(MULTILIB_MATCHES_FLOAT)
Index: gcc/config/pa/t-linux
===================================================================
--- gcc/config/pa/t-linux	(revision 177846)
+++ gcc/config/pa/t-linux	(working copy)
@@ -35,3 +35,5 @@ 
 
 # Compile crtbeginS.o and crtendS.o as PIC.
 CRTSTUFF_T_CFLAGS_S = -fPIC
+
+MULTIARCH_DIRNAME = hppa-linux-gnu
Index: gcc/config/mips/t-linux64
===================================================================
--- gcc/config/mips/t-linux64	(revision 177846)
+++ gcc/config/mips/t-linux64	(working copy)
@@ -22,6 +22,10 @@ 
 else
 MULTILIB_DIRNAMES = n32 32 64
 endif
-MULTILIB_OSDIRNAMES = ../lib32 ../lib ../lib64
+MIPS_EL = $(if $(filter %el, $(firstword $(subst -, ,$(arch)))),el)
+MULTILIB_OSDIRNAMES = \
+	../lib32:mips64$(MIPS_EL)-linux-gnuabin32 \
+	../lib:mips$(MIPS_EL)-linux-gnu \
+	../lib64:mips64$(MIPS_EL)-linux-gnuabi64
 
 EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o