[lld] r212706 - [mach-o]: support -syslibroot and -l options
Tim Northover
tnorthover at apple.com
Thu Jul 10 04:21:06 PDT 2014
Author: tnorthover
Date: Thu Jul 10 06:21:06 2014
New Revision: 212706
URL: http://llvm.org/viewvc/llvm-project?rev=212706&view=rev
Log:
[mach-o]: support -syslibroot and -l options
These behave slightly idiosyncratically in the best of cases, and have
additional hacks layered on top of that for compatibility with badly behaved
build systems (via ld64).
For -lXYZ:
+ If XYZ is actually XY.o then search all library paths for XY.o
+ Otherwise search all library paths, first for libXYZ.dylib, then libXYZ.a
+ By default the library paths are /usr/lib and /usr/local/lib in that order.
For -syslibroot:
+ -syslibroot options apply to absolute paths in the search order.
+ All -syslibroot prefixes that exist are added to the search path *instead*
of the original.
+ If no -syslibroot prefixed path exists, the original is kept.
+ Hacks^WExceptions:
+ If only 1 -syslibroot is given and doesn't contain /usr/lib or
/usr/local/lib, that path is dropped entirely. (rdar://problem/6438270).
+ If the last -syslibroot is "/", all of them are ignored entirely.
(rdar://problem/5829579).
At least, that's my best interpretation of what ld64 does in buildSearchPaths.
Added:
lld/trunk/test/mach-o/Inputs/lib-search-paths/
lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/
lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/
lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib (with props)
lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a
lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/local/
lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/local/lib/
lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o
lld/trunk/test/mach-o/lib-search-paths.yaml
lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml
lld/trunk/test/mach-o/libresolve-multiple-syslibroots.yaml
lld/trunk/test/mach-o/libresolve-one-syslibroot.yaml
lld/trunk/test/mach-o/libresolve-simple.yaml
Modified:
lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
lld/trunk/lib/Driver/DarwinLdDriver.cpp
lld/trunk/lib/Driver/DarwinLdOptions.td
lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=212706&r1=212705&r2=212706&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Thu Jul 10 06:21:06 2014
@@ -17,6 +17,8 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachO.h"
+#include <set>
+
using llvm::MachO::HeaderFileType;
namespace lld {
@@ -78,6 +80,38 @@ public:
void setDoNothing(bool value) { _doNothing = value; }
bool doNothing() const { return _doNothing; }
bool printAtoms() const { return _printAtoms; }
+ bool testingLibResolution() const { return _testingLibResolution; }
+ const StringRefVector &searchDirs() const { return _searchDirs; }
+
+ /// \brief Checks whether a given path on the filesystem exists.
+ ///
+ /// When running in -test_libresolution mode, this method consults an
+ /// internally maintained list of files that exist (provided by -path_exists)
+ /// instead of the actual filesystem.
+ bool pathExists(StringRef path) const;
+
+ /// \brief Adds any library search paths derived from the given base, possibly
+ /// modified by -syslibroots.
+ ///
+ /// The set of paths added consists of approximately all syslibroot-prepended
+ /// versions of libPath that exist, or the original libPath if there are none
+ /// for whatever reason. With various edge-cases for compatibility.
+ void addModifiedSearchDir(StringRef libPath,
+ const StringRefVector &syslibRoots,
+ bool isSystemPath = false);
+
+ /// \brief Determine whether -lFoo can be resolve within the given path, and
+ /// return the filename if so.
+ ///
+ /// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in
+ /// that order, unless Foo ends in ".o", in which case only the exact file
+ /// matches (e.g. -lfoo.o would only find foo.o).
+ ErrorOr<StringRef> searchDirForLibrary(StringRef path,
+ StringRef libName) const;
+
+ /// \brief Iterates through all search path entries lookinf for libName (as
+ /// specified by -lFoo).
+ ErrorOr<StringRef> searchLibrary(StringRef libName) const;
/// \brief The dylib's binary compatibility version, in the raw uint32 format.
///
@@ -125,6 +159,13 @@ public:
}
void setBundleLoader(StringRef loader) { _bundleLoader = loader; }
void setPrintAtoms(bool value=true) { _printAtoms = value; }
+ void setTestingLibResolution(bool value = true) {
+ _testingLibResolution = value;
+ }
+ void addExistingPathForDebug(StringRef path) {
+ _existingPaths.insert(path);
+ }
+
StringRef dyldPath() const { return "/usr/lib/dyld"; }
static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
@@ -153,6 +194,8 @@ private:
static ArchInfo _s_archInfos[];
+ std::set<StringRef> _existingPaths; // For testing only.
+ StringRefVector _searchDirs;
HeaderFileType _outputMachOType; // e.g MH_EXECUTE
bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog
bool _doNothing; // for -help and -v which just print info
@@ -166,6 +209,7 @@ private:
StringRef _installName;
bool _deadStrippableDylib;
bool _printAtoms;
+ bool _testingLibResolution;
StringRef _bundleLoader;
mutable std::unique_ptr<mach_o::KindHandler> _kindHandler;
mutable std::unique_ptr<Writer> _writer;
Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=212706&r1=212705&r2=212706&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Thu Jul 10 06:21:06 2014
@@ -263,12 +263,76 @@ bool DarwinLdDriver::parse(int argc, con
if (parsedArgs->getLastArg(OPT_print_atoms))
ctx.setPrintAtoms();
+ // In -test_libresolution mode, we'll be given an explicit list of paths that
+ // exist. We'll also be expected to print out information about how we located
+ // libraries and so on that the user specified, but not to actually do any
+ // linking.
+ if (parsedArgs->getLastArg(OPT_test_libresolution)) {
+ ctx.setTestingLibResolution();
+
+ // With paths existing by fiat, linking is not going to end well.
+ ctx.setDoNothing(true);
+
+ // Only bother looking for an existence override if we're going to use it.
+ for (auto existingPath : parsedArgs->filtered(OPT_path_exists)) {
+ ctx.addExistingPathForDebug(existingPath->getValue());
+ }
+ }
+
std::unique_ptr<InputGraph> inputGraph(new InputGraph());
+ // Now construct the set of library search directories, following ld64's
+ // baroque set of accumulated hacks. Mostly, the algorithm constructs
+ // { syslibroots } x { libpaths }
+ //
+ // Unfortunately, there are numerous exceptions:
+ // 1. Only absolute paths get modified by syslibroot options.
+ // 2. If there is just 1 -syslibroot, system paths not found in it are
+ // skipped.
+ // 3. If the last -syslibroot is "/", all of them are ignored entirely.
+ // 4. If { syslibroots } x path == {}, the original path is kept.
+ std::vector<StringRef> syslibRoots;
+ for (auto syslibRoot : parsedArgs->filtered(OPT_syslibroot)) {
+ syslibRoots.push_back(syslibRoot->getValue());
+ }
+
+ // FIXME: handle -L options: these get added *before* the default paths,
+ // possibly modified by any syslibroot options.
+ ctx.addModifiedSearchDir("/usr/lib", syslibRoots, true);
+ ctx.addModifiedSearchDir("/usr/local/lib", syslibRoots, true);
+
+ // Now that we've constructed the final set of search paths, print out what
+ // we'll be using for testing purposes.
+ if (ctx.testingLibResolution()) {
+ diagnostics << "Library search paths:\n";
+ for (auto path : ctx.searchDirs()) {
+ diagnostics << " " << path << '\n';
+ }
+ }
+
// Handle input files
- for (auto &inputFile : parsedArgs->filtered(OPT_INPUT)) {
+ for (auto &arg : *parsedArgs) {
+ StringRef inputPath;
+ switch (arg->getOption().getID()) {
+ default:
+ continue;
+ case OPT_INPUT:
+ inputPath = arg->getValue();
+ break;
+ case OPT_l: {
+ ErrorOr<StringRef> resolvedPath = ctx.searchLibrary(arg->getValue());
+ if (!resolvedPath) {
+ diagnostics << "Unable to find library -l" << arg->getValue() << "\n";
+ return false;
+ } else if (ctx.testingLibResolution()) {
+ diagnostics << "Found library " << resolvedPath.get() << '\n';
+ }
+ inputPath = resolvedPath.get();
+ break;
+ }
+ }
inputGraph->addInputElement(std::unique_ptr<InputElement>(
- new MachOFileNode(ctx, inputFile->getValue(), globalWholeArchive)));
+ new MachOFileNode(ctx, inputPath, globalWholeArchive)));
}
if (!inputGraph->size()) {
Modified: lld/trunk/lib/Driver/DarwinLdOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdOptions.td?rev=212706&r1=212705&r2=212706&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdOptions.td (original)
+++ lld/trunk/lib/Driver/DarwinLdOptions.td Thu Jul 10 06:21:06 2014
@@ -69,10 +69,23 @@ def L : Joined<["-"], "L">,
def all_load : Flag<["-"], "all_load">,
HelpText<"Forces all members of all static libraries to be loaded">,
Group<grp_libs>;
+def syslibroot : Separate<["-"], "syslibroot">,
+ HelpText<"Add path to SDK to all absolute library search paths">,
+ Group<grp_libs>;
+
+// Input options
+def l : Joined<["-"], "l">,
+ HelpText<"Base name of library searched for in -L directories">;
// test case options
-def print_atoms : Flag<["-"], "print_atoms">,
+def print_atoms : Flag<["-"], "print_atoms">,
HelpText<"Emit output as yaml atoms">;
+def test_libresolution : Flag<["-"], "test_libresolution">,
+ HelpText<"Only files specified by -file_exists are considered to exist."
+ " Print debugging information during resolution">;
+def path_exists : Separate<["-"], "path_exists">,
+ HelpText<"When used with -test_libresolution, only these paths exist">;
+
// general options
def output : Separate<["-"], "o">, HelpText<"Output file path">;
Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=212706&r1=212705&r2=212706&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Thu Jul 10 06:21:06 2014
@@ -20,8 +20,10 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MachO.h"
+#include "llvm/Support/Path.h"
using lld::mach_o::KindHandler;
using namespace llvm::MachO;
@@ -123,7 +125,7 @@ MachOLinkingContext::MachOLinkingContext
_doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
_pageZeroSize(0), _pageSize(4096), _compatibilityVersion(0),
_currentVersion(0), _deadStrippableDylib(false), _printAtoms(false),
- _kindHandler(nullptr) {}
+ _testingLibResolution(false), _kindHandler(nullptr) {}
MachOLinkingContext::~MachOLinkingContext() {}
@@ -262,6 +264,87 @@ bool MachOLinkingContext::addUnixThreadL
}
}
+bool MachOLinkingContext::pathExists(StringRef path) const {
+ if (!testingLibResolution())
+ return llvm::sys::fs::exists(path.str());
+
+ // Otherwise, we're in test mode: only files explicitly provided on the
+ // command-line exist.
+ return _existingPaths.find(path) != _existingPaths.end();
+}
+
+void MachOLinkingContext::addModifiedSearchDir(
+ StringRef libPath, const StringRefVector &syslibRoots, bool isSystemPath) {
+ bool addedModifiedPath = false;
+
+ // Two cases to consider here:
+ // + If the last -syslibroot is "/", all of them are ignored (don't ask).
+ // + -syslibroot only applies to absolute paths.
+ if (!syslibRoots.empty() && syslibRoots.back() != "/" &&
+ llvm::sys::path::is_absolute(libPath)) {
+ for (auto syslibRoot : syslibRoots) {
+ SmallString<256> path(syslibRoot);
+ llvm::sys::path::append(path, libPath);
+ if (pathExists(path)) {
+ _searchDirs.push_back(path.str().copy(_allocator));
+ addedModifiedPath = true;
+ }
+ }
+ }
+
+ if (addedModifiedPath)
+ return;
+
+ // Finally, if only one -syslibroot is given, system paths which aren't in it
+ // get suppressed.
+ if (syslibRoots.size() != 1 || !isSystemPath) {
+ if (pathExists(libPath)) {
+ _searchDirs.push_back(libPath);
+ }
+ }
+}
+
+ErrorOr<StringRef>
+MachOLinkingContext::searchDirForLibrary(StringRef path,
+ StringRef libName) const {
+ SmallString<256> fullPath;
+ if (libName.endswith(".o")) {
+ // A request ending in .o is special: just search for the file directly.
+ fullPath.assign(path);
+ llvm::sys::path::append(fullPath, libName);
+ if (pathExists(fullPath))
+ return fullPath.str().copy(_allocator);
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+ }
+
+ // Search for dynamic library
+ fullPath.assign(path);
+ llvm::sys::path::append(fullPath, Twine("lib") + libName + ".dylib");
+ if (pathExists(fullPath))
+ return fullPath.str().copy(_allocator);
+
+ // If not, try for a static library
+ fullPath.assign(path);
+ llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a");
+ if (pathExists(fullPath))
+ return fullPath.str().copy(_allocator);
+
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+
+
+ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const {
+ SmallString<256> path;
+ for (StringRef dir : searchDirs()) {
+ ErrorOr<StringRef> ec = searchDirForLibrary(dir, libName);
+ if (ec)
+ return ec;
+ }
+
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
// TODO: if -arch not specified, look at arch of first .o file.
Added: lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib?rev=212706&view=auto
==============================================================================
Binary files lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib (added) and lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib Thu Jul 10 06:21:06 2014 differ
Propchange: lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib
------------------------------------------------------------------------------
svn:executable = *
Added: lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a?rev=212706&view=auto
==============================================================================
Binary files lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a (added) and lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a Thu Jul 10 06:21:06 2014 differ
Added: lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o?rev=212706&view=auto
==============================================================================
Binary files lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o (added) and lld/trunk/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o Thu Jul 10 06:21:06 2014 differ
Added: lld/trunk/test/mach-o/lib-search-paths.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/lib-search-paths.yaml?rev=212706&view=auto
==============================================================================
--- lld/trunk/test/mach-o/lib-search-paths.yaml (added)
+++ lld/trunk/test/mach-o/lib-search-paths.yaml Thu Jul 10 06:21:06 2014
@@ -0,0 +1,16 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -print_atoms 2>&1 -r | FileCheck %s
+
+--- !native
+undefined-atoms:
+ - name: _from_myshared
+ - name: _from_mystatic
+ - name: _from_fileo
+
+# CHECK: defined-atoms:
+# CHECK: - name: _from_mystatic
+# CHECK: content: [ 02, 00, 00, 00 ]
+# CHECK: - name: _from_fileo
+# CHECK: content: [ 2A, 00, 00, 00 ]
+# CHECK: shared-library-atoms:
+# CHECK: - name: _from_myshared
+# CHECK: load-name: libmyshared.dylib
Added: lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml?rev=212706&view=auto
==============================================================================
--- lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml (added)
+++ lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml Thu Jul 10 06:21:06 2014
@@ -0,0 +1,17 @@
+# RUN: not lld -flavor darwin -test_libresolution \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /Applications/MySDK/usr/local/lib \
+# RUN: -path_exists /Applications/MySDK/usr/lib \
+# RUN: -path_exists /Applications/MySDK/usr/lib/libSystem.dylib \
+# RUN: -syslibroot /Applications/MySDK \
+# RUN: -syslibroot / \
+# RUN: -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+# When the last -syslibroot is simply "/", all of them get discarded. So in this
+# case, only /usr/lib should show up.
+
+# CHECK: Library search paths:
+# CHECK: /usr/lib
+# CHECK-NOT: /usr/local/lib
+# CHECK: Unable to find library -lSystem
Added: lld/trunk/test/mach-o/libresolve-multiple-syslibroots.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/libresolve-multiple-syslibroots.yaml?rev=212706&view=auto
==============================================================================
--- lld/trunk/test/mach-o/libresolve-multiple-syslibroots.yaml (added)
+++ lld/trunk/test/mach-o/libresolve-multiple-syslibroots.yaml Thu Jul 10 06:21:06 2014
@@ -0,0 +1,17 @@
+# RUN: lld -flavor darwin -test_libresolution \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /Applications/MyFirstSDK/usr/local/lib \
+# RUN: -path_exists /Applications/MySecondSDK/usr/local/lib \
+# RUN: -path_exists /Applications/MyFirstSDK/usr/local/lib/libSystem.a \
+# RUN: -path_exists /Applications/MySecondSDK/usr/local/lib/libSystem.a \
+# RUN: -syslibroot /Applications/MyFirstSDK \
+# RUN: -syslibroot /Applications/MySecondSDK \
+# RUN: -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+
+# CHECK: Library search paths:
+# CHECK: /usr/lib
+# CHECK: /Applications/MyFirstSDK/usr/local/lib
+# CHECK: /Applications/MySecondSDK/usr/local/lib
+# CHECK: Found library /Applications/MyFirstSDK/usr/local/lib/libSystem.a
Added: lld/trunk/test/mach-o/libresolve-one-syslibroot.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/libresolve-one-syslibroot.yaml?rev=212706&view=auto
==============================================================================
--- lld/trunk/test/mach-o/libresolve-one-syslibroot.yaml (added)
+++ lld/trunk/test/mach-o/libresolve-one-syslibroot.yaml Thu Jul 10 06:21:06 2014
@@ -0,0 +1,19 @@
+# RUN: lld -flavor darwin -test_libresolution \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /Applications/MySDK/usr/local/lib \
+# RUN: -path_exists /Applications/MySDK/usr/local/lib/libSystem.a \
+# RUN: -syslibroot /Applications/MySDK \
+# RUN: -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+# When just one -syslibroot is specified, we apparently want to skip *system*
+# paths that aren't found. User ones should still get added. In this case
+# /usr/lib exists, but not the equivalent in the -syslibroot, so there should be
+# no mention of /usr/lib.
+
+# CHECK: Library search paths:
+# CHECK-NOT: /usr/lib
+# CHECK-NOT: /usr/local/lib
+# CHECK: /Applications/MySDK/usr/local/lib
+# CHECK-NOT: /usr/local/lib
+# CHECK: Found library /Applications/MySDK/usr/local/lib/libSystem.a
Added: lld/trunk/test/mach-o/libresolve-simple.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/libresolve-simple.yaml?rev=212706&view=auto
==============================================================================
--- lld/trunk/test/mach-o/libresolve-simple.yaml (added)
+++ lld/trunk/test/mach-o/libresolve-simple.yaml Thu Jul 10 06:21:06 2014
@@ -0,0 +1,11 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_libresolution \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /usr/local/lib \
+# RUN: -path_exists /usr/lib/libSystem.dylib \
+# RUN: -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK: /usr/lib
+# CHECK: /usr/local/lib
+# CHECK: Found library /usr/lib/libSystem.dylib
More information about the llvm-commits
mailing list