Index: clang/lib/Driver/ToolChains/Gnu.h =================================================================== --- clang/lib/Driver/ToolChains/Gnu.h +++ clang/lib/Driver/ToolChains/Gnu.h @@ -314,6 +314,16 @@ /// Check whether the target triple's architecture is 32-bits. bool isTarget32Bit() const { return getTriple().isArch32Bit(); } + void PushGCCPPaths(ToolChain::path_list &PPaths); + void AddGCCMultilibPaths(const Driver &D, const std::string &SysRoot, + const std::string &OSLibDir, + const std::string &MultiarchTriple, + path_list &Paths); + void AddGCCMultiarchPaths(const Driver &D, const std::string &SysRoot, + const std::string &OSLibDir, path_list &Paths); + void AddGCCClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + // FIXME: This should be final, but the CrossWindows toolchain does weird // things that can't be easily generalized. void AddClangCXXStdlibIncludeArgs( Index: clang/lib/Driver/ToolChains/Gnu.cpp =================================================================== --- clang/lib/Driver/ToolChains/Gnu.cpp +++ clang/lib/Driver/ToolChains/Gnu.cpp @@ -35,6 +35,7 @@ using namespace llvm::opt; using tools::addMultilibFlag; +using tools::addPathIfExists; void tools::GnuTool::anchor() {} @@ -2666,6 +2667,140 @@ } } +static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, + const Multilib &Multilib, + StringRef InstallPath, + ToolChain::path_list &Paths) { + if (const auto &PathsCallback = Multilibs.filePathsCallback()) + for (const auto &Path : PathsCallback(Multilib)) + addPathIfExists(D, InstallPath + Path, Paths); +} + +void Generic_GCC::PushGCCPPaths(ToolChain::path_list &PPaths) { + // Cross-compiling binutils and GCC installations (vanilla and openSUSE at + // least) put various tools in a triple-prefixed directory off of the parent + // of the GCC installation. We use the GCC triple here to ensure that we end + // up with tools that support the same amount of cross compiling as the + // detected GCC installation. For example, if we find a GCC installation + // targeting x86_64, but it is a bi-arch GCC installation, it can also be + // used to target i386. + if (GCCInstallation.isValid()) { + PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple().str() + "/bin") + .str()); + } +} + +void Generic_GCC::AddGCCMultilibPaths(const Driver &D, + const std::string &SysRoot, + const std::string &OSLibDir, + const std::string &MultiarchTriple, + path_list &Paths) { + // Add the multilib suffixed paths where they are available. + if (GCCInstallation.isValid()) { + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); + const std::string &LibPath = + std::string(GCCInstallation.getParentLibPath()); + + // Add toolchain / multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, SelectedMultilib, + GCCInstallation.getInstallPath(), Paths); + + // Sourcery CodeBench MIPS toolchain holds some libraries under + // a biarch-like suffix of the GCC installation. + addPathIfExists( + D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(), + Paths); + + // GCC cross compiling toolchains will install target libraries which ship + // as part of the toolchain under // rather than as + // any part of the GCC installation in + // //gcc//. 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 targeting 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 present on the system root and found via an + // appropriate rpath. + // 2) There must not be libraries installed into + // // 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(D, + LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + + SelectedMultilib.osSuffix(), + 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. 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(D, LibPath + "/" + MultiarchTriple, Paths); + addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); + } + } +} + +void Generic_GCC::AddGCCMultiarchPaths(const Driver &D, + const std::string &SysRoot, + const std::string &OSLibDir, + path_list &Paths) { + // Try walking via the GCC triple path in case of biarch or multiarch GCC + // installations with strange symlinks. + if (GCCInstallation.isValid()) { + addPathIfExists(D, + SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + + "/../../" + OSLibDir, + Paths); + + // Add the 'other' biarch variant path + Multilib BiarchSibling; + if (GCCInstallation.getBiarchSibling(BiarchSibling)) { + addPathIfExists( + D, GCCInstallation.getInstallPath() + BiarchSibling.gccSuffix(), + Paths); + } + + // See comments above on the multilib variant for details of why this is + // included even from outside the sysroot. + const std::string &LibPath = + std::string(GCCInstallation.getParentLibPath()); + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + addPathIfExists( + D, LibPath + "/../" + GCCTriple.str() + "/lib" + Multilib.osSuffix(), + 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(D, LibPath, Paths); + } +} + +void Generic_GCC::AddGCCClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + // Add include directories specific to the selected multilib set and multilib. + if (GCCInstallation.isValid()) { + const auto &Callback = Multilibs.includeDirsCallback(); + if (Callback) { + for (const auto &Path : Callback(GCCInstallation.getMultilib())) + addExternCSystemIncludeIfExists( + DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); + } + } +} + void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || Index: clang/lib/Driver/ToolChains/Hurd.cpp =================================================================== --- clang/lib/Driver/ToolChains/Hurd.cpp +++ clang/lib/Driver/ToolChains/Hurd.cpp @@ -64,7 +64,19 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { + GCCInstallation.init(Triple, Args); + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilib = GCCInstallation.getMultilib(); std::string SysRoot = computeSysRoot(); + ToolChain::path_list &PPaths = getProgramPaths(); + + Generic_GCC::PushGCCPPaths(PPaths); + + // The selection of paths to try here is designed to match the patterns which + // 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 std::string OSLibDir = std::string(getOSLibDir(Triple, Args)); @@ -74,8 +86,12 @@ ExtraOpts.push_back("--build-id"); #endif - // If we are currently running Clang inside of the requested system root, add - // its parent library paths to those searched. + Generic_GCC::AddGCCMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, + Paths); + + // Similar to the logic for GCC above, if we currently running Clang inside + // of the requested system root, add its parent library paths to + // those searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) { @@ -89,8 +105,11 @@ addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); - // If we are currently running Clang inside of the requested system root, add - // its parent library path to those searched. + Generic_GCC::AddGCCMultiarchPaths(D, SysRoot, OSLibDir, Paths); + + // Similar to the logic for GCC above, if we are currently running Clang + // inside of the requested system root, add its parent library path to those + // searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) @@ -157,6 +176,9 @@ // Lacking those, try to detect the correct set of system includes for the // target triple. + + AddGCCClangSystemIncludeArgs(DriverArgs, CC1Args); + if (getTriple().getArch() == llvm::Triple::x86) { std::string Path = SysRoot + "/usr/include/i386-gnu"; if (D.getVFS().exists(Path)) Index: clang/lib/Driver/ToolChains/Linux.cpp =================================================================== --- clang/lib/Driver/ToolChains/Linux.cpp +++ clang/lib/Driver/ToolChains/Linux.cpp @@ -208,15 +208,6 @@ return Triple.isArch32Bit() ? "lib" : "lib64"; } -static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, - const Multilib &Multilib, - StringRef InstallPath, - ToolChain::path_list &Paths) { - if (const auto &PathsCallback = Multilibs.filePathsCallback()) - for (const auto &Path : PathsCallback(Multilib)) - addPathIfExists(D, InstallPath + Path, Paths); -} - Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); @@ -224,21 +215,9 @@ SelectedMultilib = GCCInstallation.getMultilib(); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); - - // Cross-compiling binutils and GCC installations (vanilla and openSUSE at - // least) put various tools in a triple-prefixed directory off of the parent - // of the GCC installation. We use the GCC triple here to ensure that we end - // up with tools that support the same amount of cross compiling as the - // detected GCC installation. For example, if we find a GCC installation - // targeting x86_64, but it is a bi-arch GCC installation, it can also be - // used to target i386. - // FIXME: This seems unlikely to be Linux-specific. ToolChain::path_list &PPaths = getProgramPaths(); - if (GCCInstallation.isValid()) { - PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + - GCCInstallation.getTriple().str() + "/bin") - .str()); - } + + Generic_GCC::PushGCCPPaths(PPaths); Distro Distro(D.getVFS(), Triple); @@ -317,58 +296,8 @@ const std::string OSLibDir = std::string(getOSLibDir(Triple, Args)); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); - // Add the multilib suffixed paths where they are available. - if (GCCInstallation.isValid()) { - const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); - const std::string &LibPath = - std::string(GCCInstallation.getParentLibPath()); - - // Add toolchain / multilib specific file paths. - addMultilibsFilePaths(D, Multilibs, SelectedMultilib, - GCCInstallation.getInstallPath(), Paths); - - // Sourcery CodeBench MIPS toolchain holds some libraries under - // a biarch-like suffix of the GCC installation. - addPathIfExists( - D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(), - Paths); - - // GCC cross compiling toolchains will install target libraries which ship - // as part of the toolchain under // rather than as - // any part of the GCC installation in - // //gcc//. 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 targeting 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 present on the system root and found via an - // appropriate rpath. - // 2) There must not be libraries installed into - // // 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(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + - OSLibDir + SelectedMultilib.osSuffix(), - 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. 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(D, LibPath + "/" + MultiarchTriple, Paths); - addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); - } - } + Generic_GCC::AddGCCMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, + Paths); // Similar to the logic for GCC above, if we currently running Clang inside // of the requested system root, add its parent library paths to @@ -412,37 +341,7 @@ addPathIfExists(D, SysRoot + "/usr/" + OSLibDir + "/" + ABIName, Paths); } - // Try walking via the GCC triple path in case of biarch or multiarch GCC - // installations with strange symlinks. - if (GCCInstallation.isValid()) { - addPathIfExists(D, - SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + - "/../../" + OSLibDir, - Paths); - - // Add the 'other' biarch variant path - Multilib BiarchSibling; - if (GCCInstallation.getBiarchSibling(BiarchSibling)) { - addPathIfExists(D, GCCInstallation.getInstallPath() + - BiarchSibling.gccSuffix(), - Paths); - } - - // See comments above on the multilib variant for details of why this is - // included even from outside the sysroot. - const std::string &LibPath = - std::string(GCCInstallation.getParentLibPath()); - const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + - Multilib.osSuffix(), - 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(D, LibPath, Paths); - } + Generic_GCC::AddGCCMultiarchPaths(D, SysRoot, OSLibDir, Paths); // Similar to the logic for GCC above, if we are currently running Clang // inside of the requested system root, add its parent library path to those @@ -685,15 +584,7 @@ // Lacking those, try to detect the correct set of system includes for the // target triple. - // Add include directories specific to the selected multilib set and multilib. - if (GCCInstallation.isValid()) { - const auto &Callback = Multilibs.includeDirsCallback(); - if (Callback) { - for (const auto &Path : Callback(GCCInstallation.getMultilib())) - addExternCSystemIncludeIfExists( - DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); - } - } + AddGCCClangSystemIncludeArgs(DriverArgs, CC1Args); // Implement generic Debian multiarch support. const StringRef X86_64MultiarchIncludeDirs[] = { Index: clang/test/Driver/Inputs/basic_cross_hurd_tree/usr/i386-gnu/bin/as =================================================================== --- /dev/null +++ clang/test/Driver/Inputs/basic_cross_hurd_tree/usr/i386-gnu/bin/as @@ -0,0 +1 @@ +#!/bin/true Index: clang/test/Driver/Inputs/basic_cross_hurd_tree/usr/i386-gnu/bin/ld =================================================================== --- /dev/null +++ clang/test/Driver/Inputs/basic_cross_hurd_tree/usr/i386-gnu/bin/ld @@ -0,0 +1 @@ +ld.gold \ No newline at end of file Index: clang/test/Driver/Inputs/basic_cross_hurd_tree/usr/i386-gnu/bin/ld.bfd =================================================================== --- /dev/null +++ clang/test/Driver/Inputs/basic_cross_hurd_tree/usr/i386-gnu/bin/ld.bfd @@ -0,0 +1 @@ +#!/bin/true Index: clang/test/Driver/Inputs/basic_cross_hurd_tree/usr/i386-gnu/bin/ld.gold =================================================================== --- /dev/null +++ clang/test/Driver/Inputs/basic_cross_hurd_tree/usr/i386-gnu/bin/ld.gold @@ -0,0 +1 @@ +#!/bin/true Index: clang/test/Driver/hurd.c =================================================================== --- clang/test/Driver/hurd.c +++ clang/test/Driver/hurd.c @@ -11,7 +11,7 @@ // CHECK: "-internal-externc-isystem" "[[SYSROOT]]/usr/include" // CHECK: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" // CHECK: "-dynamic-linker" "/lib/ld.so" -// CHECK: "crtbegin.o" +// CHECK: "{{.*}}/usr/lib/gcc/i386-gnu/4.6.0{{/|\\\\}}crtbegin.o" // CHECK: "-L[[SYSROOT]]/lib/i386-gnu" // CHECK: "-L[[SYSROOT]]/lib/../lib32" // CHECK: "-L[[SYSROOT]]/usr/lib/i386-gnu" @@ -33,7 +33,7 @@ // CHECK-STATIC: "-internal-externc-isystem" "[[SYSROOT]]/usr/include" // CHECK-STATIC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" // CHECK-STATIC: "-static" -// CHECK-STATIC: "crtbeginT.o" +// CHECK-STATIC: "{{.*}}/usr/lib/gcc/i386-gnu/4.6.0{{/|\\\\}}crtbeginT.o" // CHECK-STATIC: "-L[[SYSROOT]]/lib/i386-gnu" // CHECK-STATIC: "-L[[SYSROOT]]/lib/../lib32" // CHECK-STATIC: "-L[[SYSROOT]]/usr/lib/i386-gnu" @@ -53,10 +53,21 @@ // CHECK-SHARED: "-internal-externc-isystem" "[[SYSROOT]]/include" // CHECK-SHARED: "-internal-externc-isystem" "[[SYSROOT]]/usr/include" // CHECK-SHARED: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" -// CHECK-SHARED: "crtbeginS.o" +// CHECK-SHARED: "{{.*}}/usr/lib/gcc/i386-gnu/4.6.0{{/|\\\\}}crtbeginS.o" // CHECK-SHARED: "-L[[SYSROOT]]/lib/i386-gnu" // CHECK-SHARED: "-L[[SYSROOT]]/lib/../lib32" // CHECK-SHARED: "-L[[SYSROOT]]/usr/lib/i386-gnu" // CHECK-SHARED: "-L[[SYSROOT]]/usr/lib/../lib32" // CHECK-SHARED: "-L[[SYSROOT]]/lib" // CHECK-SHARED: "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \ +// RUN: --gcc-toolchain=%S/Inputs/basic_cross_hurd_tree/usr \ +// RUN: --target=i386-pc-gnu \ +// RUN: | FileCheck --check-prefix=CHECK-CROSS %s +// CHECK-CROSS-NOT: warning: +// CHECK-CROSS: "-cc1" "-triple" "i386-pc-hurd-gnu" +// CHECK-CROSS: "{{.*}}/Inputs/basic_cross_hurd_tree/usr/lib/gcc/i386-gnu/4.6.0/../../../../i386-gnu/bin{{/|\\\\}}as" "--32" +// CHECK-CROSS: "{{.*}}/Inputs/basic_cross_hurd_tree/usr/lib/gcc/i386-gnu/4.6.0/../../../../i386-gnu/bin{{/|\\\\}}ld" {{.*}} "-m" "elf_i386" +// CHECK-CROSS: "{{.*}}/Inputs/basic_cross_hurd_tree/usr/lib/gcc/i386-gnu/4.6.0{{/|\\\\}}crtbegin.o" +// CHECK-CROSS: "-L{{.*}}/Inputs/basic_cross_hurd_tree/usr/lib/gcc/i386-gnu/4.6.0/../../../../i386-gnu/lib"