[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. llvm-svn: 215680
This commit is contained in:
parent
e8d2a9d755
commit
2d835dad0a
|
@ -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
|
||||
|
|
|
@ -321,8 +321,14 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
|
|||
// 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, const char *argv[],
|
|||
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, const char *argv[],
|
|||
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, const char *argv[],
|
|||
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)));
|
||||
|
|
|
@ -66,6 +66,8 @@ def bundle_loader : Separate<["-"], "bundle_loader">,
|
|||
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<["-"], "syslibroot">,
|
|||
// 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">,
|
||||
|
|
|
@ -307,15 +307,16 @@ bool MachOLinkingContext::pathExists(StringRef path) const {
|
|||
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::addModifiedSearchDir(StringRef libPath,
|
|||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -379,6 +409,19 @@ ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const {
|
|||
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) {
|
||||
// TODO: if -arch not specified, look at arch of first .o file.
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue