This change adds an arch-specific subdirectory in <ResourceDir>/lib/<OS>
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.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
include/clang/Driver/ToolChain.h | ||
---|---|---|
304 ↗ | (On Diff #88631) | Add a period at the end of the sentence. |
The other runtime libraries have the arch included in the library's name and the driver links the correct file. cbergstrom preferred to look in an arch-specific directory rather (http://lists.llvm.org/pipermail/openmp-dev/2017-February/001659.html). It makes sense for OpenMP because other toolchains may assume the standard library name (libomp.so).
Yes, that's the current state. We had some discussion on cfe-dev on that matter: http://lists.llvm.org/pipermail/cfe-dev/2017-January/052512.html
Could you slightly adapt your patch so that other runtime libraries can follow this idea in the future?
lib/Driver/Tools.cpp | ||
---|---|---|
3267 ↗ | (On Diff #88662) | Don't you also need rpath for it? Or is this purely for static runtime? |
lib/Driver/Tools.cpp | ||
---|---|---|
3267 ↗ | (On Diff #88662) | I am doing this for a cross-compiling toolchain (Android NDK) where the actual rpath is not valid at runtime. The runtime is packaged with the application and made available to the loader behind the scenes. That said, I don't think providing an rpath doesn't hurt. I'll wait for input from @cbergstrom and OpenMP folks to see if this'd be useful. |
I still think this should not be done for OpenMP only and hence move out of addOpenMPRuntime.
(Why the heck are there two places to add -lomp?!? I'll clean that up later...)
I am fine to do this more generally, but not sure of the scope. Should this be always added or only if a runtime (sanitizer or openmp or xray) is requested?
I think always. From my point of view, this would be the right solution for my D26244.
Maybe something like the following (without tests):
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index ffb0d60..0f3507d 100644 --- a/include/clang/Driver/ToolChain.h +++ b/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 <ResourceDir>/lib/<OSName>/<arch>. This is used by runtimes (such + /// as OpenMP) to find arch-specific libraries. + const std::string getArchSpecificLibPath() const; + /// needsProfileRT - returns true if instrumentation profile is on. static bool needsProfileRT(const llvm::opt::ArgList &Args); diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 6adc038..ae2c08e 100644 --- a/lib/Driver/ToolChain.cpp +++ b/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)); } +const 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/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index cc7d9e1..c0fb4bc 100644 --- a/lib/Driver/Tools.cpp +++ b/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" @@ -276,8 +277,15 @@ 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"); + + std::string CandidateRPath = TC.getArchSpecificLibPath(); + if (D.getVFS().exists(CandidateRPath)) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); + } + } } /// Add OpenMP linker script arguments at the end of the argument list so that
- Arch-subdir is now always added to -L
- It is added to -rpath during native compilation.
- Tests have been updated
test/Driver/arch-specific-libdir-rpath.c | ||
---|---|---|
6 ↗ | (On Diff #88768) | I feel this test is fragile. Any idea how to further restrict and require that the default target triple has linux and one of i386, x86_64, arm, aarch64? I could create sub-dirs for all archs returned by Triple::getArchTypeName (llvm/lib/Support/Triple.cpp) but it seems overkill. |
test/Driver/arch-specific-libdir.c | ||
---|---|---|
6 ↗ | (On Diff #88768) | Please be more specific in the tests, i.e. check if the correct arch dir is selected. Also add a test for i386-* triple, and make sure that both i386-* and i686-* give the same result. |
test/Driver/arch-specific-libdir-rpath.c | ||
---|---|---|
6 ↗ | (On Diff #88768) | I've restricted the test to just x86_64-linux. |
Please adapt the title and summary for the more general changes this has evolved to.
lib/Driver/Tools.cpp | ||
---|---|---|
284 ↗ | (On Diff #88799) | s/lined/linked/ |
test/Driver/arch-specific-libdir-rpath.c | ||
18 ↗ | (On Diff #88799) | Can you split that into two lines? Then it won't fail if there is some argument added in between |
6 ↗ | (On Diff #88768) | Instead of REQUIRES, you should probably add -target x86_64-unknown-linux |
Thanks. The -L tests look good, -rpath is not perfect but I don't think you can improve it without additional changes to the Driver.
test/Driver/arch-specific-libdir-rpath.c | ||
---|---|---|
6 ↗ | (On Diff #88768) | Hmm, I don't see any good solution for this. Looking at the code, the host triple is hardcoded, so you'd indeed have to either restrict the test to triples matching LLVM_HOST_TRIPLE. Or maybe add a command-line option to override the host triple. |
test/Driver/arch-specific-libdir-rpath.c | ||
---|---|---|
6 ↗ | (On Diff #88768) | Sorry, I missed that it's cross-compiling then. x86_64 is in that case probably the best thing to do because it's most widespread, also among the buildbots. |
lib/Driver/Tools.cpp | ||
---|---|---|
3267 ↗ | (On Diff #88662) | @cbergstrom says: 'let them know that your comments are equivalent (or better) than mine'. But yeah, PathScale's adding rpaths for the libraries on our end, so this is consistent with what we do. |
test/Driver/arch-specific-libdir-rpath.c | ||
---|---|---|
18 ↗ | (On Diff #88799) | Splitting into two lines makes FileCheck eagerly match the arch-subdir and -rpath into the {{.*}} next to the "-L". This causes the check for -rpath to fail. The test accepts intermediate arguments because of the wildcard right after the -L...Inputs/... |
LGTM modulo the test match split. But please wait for someone who has been longer here to confirm.
test/Driver/arch-specific-libdir-rpath.c | ||
---|---|---|
18 ↗ | (On Diff #88799) | Please do not rely on implicit assumptions like that. One day someone may decide to 'fix' the wildcard not to match whitespace, and make the wrong assumption about order. If for anything, splitting in two would make this more readable. |
test/Driver/arch-specific-libdir-rpath.c | ||
---|---|---|
18 ↗ | (On Diff #88799) | Do you have any suggestions? Right now, if I split it into two lines, the second check fails due to the eager regex match. |
@rnk: This patch was to address discussion in http://lists.llvm.org/pipermail/openmp-dev/2017-February/001659.html but now also addresses http://lists.llvm.org/pipermail/cfe-dev/2017-January/052512.html. Can you take a look?
include/clang/Driver/ToolChain.h | ||
---|---|---|
305 ↗ | (On Diff #88865) | Why const qualify the std::string? |
lib/Driver/Tools.cpp | ||
289 ↗ | (On Diff #88865) | We shouldn't add rpath to every binary linked by clang. We should only add rpath when we know the user is linking against a shared library provided by clang. See for example the way the darwin toolchain handles this in Toolchains.cpp. Right now most libraries provided by clang are static, so there hasn't been much need to add rpath, but if we add more shared libraries (xray, sanitizers, profiling, etc), then I think we'll want to do this along with adding an option to suppress the implicit addition of rpath. |
Looks good with a minor comment about a comment in the test case.
lib/Driver/Tools.cpp | ||
---|---|---|
2007–2009 ↗ | (On Diff #90373) | This seems like a really poor heuristic for "will the user ship this binary to another computer that doesn't have clang installed in the same location", but the convenience of not having to add clang's unpredictably named resource library directory to LD_LIBRARY_PATH seems worth baking in a possibly-wrong rpath. |
test/Driver/arch-specific-libdir-rpath.c | ||
9 ↗ | (On Diff #90373) | This comment seems wrong, with -shared-libasan we add it to rpath. It's really, only add rpath if we are using shared libraries. |
Fixed comment in test and added a test for -fsanitize=address without -shared-libasan.
lib/Driver/Tools.cpp | ||
---|---|---|
2007–2009 ↗ | (On Diff #90373) | This is indeed poor, but a good check that omits rpath when it is definitely useless but leave it in case it might be useful. |