[lld] [mach-o] Support -l and -syslibroot options

Tim Northover t.p.northover at gmail.com
Mon Jul 7 09:01:10 PDT 2014


Hi,

The attached patch implements the -l and -syslibroot options for the
Darwin lld driver. They're in the same patch because testing -l (looks
in /usr/lib and /usr/local/lib) without being able to override the
prefix is rather problematic.

I think the implementation itself is reasonably straightforward (the
one wrinkle is iterating through all arguments now, as opposed to just
OPT_INPUT and OPT_l. Not *strictly* necessary yet, but adding more
filter OPT_nnn arguments to the iterator doesn't scale and we do have
a lot more to support in the end).

The most controversial part is likely to be the testing: it adds
crafted binary MachO inputs, which isn't ideal if they ever need
updating (unlikely, they simply export a single, given symbol). This
isn't exactly unique though, so hopefully won't cause any problems.

OK to commit?

Cheers.

Tim.
-------------- next part --------------
commit ca1bf01d29014eee796172c9a89836fff1714bb0
Author: Tim Northover <tnorthover at apple.com>
Date:   Mon Jul 7 16:30:49 2014 +0100

    [mach-o]: support -syslibroot and -l options

diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h
index 036fe8b..c79a091 100644
--- a/include/lld/ReaderWriter/MachOLinkingContext.h
+++ b/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -79,6 +79,12 @@ public:
   bool doNothing() const { return _doNothing; }
   bool printAtoms() const { return _printAtoms; }
 
+  ErrorOr<StringRef> searchPathForLibrary(StringRef path,
+                                          StringRef libName) const;
+
+  /// Searches directories for a match on the input File
+  ErrorOr<StringRef> searchLibrary(StringRef libName) const;
+
   /// \brief The dylib's binary compatibility version, in the raw uint32 format.
   ///
   /// When building a dynamic library, this is the compatibility version that
@@ -125,6 +131,8 @@ public:
   }
   void setBundleLoader(StringRef loader) { _bundleLoader = loader; }
   void setPrintAtoms(bool value=true) { _printAtoms = value; }
+  void setSyslibRoot(StringRef path) { _syslibRoot = path; }
+
   StringRef dyldPath() const { return "/usr/lib/dyld"; }
 
   static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
@@ -153,6 +161,7 @@ private:
 
   static ArchInfo _s_archInfos[];
 
+  StringRef _syslibRoot;
   HeaderFileType _outputMachOType;   // e.g MH_EXECUTE
   bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog
   bool _doNothing;            // for -help and -v which just print info
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
index 6686caf..aac89b8 100644
--- a/lib/Driver/DarwinLdDriver.cpp
+++ b/lib/Driver/DarwinLdDriver.cpp
@@ -268,12 +268,31 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
 
   std::unique_ptr<InputGraph> inputGraph(new InputGraph());
 
+  if (llvm::opt::Arg *syslibRoot = parsedArgs->getLastArg(OPT_syslibroot)) {
+    ctx.setSyslibRoot(syslibRoot->getValue());
+  }
+
   // Handle input files
-  for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
-                               ie = parsedArgs->filtered_end();
-                              it != ie; ++it) {
+  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;
+      }
+      inputPath = resolvedPath.get();
+      break;
+    }
+    }
     inputGraph->addInputElement(std::unique_ptr<InputElement>(
-        new MachOFileNode(ctx, (*it)->getValue(), globalWholeArchive)));
+        new MachOFileNode(ctx, inputPath, globalWholeArchive)));
   }
 
   if (!inputGraph->size()) {
diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td
index 61c151a..15af151 100644
--- a/lib/Driver/DarwinLdOptions.td
+++ b/lib/Driver/DarwinLdOptions.td
@@ -69,9 +69,16 @@ 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 prefix to all system library search paths">,
+        Group<grp_libs>;
+
+// Input options
+def l : Joined<["-"], "l">,
+        HelpText<"Root name of library to searchf for">;
 
 // test case options
-def print_atoms : Flag<["-"], "print_atoms">, 
+def print_atoms : Flag<["-"], "print_atoms">,
         HelpText<"Emit output as yaml atoms">;
 
 // general options
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index b1e2929..36d267a 100644
--- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -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;
@@ -262,6 +264,49 @@ bool MachOLinkingContext::addUnixThreadLoadCommand() const {
   }
 }
 
+ErrorOr<StringRef>
+MachOLinkingContext::searchPathForLibrary(StringRef path,
+                                          StringRef libName) const {
+  SmallString<128> 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 (llvm::sys::fs::exists(fullPath.str()))
+      return StringRef(*new (_allocator) std::string(fullPath.str()));
+    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 (llvm::sys::fs::exists(fullPath.str()))
+    return StringRef(*new (_allocator) std::string(fullPath.str()));
+
+  // If not, try for a static library
+  fullPath.assign(path);
+  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a");
+  if (llvm::sys::fs::exists(fullPath.str()))
+    return StringRef(*new (_allocator) std::string(fullPath.str()));
+
+  return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const {
+  SmallString<128> path;
+  static const char *syslibPaths[] = {"/usr/lib", "/usr/local/lib"};
+  for (StringRef dir : syslibPaths) {
+    path.assign(_syslibRoot);
+    llvm::sys::path::append(path, dir);
+
+    ErrorOr<StringRef> ec = searchPathForLibrary(path, 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.
 
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib
new file mode 100755
index 0000000000000000000000000000000000000000..839d00d1927993b520130aa099695ee24865c68b
GIT binary patch
literal 8360
zcmeI2y-or_5XT3>j{tsKU~DdGj7kDFMhgoukVrH}BQbU>cxNOLO^zdxj>f__Fm`sn
zft97TK7sKCd;tpMe~w%3f)eeSN&eZL+1=UM9~BI*&CjnvqEMKK2A~n>qmSr@#xNtA
zhVCGx3c2F~M>?#v%@2A$a#BAO@>Y~`tZT>L_9I`HJna(^YP9E=_;qD7g-l>Y=jk$X
zUHn$RF0<$q{qsuwo-d-eATRKAHLhzLQffE9x0B1}H8aCIqU-YfM=#8E>6$n+46Q&3
zC>Xyemn!w at dC|7alv#&|b+%ce2JipVj8;y51Lr=0&+`VxMT{|M9|{`ZuN92{XFh{X
zd{6S>;A!rD_2~9A_42k>o}5R_MG=h>LCf05$QFmzAwJ9X5k2E02vNFLwbOVu>#$yR
ztV(Jt2x0*{Id8%s8p62b`38KpB*g3NZ(<Y^0zyCt2mv7=1cZPP5CTF#2=oep)_1F3
zd9A!t2nYcoAOwVf5D)@FKnMr{As_^VK#vj#sWbbkqI6T4Cc<tnSkq{}$GMHa0dWhM
zZ3;0Sxn0aL{@Vcmj1UX7WZ}APc6VWvSKVeW(Kx0!q;ru$9rvTDZK|qME2&cX(zI;O
G1p5ZJR#I93

literal 0
HcmV?d00001

diff --git a/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a
new file mode 100644
index 0000000000000000000000000000000000000000..b12062941f376d739ba0bee9161c165f25c6a2a0
GIT binary patch
literal 556
zcmY$iNi0gvu;bEKKm~>-1}5evX6B}b3JL~bDP&SX!N>%rK7osYfq at Z-W8%|_@^j;J
zD~n4KOEQxg7+@^De2D2VGfgZN6if|(1}hkW4K*|{Ff##~2ecAuXad*yUvK}h1I=ZI
z8V;fZK(;6VF%U=s at e42uJHY}KE&%BP0vI1?CIbjFfdqjdKE5Qiq6ET*@Izc9LJ)j(
z7R)>(@dhL|(7cqyl0<|^e7uWeh$DgzW5L`5G7sh!m>e<<l9K at 95}-ODVrT&p0zjG@
Zhy#Ea8Gz(Lm>dAI2c(xD*)eDl3IOc4H2MGl

literal 0
HcmV?d00001

diff --git a/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o b/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o
new file mode 100644
index 0000000000000000000000000000000000000000..f9a923d37db381942611b306f0c87ed7266b2723
GIT binary patch
literal 404
zcmX^A>+L^w1_nlE1|R{%AUXiVPyk{ekOblvU>0_Q1u9$s(gOrAKF~}C5M}}i0zrIy
zNoqw2gbm?`xJHB^_~<N{c}U_7NNk{aDTyVC2$A at B7sn7s1RutNxd&t(%q=iEWEvzV
y0mLOhbwI?>0we^0G&c|j05LKE$%8OCKnth|q?aGrG4W|d`ML3FnK`NXATt4O85SG>

literal 0
HcmV?d00001

diff --git a/test/mach-o/lib-search-paths.yaml b/test/mach-o/lib-search-paths.yaml
new file mode 100644
index 0000000..88c4b51
--- /dev/null
+++ b/test/mach-o/lib-search-paths.yaml
@@ -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


More information about the llvm-commits mailing list