From 69a125bf02d608b37880401c0494f589b4999cf1 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 6 Apr 2012 16:32:06 +0000 Subject: [PATCH] Fix using Clang as a cross compiler installed on a host machine and not inside of a sysroot targeting a system+sysroot which is "similar" or "compatible" with the host system. This shows up when trying to build system images on largely compatible hardware as-if fully cross compiled. The problem is that previously we *perfectly* mimiced GCC here, and it turns out GCC has a bug that no one has really stumbled across. GCC will try to look in thy system prefix ('/usr/local' f.ex.) into which it is instaled to find libraries installed along side GCC that should be preferred to the base system libraries ('/usr' f.ex.). This seems not unreasonable, but it has a very unfortunate consequence when combined with a '--sysroot' which does *not* contain the GCC installation we're using to complete the toolchain. That results in some of the host system's library directories being searched during the link. Now, it so happens that most folks doing stuff like this use '--with-sysroot' and '--disable-multilib' when configuring GCC. Even better, they're usually not cross-compiling to a target that is similar to the host. As a result, searching the host for libraries doesn't really matter -- most of the time weird directories get appended that don't exist (no arm triple lib directory, etc). Even if you're cross-compiling from 32-bit to 64-bit x86 or vice-versa, disabling multilib makes it less likely that you'll actually find viable libraries on the host. But that's just luck. We shouldn't rely on this, and this patch disables looking in the system prefix containing the GCC installation if that system prefix is *outside* of the sysroot. For empty sysroots, this has no effect. Similarly, when using the GCC *inside* of the sysroot, we still track wherever it is installed within the sysroot and look there for libraries. But now we can use a cross compiler GCC installation outside the system root, and only look for the crtbegin.o in the GCC installation, and look for all the other libraries inside the system root. This should fix PR12478, allowing Clang to be used when building a ChromiumOS image without polluting the image with libraries from the host system. llvm-svn: 154176 --- clang/lib/Driver/ToolChains.cpp | 25 +++++++++++++++++++------ clang/test/Driver/linux-ld.c | 14 ++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/clang/lib/Driver/ToolChains.cpp b/clang/lib/Driver/ToolChains.cpp index 1eb7c9cdf248..67697569c43f 100644 --- a/clang/lib/Driver/ToolChains.cpp +++ b/clang/lib/Driver/ToolChains.cpp @@ -2059,10 +2059,20 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) addPathIfExists((GCCInstallation.getInstallPath() + GCCInstallation.getMultiarchSuffix()), Paths); - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib, - Paths); - addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); - addPathIfExists(LibPath + "/../" + Multilib, 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 un-intented 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. + if (StringRef(LibPath).startswith(SysRoot)) { + addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib, + Paths); + addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); + addPathIfExists(LibPath + "/../" + Multilib, Paths); + } } addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); @@ -2081,8 +2091,11 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); if (!GCCInstallation.getMultiarchSuffix().empty()) addPathIfExists(GCCInstallation.getInstallPath(), Paths); - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); - addPathIfExists(LibPath, Paths); + + if (StringRef(LibPath).startswith(SysRoot)) { + addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); + addPathIfExists(LibPath, Paths); + } } addPathIfExists(SysRoot + "/lib", Paths); addPathIfExists(SysRoot + "/usr/lib", Paths); diff --git a/clang/test/Driver/linux-ld.c b/clang/test/Driver/linux-ld.c index 7c6cac71b9bb..1ade7f1d0501 100644 --- a/clang/test/Driver/linux-ld.c +++ b/clang/test/Driver/linux-ld.c @@ -92,6 +92,20 @@ // CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib" // // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: -target x86_64-unknown-linux -m32 \ +// RUN: -gcc-toolchain %S/Inputs/multilib_64bit_linux_tree/usr \ +// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-64-TO-32-SYSROOT %s +// CHECK-64-TO-32-SYSROOT: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-64-TO-32-SYSROOT: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o" +// CHECK-64-TO-32-SYSROOT: "-L{{[^"]*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32" +// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/lib/../lib32" +// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/usr/lib/../lib32" +// CHECK-64-TO-32-SYSROOT: "-L{{[^"]*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0" +// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/lib" +// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/usr/lib" +// +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: -target i386-unknown-linux -m32 \ // RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \