diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -126,28 +126,48 @@ static void getSearchPaths(std::vector &paths, unsigned optionCode, opt::InputArgList &args, + const std::vector &roots, const SmallVector &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 (auto root : roots) { + SmallString<261> buffer(root); + llvm::sys::path::append(buffer, path); + if (isDirectory(optionLetter, buffer.str())) + paths.push_back(saver.save(buffer.str())); + } + } else { if (isDirectory(optionLetter, path)) paths.push_back(path); } } + + // `-Z` supresses 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 &paths, - opt::InputArgList &args) { - getSearchPaths(paths, OPT_L, args, {"/usr/lib", "/usr/local/lib"}); +static void getLibrarySearchPaths(opt::InputArgList &args, + const std::vector &roots, + std::vector &paths) { + getSearchPaths(paths, OPT_L, args, roots, {"/usr/lib", "/usr/local/lib"}); } -static void getFrameworkSearchPaths(std::vector &paths, - opt::InputArgList &args) { - getSearchPaths(paths, OPT_F, args, +static void getFrameworkSearchPaths(opt::InputArgList &args, + const std::vector &roots, + std::vector &paths) { + getSearchPaths(paths, OPT_F, args, roots, {"/Library/Frameworks", "/System/Library/Frameworks"}); } @@ -399,8 +419,20 @@ config->outputFile = args.getLastArgValue(OPT_o, "a.out"); config->installName = args.getLastArgValue(OPT_install_name, config->outputFile); - getLibrarySearchPaths(config->librarySearchPaths, args); - getFrameworkSearchPaths(config->frameworkSearchPaths, args); + + std::vector roots; + for (const auto 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); config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE; if (args.hasArg(OPT_v)) { @@ -442,6 +474,7 @@ case OPT_L: case OPT_Z: case OPT_arch: + case OPT_syslibroot: // handled elsewhere break; default: diff --git a/lld/test/MachO/syslibroot.test b/lld/test/MachO/syslibroot.test new file mode 100644 --- /dev/null +++ b/lld/test/MachO/syslibroot.test @@ -0,0 +1,53 @@ +# Ensure that a non-existant path is ignored with a syslibroot + +RUN: lld -flavor darwinnew -v -syslibroot /var/empty | FileCheck %s -check-prefix CHECK-NONEXISTANT-SYSLIBROOT + +CHECK-NONEXISTANT-SYSLIBROOT: Library search paths: +CHECK-NONEXISTANT-SYSLIBROOT-NEXT: Framework search paths: + +RUN: mkdir -p %t/usr/lib +RUN: lld -flavor darwinnew -v -syslibroot %t | FileCheck %s -check-prefix CHECK-SYSLIBROOT + +CHECK-SYSLIBROOT: Library search paths: +CHECK-SYSLIBROOT-NEXT: {{.+}}/usr/lib + +RUN: mkdir -p %t/Users/compnerd/Library/libxml2-development +RUN: lld -flavor darwinnew -v -syslibroot %t -L /Users/compnerd/Library/libxml2-development | FileCheck %s -check-prefix CHECK-ABSOLUTE-PATH-REROOTED + +CHECK-ABSOLUTE-PATH-REROOTED: Library search paths: +CHECK-ABSOLUTE-PATH-REROOTED: {{.+}}/Users/compnerd/Library/libxml2-development +CHECK-ABSOLUTE-PATH-REROOTED: {{.+}}/usr/lib + +# NOTE: the match here is fuzzy because the default search paths exist on Linux +# and macOS, but not on Windows. +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 + +CHECK-SYSLIBROOT-MATRIX: Library search paths: +CHECK-SYSLIBROOT-MATRIX: {{.+}}/usr/lib +CHECK-SYSLIBROOT-MATRIX: {{.+}}/usr/lib + +RUN: mkdir -p %t/System/Library/Frameworks +RUN: lld -flavor darwinnew -v -syslibroot %t | FileCheck %s -check-prefix CHECK-SYSLIBROOT-FRAMEWORK + +CHECK-SYSLIBROOT-FRAMEWORK: Framework search paths: +CHECK-SYSLIBROOT-FRAMEWORK: {{.+}}/System/Library/Frameworks + +# NOTE: the match here is fuzzy because the default search paths exist on Linux +# and macOS, but not on Windows. +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/Users/compnerd/Library/Frameworks +RUN: mkdir -p %t.2/Users/compnerd/Library/Frameworks +RUN: lld -flavor darwinnew -v -syslibroot %t -syslibroot %t.2 -F /Users/compnerd/Library/Frameworks | FileCheck %s -check-prefix CHECK-SYSLIBROOT-FRAMEWORK-MATRIX + +CHECK-SYSLIBROOT-FRAMEWORK-MATRIX: Framework search paths: +CHECK-SYSLIBROOT-FRAMEWORK-MATRIX: {{.*}}/Users/compnerd/Library/Frameworks +CHECK-SYSLIBROOT-FRAMEWORK-MATRIX: {{.*}}/Users/compnerd/Library/Frameworks