From 65a16dd85811f385f36c8d94bb960d88dce9a6c9 Mon Sep 17 00:00:00 2001 From: Pirama Arumuga Nainar Date: Fri, 3 Mar 2017 23:20:49 +0000 Subject: [PATCH] Add arch-specific directory to search path Summary: This change adds an arch-specific subdirectory in /lib/ to the linker search path. This path also gets added as '-rpath' for native compilation if a runtime is linked in as a shared object. This allows arch-specific libraries to be installed alongside clang. Reviewers: danalbert, cbergstrom, javed.absar Subscribers: srhines Differential Revision: https://reviews.llvm.org/D30015 llvm-svn: 296927 --- clang/include/clang/Driver/ToolChain.h | 5 ++ clang/lib/Driver/ToolChain.cpp | 13 +++++ clang/lib/Driver/Tools.cpp | 25 ++++++++- .../lib/linux/aarch64/.keep | 0 .../lib/linux/arm/.keep | 0 .../lib/linux/i386/.keep | 0 .../lib/linux/x86_64/.keep | 0 .../test/Driver/arch-specific-libdir-rpath.c | 50 +++++++++++++++++ clang/test/Driver/arch-specific-libdir.c | 53 +++++++++++++++++++ clang/test/lit.cfg | 4 ++ 10 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/aarch64/.keep create mode 100644 clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/arm/.keep create mode 100644 clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/i386/.keep create mode 100644 clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64/.keep create mode 100644 clang/test/Driver/arch-specific-libdir-rpath.c create mode 100644 clang/test/Driver/arch-specific-libdir.c diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index ffb0d60a6398..7dbe7a96dd5d 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -299,6 +299,11 @@ public: const char *getCompilerRTArgString(const llvm::opt::ArgList &Args, StringRef Component, bool Shared = false) const; + + // Returns /lib//. This is used by runtimes (such + // as OpenMP) to find arch-specific libraries. + std::string getArchSpecificLibPath() const; + /// needsProfileRT - returns true if instrumentation profile is on. static bool needsProfileRT(const llvm::opt::ArgList &Args); diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 6adc0386ee7b..5a2ed0bd69be 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -10,6 +10,7 @@ #include "clang/Driver/ToolChain.h" #include "Tools.h" #include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Driver.h" @@ -74,6 +75,10 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, if (!isThreadModelSupported(A->getValue())) D.Diag(diag::err_drv_invalid_thread_model_for_target) << A->getValue() << A->getAsString(Args); + + std::string CandidateLibPath = getArchSpecificLibPath(); + if (getVFS().exists(CandidateLibPath)) + getFilePaths().push_back(CandidateLibPath); } ToolChain::~ToolChain() { @@ -320,6 +325,14 @@ const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, return Args.MakeArgString(getCompilerRT(Args, Component, Shared)); } +std::string ToolChain::getArchSpecificLibPath() const { + SmallString<128> Path(getDriver().ResourceDir); + StringRef OSLibName = getTriple().isOSFreeBSD() ? "freebsd" : getOS(); + llvm::sys::path::append(Path, "lib", OSLibName, + llvm::Triple::getArchTypeName(getArch())); + return Path.str(); +} + bool ToolChain::needsProfileRT(const ArgList &Args) { if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 283d7ee06258..139fceadc117 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -14,6 +14,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" @@ -238,8 +239,9 @@ static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, // LIBRARY_PATH - included following the user specified library paths. // and only supported on native toolchains. - if (!TC.isCrossCompiling()) + if (!TC.isCrossCompiling()) { addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); + } } /// Add OpenMP linker script arguments at the end of the argument list so that @@ -2000,6 +2002,19 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } } +static void addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + // In the cross-compilation case, arch-specific library path is likely + // unavailable at runtime. + if (TC.isCrossCompiling()) return; + + std::string CandidateRPath = TC.getArchSpecificLibPath(); + if (TC.getVFS().exists(CandidateRPath)) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); + } +} + static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, const ArgList &Args) { if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, @@ -2020,6 +2035,8 @@ static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, // Already diagnosed. break; } + + addArchSpecificRPath(TC, Args, CmdArgs); } static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, @@ -2030,6 +2047,10 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, if (IsWhole) CmdArgs.push_back("-whole-archive"); CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared)); if (IsWhole) CmdArgs.push_back("-no-whole-archive"); + + if (IsShared) { + addArchSpecificRPath(TC, Args, CmdArgs); + } } // Tries to use a file with the list of dynamic symbols that need to be exported @@ -9002,6 +9023,8 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (JA.isHostOffloading(Action::OFK_OpenMP)) CmdArgs.push_back("-lomptarget"); + + addArchSpecificRPath(ToolChain, Args, CmdArgs); } AddRunTimeLibs(ToolChain, D, CmdArgs, Args); diff --git a/clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/aarch64/.keep b/clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/aarch64/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/arm/.keep b/clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/arm/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/i386/.keep b/clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/i386/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64/.keep b/clang/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/arch-specific-libdir-rpath.c b/clang/test/Driver/arch-specific-libdir-rpath.c new file mode 100644 index 000000000000..e6a5da8752cf --- /dev/null +++ b/clang/test/Driver/arch-specific-libdir-rpath.c @@ -0,0 +1,50 @@ +// Test that the driver adds an arch-specific subdirectory in +// {RESOURCE_DIR}/lib/linux to the linker search path and to '-rpath' for native +// compilations. +// +// -rpath only gets added during native compilation. To keep the test simple, +// just test for x86_64-linux native compilation. +// REQUIRES: x86_64-linux +// +// Add LIBPATH but no RPATH for -fsanitizer=address w/o -shared-libasan +// RUN: %clang %s -### 2>&1 -fsanitize=undefined \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,NO-RPATH %s +// +// Add LIBPATH, RPATH for -fsanitize=address -shared-libasan +// RUN: %clang %s -### 2>&1 -target x86_64-linux \ +// RUN: -fsanitize=address -shared-libasan \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,RPATH %s +// +// Add LIBPATH, RPATH with -fsanitize=address for Android +// RUN: %clang %s -### 2>&1 -target x86_64-linux-android -fsanitize=address \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,RPATH %s +// +// Add LIBPATH, RPATH for OpenMP +// RUN: %clang %s -### 2>&1 -fopenmp \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,RPATH %s +// +// Add LIBPATH but no RPATH for ubsan (or any other sanitizer) +// RUN: %clang %s -### 2>&1 -fsanitize=undefined \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,NO-RPATH %s +// +// Add LIBPATH but no RPATH if no sanitizer or runtime is specified +// RUN: %clang %s -### 2>&1 \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,NO-RPATH %s +// +// Do not add LIBPATH or RPATH if arch-specific subdir doesn't exist +// RUN: %clang %s -### 2>&1 \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,NO-LIBPATH,NO-RPATH %s +// +// +// FILEPATH: "-x" "c" "[[FILE_PATH:.*]]/{{.*}}.c" +// LIBPATH: -L[[FILE_PATH]]/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64 +// RPATH: "-rpath" "[[FILE_PATH]]/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64" +// NO-LIBPATH-NOT: -L{{.*}}Inputs/resource_dir +// NO-RPATH-NOT: "-rpath" {{.*}}/Inputs/resource_dir diff --git a/clang/test/Driver/arch-specific-libdir.c b/clang/test/Driver/arch-specific-libdir.c new file mode 100644 index 000000000000..48196e6bdd0e --- /dev/null +++ b/clang/test/Driver/arch-specific-libdir.c @@ -0,0 +1,53 @@ +// Test that the driver adds an arch-specific subdirectory in +// {RESOURCE_DIR}/lib/linux to the search path. +// +// RUN: %clang %s -### 2>&1 -target i386-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-i386 %s +// +// RUN: %clang %s -### 2>&1 -target i386-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s +// +// RUN: %clang %s -### 2>&1 -target i686-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-i386 %s +// +// RUN: %clang %s -### 2>&1 -target i686-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s +// +// RUN: %clang %s -### 2>&1 -target x86_64-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-x86_64 %s +// +// RUN: %clang %s -### 2>&1 -target x86_64-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s +// +// RUN: %clang %s -### 2>&1 -target arm-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-arm %s +// +// RUN: %clang %s -### 2>&1 -target arm-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s +// +// RUN: %clang %s -### 2>&1 -target aarch64-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-aarch64 %s +// +// RUN: %clang %s -### 2>&1 -target aarch64-unknown-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s +// +// +// FILEPATH: "-x" "c" "[[FILE_PATH:.*]]/{{.*}}.c" +// ARCHDIR-i386: -L[[FILE_PATH]]/Inputs/resource_dir_with_arch_subdir/lib/linux/i386 +// ARCHDIR-x86_64: -L[[FILE_PATH]]/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64 +// ARCHDIR-arm: -L[[FILE_PATH]]/Inputs/resource_dir_with_arch_subdir/lib/linux/arm +// ARCHDIR-aarch64: -L[[FILE_PATH]]/Inputs/resource_dir_with_arch_subdir/lib/linux/aarch64 +// +// Have a stricter check for no-archdir - that the driver doesn't add any +// subdirectory from the provided resource directory. +// NO-ARCHDIR-NOT: -L[[FILE_PATH]]/Inputs/resource_dir diff --git a/clang/test/lit.cfg b/clang/test/lit.cfg index 2b494c491097..5beecb65bd66 100644 --- a/clang/test/lit.cfg +++ b/clang/test/lit.cfg @@ -397,6 +397,10 @@ if platform.system() not in ['Darwin', 'Fuchsia']: if config.host_triple == config.target_triple: config.available_features.add("native") +# Test Driver/arch-specific-libdir-rpath.c is restricted to x86_64-linux +if re.match(r'^x86_64.*-linux', config.target_triple): + config.available_features.add("x86_64-linux") + # Case-insensitive file system def is_filesystem_case_insensitive(): handle, path = tempfile.mkstemp(prefix='case-test', dir=config.test_exec_root)