[lld] r215680 - [mach-o] Support -F and -framework options in darwin driver

Nick Kledzik kledzik at apple.com
Thu Aug 14 15:20:41 PDT 2014


Author: kledzik
Date: Thu Aug 14 17:20:41 2014
New Revision: 215680

URL: http://llvm.org/viewvc/llvm-project?rev=215680&view=rev
Log:
[mach-o] Support -F and -framework options in darwin driver

Darwin has a packaging mechanism for shared libraries and headers called
frameworks.  A directory Foo.framework contains a shared library binary file
"Foo" and a subdirectory "Headers". Most OS frameworks are all in one
directory /System/Library/Frameworks/.  As a linking convenience, the linker
option "-framework Foo" means search the framework directories specified
with -F (analogous to -L) looking for a shared library Foo.framework/Foo.

Added:
    lld/trunk/test/mach-o/framework-user-paths.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=215680&r1=215679&r2=215680&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Thu Aug 14 17:20:41 2014
@@ -85,7 +85,8 @@ public:
   bool printAtoms() const { return _printAtoms; }
   bool testingLibResolution() const { return _testingLibResolution; }
   const StringRefVector &searchDirs() const { return _searchDirs; }
-  void addSysLibRoot(StringRef sysPath) { _syslibRoots.push_back(sysPath); }
+  const StringRefVector &frameworkDirs() const { return _frameworkDirs; }
+  void setSysLibRoots(const StringRefVector &paths);
   const StringRefVector &sysLibRoots() const { return _syslibRoots; }
 
   /// \brief Checks whether a given path on the filesystem exists.
@@ -112,10 +113,18 @@ public:
   ErrorOr<StringRef> searchDirForLibrary(StringRef path,
                                          StringRef libName) const;
 
-  /// \brief Iterates through all search path entries lookinf for libName (as
+  /// \brief Iterates through all search path entries looking for libName (as
   /// specified by -lFoo).
   ErrorOr<StringRef> searchLibrary(StringRef libName) const;
 
+  /// Add a framework search path.  Internally, this method may be prepended
+  /// the path with syslibroot.
+  void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false);
+
+  /// \brief Iterates through all framework directories looking for
+  /// Foo.framework/Foo (when fwName = "Foo").
+  ErrorOr<StringRef> findPathForFramework(StringRef fwName) const;
+
   /// \brief The dylib's binary compatibility version, in the raw uint32 format.
   ///
   /// When building a dynamic library, this is the compatibility version that
@@ -231,6 +240,7 @@ private:
   std::set<StringRef> _existingPaths; // For testing only.
   StringRefVector _searchDirs;
   StringRefVector _syslibRoots;
+  StringRefVector _frameworkDirs;
   HeaderFileType _outputMachOType;   // e.g MH_EXECUTE
   bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog
   bool _doNothing;            // for -help and -v which just print info

Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=215680&r1=215679&r2=215680&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Thu Aug 14 17:20:41 2014
@@ -321,8 +321,14 @@ bool DarwinLdDriver::parse(int argc, con
   //      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)) {
-    ctx.addSysLibRoot(syslibRoot->getValue());
+    sysLibRoots.push_back(syslibRoot->getValue());
+  }
+  if (!sysLibRoots.empty()) {
+    // Ignore all if last -syslibroot is "/".
+    if (sysLibRoots.back() != "/")
+      ctx.setSysLibRoots(sysLibRoots);
   }
 
   // Paths specified with -L come first, and are not considered system paths for
@@ -331,10 +337,17 @@ bool DarwinLdDriver::parse(int argc, con
     ctx.addModifiedSearchDir(libPath->getValue());
   }
 
+  // Process -F directories (where to look for frameworks).
+  for (auto fwPath : parsedArgs->filtered(OPT_F)) {
+    ctx.addFrameworkSearchDir(fwPath->getValue());
+  }
+
   // -Z suppresses the standard search paths.
   if (!parsedArgs->hasArg(OPT_Z)) {
     ctx.addModifiedSearchDir("/usr/lib", true);
     ctx.addModifiedSearchDir("/usr/local/lib", true);
+    ctx.addFrameworkSearchDir("/Library/Frameworks", true);
+    ctx.addFrameworkSearchDir("/System/Library/Frameworks", true);
   }
 
   // Now that we've constructed the final set of search paths, print out what
@@ -344,6 +357,10 @@ bool DarwinLdDriver::parse(int argc, con
     for (auto path : ctx.searchDirs()) {
       diagnostics << "    " << path << '\n';
     }
+    diagnostics << "Framework search paths:\n";
+    for (auto path : ctx.frameworkDirs()) {
+      diagnostics << "    " << path << '\n';
+    }
   }
 
   // Handle input files
@@ -370,6 +387,21 @@ bool DarwinLdDriver::parse(int argc, con
       inputPath = resolvedPath.get();
       break;
     }
+    case OPT_framework: {
+      ErrorOr<StringRef> fullPath = ctx.findPathForFramework(arg->getValue());
+      if (!fullPath) {
+        diagnostics << "Unable to find -framework " << arg->getValue() << "\n";
+        return false;
+      } else if (ctx.testingLibResolution()) {
+       // Test may be running on Windows. Canonicalize the path
+       // separator to '/' to get consistent outputs for tests.
+       std::string path = fullPath.get();
+       std::replace(path.begin(), path.end(), '\\', '/');
+       diagnostics << "Found framework " << path << '\n';
+      }
+      inputPath = fullPath.get();
+      break;
+    }
     }
     inputGraph->addInputElement(std::unique_ptr<InputElement>(
         new MachOFileNode(inputPath, globalWholeArchive)));

Modified: lld/trunk/lib/Driver/DarwinLdOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdOptions.td?rev=215680&r1=215679&r2=215680&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdOptions.td (original)
+++ lld/trunk/lib/Driver/DarwinLdOptions.td Thu Aug 14 17:20:41 2014
@@ -66,6 +66,8 @@ def bundle_loader : Separate<["-"], "bun
 def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARY OPTIONS">;
 def L : JoinedOrSeparate<["-"], "L">,
         HelpText<"Add directory to library search path">, Group<grp_libs>;
+def F : JoinedOrSeparate<["-"], "F">,
+        HelpText<"Add directory to framework search path">, Group<grp_libs>;
 def Z : Flag<["-"], "Z">,
      HelpText<"Do not search standard directories for libraries or frameworks">;
 def all_load : Flag<["-"], "all_load">,
@@ -78,6 +80,8 @@ def syslibroot : Separate<["-"], "syslib
 // Input options
 def l : Joined<["-"], "l">,
         HelpText<"Base name of library searched for in -L directories">;
+def framework : Separate<["-"], "framework">,
+    HelpText<"Base name of framework searched for in -F directories">;
 
 // test case options
 def print_atoms : Flag<["-"], "print_atoms">,

Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=215680&r1=215679&r2=215680&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Thu Aug 14 17:20:41 2014
@@ -307,15 +307,16 @@ bool MachOLinkingContext::pathExists(Str
   return _existingPaths.find(key) != _existingPaths.end();
 }
 
+void MachOLinkingContext::setSysLibRoots(const StringRefVector &paths) {
+  _syslibRoots = paths;
+}
+
 void MachOLinkingContext::addModifiedSearchDir(StringRef libPath,
                                                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() != "/" &&
-      libPath.startswith("/")) {
+  // -syslibroot only applies to absolute paths.
+  if (libPath.startswith("/")) {
     for (auto syslibRoot : _syslibRoots) {
       SmallString<256> path(syslibRoot);
       llvm::sys::path::append(path, libPath);
@@ -338,6 +339,35 @@ void MachOLinkingContext::addModifiedSea
   }
 }
 
+void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,
+                                                bool isSystemPath) {
+  bool pathAdded = false;
+
+  // -syslibroot only used with to absolute framework search paths.
+  if (fwPath.startswith("/")) {
+    for (auto syslibRoot : _syslibRoots) {
+      SmallString<256> path(syslibRoot);
+      llvm::sys::path::append(path, fwPath);
+      if (pathExists(path)) {
+        _frameworkDirs.push_back(path.str().copy(_allocator));
+        pathAdded = true;
+      }
+    }
+  }
+  // If fwPath found in any -syslibroot, then done.
+  if (pathAdded)
+    return;
+
+  // If only one -syslibroot, system paths not in that SDK are suppressed.
+  if (isSystemPath && (_syslibRoots.size() == 1))
+    return;
+
+  // Only use raw fwPath if that directory exists.
+  if (pathExists(fwPath))
+    _frameworkDirs.push_back(fwPath);
+}
+
+
 ErrorOr<StringRef>
 MachOLinkingContext::searchDirForLibrary(StringRef path,
                                          StringRef libName) const {
@@ -377,6 +407,19 @@ ErrorOr<StringRef> MachOLinkingContext::
   }
 
   return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+
+ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) const{
+  SmallString<256> fullPath;
+  for (StringRef dir : frameworkDirs()) {
+    fullPath.assign(dir);
+    llvm::sys::path::append(fullPath, Twine(fwName) + ".framework", fwName);
+    if (pathExists(fullPath))
+      return fullPath.str().copy(_allocator);
+  }
+
+  return make_error_code(llvm::errc::no_such_file_or_directory);
 }
 
 bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {

Added: lld/trunk/test/mach-o/framework-user-paths.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/framework-user-paths.yaml?rev=215680&view=auto
==============================================================================
--- lld/trunk/test/mach-o/framework-user-paths.yaml (added)
+++ lld/trunk/test/mach-o/framework-user-paths.yaml Thu Aug 14 17:20:41 2014
@@ -0,0 +1,41 @@
+#
+# Test framework and SDK search paths. 
+#   myFrameworks is not an absolute path, so it should not by found in SDK
+#   /Custom/Frameworks should be found in SDK
+#   /opt/Frameworks should not be found in SDK
+#   /System/Library/Frameworks is implicit and should be in SDK
+#
+# RUN: lld -flavor darwin -arch x86_64 -r -test_libresolution \
+# RUN:        -path_exists myFrameworks \
+# RUN:        -path_exists myFrameworks/my.framework/my \
+# RUN:        -path_exists /opt/Frameworks \
+# RUN:        -path_exists /opt/Frameworks/other.framework/other \
+# RUN:        -path_exists /Custom/Frameworks \
+# RUN:        -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /System/Library/Frameworks \
+# RUN:        -path_exists /System/Library/Frameworks/Foo.framework/Foo \
+# RUN:        -path_exists /SDK/myFrameworks \
+# RUN:        -path_exists /SDK/myFrameworks/my.framework/my \
+# RUN:        -path_exists /SDK/Custom/Frameworks \
+# RUN:        -path_exists /SDK/Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /SDK/System/Library/Frameworks \
+# RUN:        -path_exists /SDK/System/Library/Frameworks/Foo.framework/Foo \
+# RUN:        -syslibroot /SDK \
+# RUN:        -FmyFrameworks \
+# RUN:        -F/Custom/Frameworks \
+# RUN:        -F/opt/Frameworks \
+# RUN:        -framework my \
+# RUN:        -framework Bar \
+# RUN:        -framework Foo \
+# RUN:        -framework other \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK:        Framework search paths:
+# CHECK-NEXT:     myFrameworks
+# CHECK-NEXT:     /SDK/Custom/Frameworks
+# CHECK-NEXT:     /opt/Frameworks
+# CHECK-NEXT:     /SDK/System/Library/Frameworks
+# CHECK: Found framework myFrameworks/my.framework/my
+# CHECK: Found framework /SDK/Custom/Frameworks/Bar.framework/Bar
+# CHECK: Found framework /SDK/System/Library/Frameworks/Foo.framework/Foo
+# CHECK: Found framework /opt/Frameworks/other.framework/other





More information about the llvm-commits mailing list