Find a better compromise with the default library search paths used by

Clang when linking and using a GCC installation from a GCC
cross-compiler.

This was desired already by two special case platforms (Android and
Mips), and turns out to be generally (if frustratingly) true. I've added
a substantial comment to the code clarifying the underlying assumptions
of doing actual cross compiles with Clang (or GCC for that matter!) and
help avoid further confusion here.

The end result is to realize that fully general form of PR12478 cannot
be resolved while we support existing cross-compiling GCC toolchains,
and linking with them (namely, linking against their libgcc and
libstdc++ installs). GCC installs these target libraries under
a target-specific prefix but one that may not be available within the
actual sysroot in use. When linking in this world, GCC works and Clang
should as well, but caveat emptor: DSOs from this tree must be
replicated and rpath-fixed to be found at runtime within the sysroot.

I've extended the cross compile test cases to cover these issues by
pointing them at a sysroot and actually checking the library search
paths.

llvm-svn: 187466
This commit is contained in:
Chandler Carruth 2013-07-31 00:37:07 +00:00
parent 629ff3628a
commit 7f8042c8f3
2 changed files with 81 additions and 24 deletions

View File

@ -2281,33 +2281,48 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
GCCInstallation.getBiarchSuffix()),
Paths);
// Sourcery CodeBench MIPS toolchain holds some libraries under
// the parent prefix of the GCC installation.
// FIXME: It would be cleaner to model this as a variant of multilib. IE,
// instead of 'lib64' it would be 'lib/el'.
std::string MultilibSuffix;
appendMipsTargetSuffix(MultilibSuffix, Arch, Args);
// GCC cross compiling toolchains will install target libraries which ship
// as part of the toolchain under <prefix>/<triple>/<libdir> rather than as
// any part of the GCC installation in
// <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat
// debatable, but is the reality today. We need to search this tree even
// when we have a sysroot somewhere else. It is the responsibility of
// whomever is doing the cross build targetting a sysroot using a GCC
// installation that is *not* within the system root to ensure two things:
//
// 1) Any DSOs that are linked in from this tree or from the install path
// above must be preasant on the system root and found via an
// appropriate rpath.
// 2) There must not be libraries installed into
// <prefix>/<triple>/<libdir> unless they should be preferred over
// those within the system root.
//
// Note that this matches the GCC behavior. See the below comment for where
// Clang diverges from GCC's behavior.
addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib +
MultilibSuffix,
Paths);
// If the GCC installation we found is inside of the sysroot, we want to
// prefer libraries installed in the parent prefix of the GCC installation.
// It is important to *not* use these paths when the GCC installation is
// outside of the system root as that can pick up unintended libraries.
// This usually happens when there is an external cross compiler on the
// host system, and a more minimal sysroot available that is the target of
// the cross.
// the cross. Note that GCC does include some of these directories in some
// configurations but this seems somewhere between questionable and simply
// a bug.
if (StringRef(LibPath).startswith(SysRoot)) {
addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib,
Paths);
addPathIfExists(LibPath + "/" + MultiarchTriple, Paths);
addPathIfExists(LibPath + "/../" + Multilib, Paths);
}
// On Android, libraries in the parent prefix of the GCC installation are
// preferred to the ones under sysroot.
if (IsAndroid) {
addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths);
}
// Sourcery CodeBench MIPS toolchain holds some libraries under
// the parent prefix of the GCC installation.
if (IsMips) {
std::string Suffix;
appendMipsTargetSuffix(Suffix, Arch, Args);
addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" +
Multilib + Suffix,
Paths);
}
}
addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths);
addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths);
@ -2327,10 +2342,14 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
if (!GCCInstallation.getBiarchSuffix().empty())
addPathIfExists(GCCInstallation.getInstallPath(), Paths);
if (StringRef(LibPath).startswith(SysRoot)) {
addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths);
// See comments above on the multilib variant for details of why this is
// included even from outside the sysroot.
addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths);
// See comments above on the multilib variant for details of why this is
// only included from within the sysroot.
if (StringRef(LibPath).startswith(SysRoot))
addPathIfExists(LibPath, Paths);
}
}
addPathIfExists(SysRoot + "/lib", Paths);
addPathIfExists(SysRoot + "/usr/lib", Paths);

View File

@ -27,31 +27,69 @@
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
// RUN: --gcc-toolchain=%S/Inputs/multilib_32bit_linux_tree/usr \
// RUN: --target=i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MULTI32-I386 %s
// CHECK-MULTI32-I386: "-cc1" "-triple" "i386-unknown-linux"
// CHECK-MULTI32-I386: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}as" "--32"
// CHECK-MULTI32-I386: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}ld" {{.*}} "-m" "elf_i386"
// CHECK-MULTI32-I386: "[[gcc_install:.*/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0]]/../../../../i386-unknown-linux/bin{{/|\\}}ld"
// CHECK-MULTI32-I386: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
// CHECK-MULTI32-I386: "-m" "elf_i386"
// CHECK-MULTI32-I386: "[[gcc_install]]/crtbegin.o"
// CHECK-MULTI32-I386: "-L[[gcc_install]]"
// CHECK-MULTI32-I386: "-L[[gcc_install]]/../../../../i386-unknown-linux/lib/../lib32"
// CHECK-MULTI32-I386: "-L[[gcc_install]]/../../../../i386-unknown-linux/lib"
// CHECK-MULTI32-I386: "-L[[sysroot]]/lib"
// CHECK-MULTI32-I386: "-L[[sysroot]]/usr/lib"
//
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
// RUN: --gcc-toolchain=%S/Inputs/multilib_32bit_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MULTI32-X86-64 %s
// CHECK-MULTI32-X86-64: "-cc1" "-triple" "x86_64-unknown-linux"
// CHECK-MULTI32-X86-64: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}as" "--64"
// CHECK-MULTI32-X86-64: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}ld" {{.*}} "-m" "elf_x86_64"
// CHECK-MULTI32-X86-64: "[[gcc_install:.*/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0]]/../../../../i386-unknown-linux/bin{{/|\\}}ld"
// CHECK-MULTI32-X86-64: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
// CHECK-MULTI32-X86-64: "-m" "elf_x86_64"
// CHECK-MULTI32-X86-64: "[[gcc_install]]/64/crtbegin.o"
// CHECK-MULTI32-X86-64: "-L[[gcc_install]]/64"
// CHECK-MULTI32-X86-64: "-L[[gcc_install]]/../../../../i386-unknown-linux/lib/../lib64"
// CHECK-MULTI32-X86-64: "-L[[gcc_install]]"
// CHECK-MULTI32-X86-64: "-L[[gcc_install]]/../../../../i386-unknown-linux/lib"
// CHECK-MULTI32-X86-64: "-L[[sysroot]]/lib"
// CHECK-MULTI32-X86-64: "-L[[sysroot]]/usr/lib"
//
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
// RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \
// RUN: --target=i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MULTI64-I386 %s
// CHECK-MULTI64-I386: "-cc1" "-triple" "i386-unknown-linux"
// CHECK-MULTI64-I386: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}as" "--32"
// CHECK-MULTI64-I386: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}ld" {{.*}} "-m" "elf_i386"
// CHECK-MULTI64-I386: "[[gcc_install:.*/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0]]/../../../../x86_64-unknown-linux/bin{{/|\\}}ld"
// CHECK-MULTI64-I386: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
// CHECK-MULTI64-I386: "-m" "elf_i386"
// CHECK-MULTI64-I386: "[[gcc_install]]/32/crtbegin.o"
// CHECK-MULTI64-I386: "-L[[gcc_install]]/32"
// CHECK-MULTI64-I386: "-L[[gcc_install]]/../../../../x86_64-unknown-linux/lib/../lib32"
// CHECK-MULTI64-I386: "-L[[gcc_install]]"
// CHECK-MULTI64-I386: "-L[[gcc_install]]/../../../../x86_64-unknown-linux/lib"
// CHECK-MULTI64-I386: "-L[[sysroot]]/lib"
// CHECK-MULTI64-I386: "-L[[sysroot]]/usr/lib"
//
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
// RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MULTI64-X86-64 %s
// CHECK-MULTI64-X86-64: "-cc1" "-triple" "x86_64-unknown-linux"
// CHECK-MULTI64-X86-64: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}as" "--64"
// CHECK-MULTI64-X86-64: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}ld" {{.*}} "-m" "elf_x86_64"
// CHECK-MULTI64-X86-64: "[[gcc_install:.*/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0]]/../../../../x86_64-unknown-linux/bin{{/|\\}}ld"
// CHECK-MULTI64-X86-64: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
// CHECK-MULTI64-X86-64: "-m" "elf_x86_64"
// CHECK-MULTI64-X86-64: "[[gcc_install]]/crtbegin.o"
// CHECK-MULTI64-X86-64: "-L[[gcc_install]]"
// CHECK-MULTI64-X86-64: "-L[[gcc_install]]/../../../../x86_64-unknown-linux/lib/../lib64"
// CHECK-MULTI64-X86-64: "-L[[gcc_install]]/../../../../x86_64-unknown-linux/lib"
// CHECK-MULTI64-X86-64: "-L[[sysroot]]/lib"
// CHECK-MULTI64-X86-64: "-L[[sysroot]]/usr/lib"