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"});
}
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:") +
case OPT_install_name:
case OPT_Z:
case OPT_arch:
+ case OPT_syslibroot:
// handled elsewhere
break;
default:
--- /dev/null
+# 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