MachO: support `-syslibroot`

This adds support for the `-syslibroot` option.  This is required to
make the library search order actually function.  With this, it is now
possible to link a test Darwin x86_64 program with lld on Darwin.

Differential Revision: https://reviews.llvm.org/D82252
Reviewed By: Jez Ng
This commit is contained in:
Saleem Abdulrasool 2020-06-19 21:13:03 -07:00
parent bd2c88b253
commit 0ccda7c232
3 changed files with 104 additions and 15 deletions

View File

@ -152,28 +152,49 @@ static bool isDirectory(StringRef option, StringRef path) {
static void getSearchPaths(std::vector<StringRef> &paths, unsigned optionCode,
opt::InputArgList &args,
const std::vector<StringRef> &roots,
const SmallVector<StringRef, 2> &systemPaths) {
StringRef optionLetter{(optionCode == OPT_F ? "F" : "L")};
for (auto const &path : args::getStrings(args, optionCode)) {
if (isDirectory(optionLetter, path))
paths.push_back(path);
}
if (!args.hasArg(OPT_Z) && Triple(sys::getProcessTriple()).isOSDarwin()) {
for (auto const &path : systemPaths) {
// NOTE: only absolute paths are re-rooted to syslibroot(s)
if (llvm::sys::path::is_absolute(path, llvm::sys::path::Style::posix)) {
for (StringRef root : roots) {
SmallString<261> buffer(root);
llvm::sys::path::append(buffer, path);
// Do not warn about paths that are computed via the syslib roots
if (llvm::sys::fs::is_directory(buffer))
paths.push_back(saver.save(buffer.str()));
}
} else {
if (isDirectory(optionLetter, path))
paths.push_back(path);
}
}
// `-Z` suppresses the standard "system" search paths.
if (args.hasArg(OPT_Z))
return;
for (auto const &path : systemPaths) {
for (auto root : roots) {
SmallString<261> buffer(root);
llvm::sys::path::append(buffer, path);
if (isDirectory(optionLetter, buffer))
paths.push_back(saver.save(buffer.str()));
}
}
}
static void getLibrarySearchPaths(std::vector<StringRef> &paths,
opt::InputArgList &args) {
getSearchPaths(paths, OPT_L, args, {"/usr/lib", "/usr/local/lib"});
static void getLibrarySearchPaths(opt::InputArgList &args,
const std::vector<StringRef> &roots,
std::vector<StringRef> &paths) {
getSearchPaths(paths, OPT_L, args, roots, {"/usr/lib", "/usr/local/lib"});
}
static void getFrameworkSearchPaths(std::vector<StringRef> &paths,
opt::InputArgList &args) {
getSearchPaths(paths, OPT_F, args,
static void getFrameworkSearchPaths(opt::InputArgList &args,
const std::vector<StringRef> &roots,
std::vector<StringRef> &paths) {
getSearchPaths(paths, OPT_F, args, roots,
{"/Library/Frameworks", "/System/Library/Frameworks"});
}
@ -397,10 +418,22 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
config->installName =
args.getLastArgValue(OPT_install_name, config->outputFile);
config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32);
getLibrarySearchPaths(config->librarySearchPaths, args);
getFrameworkSearchPaths(config->frameworkSearchPaths, args);
config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
std::vector<StringRef> roots;
for (const Arg *arg : args.filtered(OPT_syslibroot))
roots.push_back(arg->getValue());
// NOTE: the final `-syslibroot` being `/` will ignore all roots
if (roots.size() && roots.back() == "/")
roots.clear();
// NOTE: roots can never be empty - add an empty root to simplify the library
// and framework search path computation.
if (roots.empty())
roots.emplace_back("");
getLibrarySearchPaths(args, roots, config->librarySearchPaths);
getFrameworkSearchPaths(args, roots, config->frameworkSearchPaths);
if (args.hasArg(OPT_v)) {
message(getLLDVersion());
message(StringRef("Library search paths:") +
@ -455,6 +488,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
case OPT_install_name:
case OPT_Z:
case OPT_arch:
case OPT_syslibroot:
// handled elsewhere
break;
default:

View File

@ -2,13 +2,13 @@ UNSUPPORTED: darwin
RUN: mkdir -p %t1 %t2
RUN: lld -flavor darwinnew -v -L%t1 -F%t2 2>&1 | FileCheck -DLDIR=%t1 -DFDIR=%t2 %s
RUN: lld -flavor darwinnew -Z -v -L%t1 -F%t2 2>&1 | FileCheck -DLDIR=%t1 -DFDIR=%t2 %s
CHECK: Library search paths:
CHECK-NEXT: [[LDIR]]
CHECK-NEXT: Framework search paths:
CHECK-NEXT: [[FDIR]]
RUN: lld -flavor darwinnew -v -L%t1 -F%t2 -Z 2>&1 | FileCheck -DLDIR=%t1 -DFDIR=%t2 --check-prefix=CHECK_Z %s
RUN: lld -flavor darwinnew -Z -v -L%t1 -F%t2 -Z 2>&1 | FileCheck -DLDIR=%t1 -DFDIR=%t2 --check-prefix=CHECK_Z %s
CHECK_Z: Library search paths:
CHECK_Z-NEXT: [[LDIR]]
CHECK_Z-NEXT: Framework search paths:

View File

@ -0,0 +1,55 @@
# Ensure that a nonexistent path is ignored with a syslibroot
RUN: lld -flavor darwinnew -v -syslibroot /var/empty | FileCheck %s -check-prefix CHECK-NONEXISTENT-SYSLIBROOT
CHECK-NONEXISTENT-SYSLIBROOT: Library search paths:
CHECK-NONEXISTENT-SYSLIBROOT-NEXT: Framework search paths:
RUN: mkdir -p %t/usr/lib
RUN: lld -flavor darwinnew -v -syslibroot %t | FileCheck %s -check-prefix CHECK-SYSLIBROOT -DROOT=%t
CHECK-SYSLIBROOT: Library search paths:
CHECK-SYSLIBROOT-NEXT: [[ROOT]]/usr/lib
RUN: mkdir -p %t/Library/libxml2-development
RUN: lld -flavor darwinnew -v -syslibroot %t -L /Library/libxml2-development | FileCheck %s -check-prefix CHECK-ABSOLUTE-PATH-REROOTED -DROOT=%t
CHECK-ABSOLUTE-PATH-REROOTED: Library search paths:
CHECK-ABSOLUTE-PATH-REROOTED: [[ROOT]]/Library/libxml2-development
CHECK-ABSOLUTE-PATH-REROOTED: [[ROOT]]/usr/lib
# NOTE: the match here is fuzzy because the default search paths exist on Linux
# and macOS, but not on Windows (that is we ignore `/var/empty`). This allows
# us to run the test uniformly on all the platforms.
RUN: lld -flavor darwinnew -v -syslibroot /var/empty -syslibroot / 2>&1 | FileCheck %s -check-prefix CHECK-SYSLIBROOT-IGNORED
CHECK-SYSLIBROOT-IGNORED: /usr/lib
CHECK-SYSLIBROOT-IGNORED: /usr/local/lib
RUN: mkdir -p %t.2/usr/lib
RUN: lld -flavor darwinnew -v -syslibroot %t -syslibroot %t.2 | FileCheck %s -check-prefix CHECK-SYSLIBROOT-MATRIX -DROOT=%t
CHECK-SYSLIBROOT-MATRIX: Library search paths:
CHECK-SYSLIBROOT-MATRIX: [[ROOT]]/usr/lib
CHECK-SYSLIBROOT-MATRIX: [[ROOT]].2/usr/lib
RUN: mkdir -p %t/System/Library/Frameworks
RUN: lld -flavor darwinnew -v -syslibroot %t | FileCheck %s -check-prefix CHECK-SYSLIBROOT-FRAMEWORK -DROOT=%t
CHECK-SYSLIBROOT-FRAMEWORK: Framework search paths:
CHECK-SYSLIBROOT-FRAMEWORK: [[ROOT]]/System/Library/Frameworks
# NOTE: the match here is fuzzy because the default search paths exist on Linux
# and macOS, but not on Windows (that is we ignore `/var/empty`). This allows
# us to run the test uniformly on all the platforms.
RUN: lld -flavor darwinnew -v -syslibroot /var/empty -syslibroot / 2>&1 | FileCheck %s -check-prefix CHECK-SYSLIBROOT-FRAMEWORK-IGNORED
CHECK-SYSLIBROOT-FRAMEWORK-IGNORED: /System/Library/Framework
RUN: mkdir -p %t/Library/Frameworks
RUN: mkdir -p %t.2/Library/Frameworks
RUN: lld -flavor darwinnew -v -syslibroot %t -syslibroot %t.2 -F /Library/Frameworks | FileCheck %s -check-prefix CHECK-SYSLIBROOT-FRAMEWORK-MATRIX -DROOT=%t
CHECK-SYSLIBROOT-FRAMEWORK-MATRIX: Framework search paths:
CHECK-SYSLIBROOT-FRAMEWORK-MATRIX: [[ROOT]]/Library/Frameworks
CHECK-SYSLIBROOT-FRAMEWORK-MATRIX: [[ROOT]].2/Library/Frameworks