Rework the selection of builtin library search paths on Linux to

precisely match the pattern and logic used by the GCC driver on Linux as
of a recent SVN checkout.

This happens to follow a *much* more principled approach. There is
a strict hierarchy of paths examined, first with multilib-suffixing,
second without such suffixing. Any and all of these directories which
exist will be added to the library search path when using GCC.

There were many places where Clang followed different paths, omitted
critical entries, and worst of all (in terms of challenges to debugging)
got the entries in a subtly wrong order.

If this breaks Clang on a distro you use, please let me know, and I'll
work with you to figure out what is needed to work on that distro. I've
checked the behavior of the latest release of Ubuntu, OpenSUSE, Fedora,
and Gentoo. I'll be testing it on those as well as Debian stable and
unstable and ArchLinux. I may even dig out a Slackware install.

No real regression tests yet, those will follow once I add enough
support for sysroot to simulate various distro layouts in the testsuite.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140981 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chandler Carruth 2011-10-03 05:28:29 +00:00
Родитель 78dd67e78c
Коммит d2deee17ad
2 изменённых файлов: 46 добавлений и 35 удалений

Просмотреть файл

@ -1549,6 +1549,13 @@ static std::string findGCCBaseLibDir(const Driver &D,
return ""; return "";
} }
static void addPathIfExists(const std::string &Path,
ToolChain::path_list &Paths) {
bool Exists;
if (!llvm::sys::fs::exists(Path, Exists) && Exists)
Paths.push_back(Path);
}
Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
: Generic_ELF(Host, Triple) { : Generic_ELF(Host, Triple) {
llvm::Triple::ArchType Arch = llvm::Triple::ArchType Arch =
@ -1626,25 +1633,6 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
} }
std::string Base = findGCCBaseLibDir(getDriver(), GccTriple); std::string Base = findGCCBaseLibDir(getDriver(), GccTriple);
path_list &Paths = getFilePaths();
bool Is32Bits = (getArch() == llvm::Triple::x86 ||
getArch() == llvm::Triple::ppc);
const std::string Suffix32 = Arch == llvm::Triple::x86_64 ? "/32" : "";
const std::string Suffix64 = Is32Bits ? "/64" : "";
const std::string Suffix = Is32Bits ? Suffix32 : Suffix64;
std::string Lib32 = "lib";
if (!llvm::sys::fs::exists("/lib32", Exists) && Exists)
Lib32 = "lib32";
std::string Lib64 = "lib";
bool Symlink;
if (!llvm::sys::fs::exists("/lib64", Exists) && Exists &&
(llvm::sys::fs::is_symlink("/lib64", Symlink) || !Symlink))
Lib64 = "lib64";
std::string Lib = Is32Bits ? Lib32 : Lib64;
// OpenSuse stores the linker with the compiler, add that to the search // OpenSuse stores the linker with the compiler, add that to the search
// path. // path.
@ -1685,27 +1673,50 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (IsOpenSuse(Distro)) if (IsOpenSuse(Distro))
ExtraOpts.push_back("--enable-new-dtags"); ExtraOpts.push_back("--enable-new-dtags");
if (Distro == ArchLinux) // The selection of paths to try here is designed to match the patterns which
Lib = "lib"; // the GCC driver itself uses, as this is part of the GCC-compatible driver.
// This was determined by running GCC in a fake filesystem, creating all
// possible permutations of these directories, and seeing which ones it added
// to the link paths.
path_list &Paths = getFilePaths();
const bool Is32Bits = (getArch() == llvm::Triple::x86 ||
getArch() == llvm::Triple::ppc);
Paths.push_back(Base + Suffix); const std::string Suffix32 = Arch == llvm::Triple::x86_64 ? "/32" : "";
const std::string Suffix64 = Is32Bits ? "/64" : "";
const std::string Suffix = Is32Bits ? Suffix32 : Suffix64;
const std::string Multilib = Is32Bits ? "lib32" : "lib64";
// FIXME: Because we add paths only when they exist on the system, I think we
// should remove the concept of 'HasMultilib'. It's more likely to break the
// behavior than to preserve any useful invariant on the system.
if (HasMultilib(Arch, Distro)) { if (HasMultilib(Arch, Distro)) {
// FIXME: This OpenSuse-specific path shouldn't be needed any more, but
// I don't want to remove it without finding someone to test.
if (IsOpenSuse(Distro) && Is32Bits) if (IsOpenSuse(Distro) && Is32Bits)
Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib"); Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib");
Paths.push_back(Base + "/../../../../" + Lib);
// Add the multilib suffixed paths.
if (!Base.empty() && !GccTriple.empty()) {
addPathIfExists(Base + Suffix, Paths);
addPathIfExists(Base + "/../../../../" + GccTriple + "/lib/../" +
Multilib, Paths);
addPathIfExists(Base + "/../../../../" + Multilib, Paths);
}
addPathIfExists("/lib/../" + Multilib, Paths);
addPathIfExists("/usr/lib/../" + Multilib, Paths);
} }
// FIXME: This is in here to find crt1.o. It is provided by libc, and // Add the non-multiplib suffixed paths (if potentially different).
// libc (like gcc), can be installed in any directory. Once we are if (!Base.empty() && !GccTriple.empty()) {
// fetching this from a config file, we should have a libc prefix. if (!Suffix.empty())
Paths.push_back("/lib/../" + Lib); addPathIfExists(Base, Paths);
Paths.push_back("/usr/lib/../" + Lib); addPathIfExists(Base + "/../../../../" + GccTriple + "/lib", Paths);
addPathIfExists(Base + "/../../..", Paths);
}
addPathIfExists("/lib", Paths);
addPathIfExists("/usr/lib", Paths);
if (!Suffix.empty())
Paths.push_back(Base);
if (IsOpenSuse(Distro))
Paths.push_back(Base + "/../../../../" + GccTriple + "/lib");
Paths.push_back(Base + "/../../..");
if (Arch == getArch() && IsUbuntu(Distro)) if (Arch == getArch() && IsUbuntu(Distro))
Paths.push_back("/usr/lib/" + GccTriple); Paths.push_back("/usr/lib/" + GccTriple);
} }

Просмотреть файл

@ -2,8 +2,8 @@
// //
// RUN: %clang -no-canonical-prefixes -ccc-host-triple i386-unknown-linux %s -### -o %t.o 2>&1 \ // RUN: %clang -no-canonical-prefixes -ccc-host-triple i386-unknown-linux %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s // RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" {{.*}} "-L/lib/../lib{{(32)?}}" "-L/usr/lib/../lib{{(32)?}}" // CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" {{.*}} "-L/lib" "-L/usr/lib"
// //
// RUN: %clang -no-canonical-prefixes -ccc-host-triple x86_64-unknown-linux %s -### -o %t.o 2>&1 \ // RUN: %clang -no-canonical-prefixes -ccc-host-triple x86_64-unknown-linux %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s // RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" {{.*}} "-L/lib/../lib{{(64)?}}" "-L/usr/lib/../lib{{(64)?}}" // CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" {{.*}} "-L/lib" "-L/usr/lib"