diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -27,7 +27,9 @@ llvm::StringRef installName; llvm::StringRef outputFile; llvm::MachO::HeaderFileType outputType; - std::vector searchPaths; + // TODO: use the library and framework search paths + std::vector librarySearchPaths; + std::vector frameworkSearchPaths; llvm::DenseMap priorities; }; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -30,6 +30,7 @@ #include "llvm/Object/Archive.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -83,7 +84,7 @@ // This is for -lfoo. We'll look for libfoo.dylib from search paths. static Optional findDylib(StringRef name) { - for (StringRef dir : config->searchPaths) { + for (StringRef dir : config->librarySearchPaths) { std::string path = (dir + "/lib" + name + ".dylib").str(); if (fs::exists(path)) return path; @@ -99,13 +100,51 @@ return createX86_64TargetInfo(); } -static std::vector getSearchPaths(opt::InputArgList &args) { - std::vector ret{args::getStrings(args, OPT_L)}; - if (!args.hasArg(OPT_Z)) { - ret.push_back("/usr/lib"); - ret.push_back("/usr/local/lib"); +static bool isDirectory(StringRef option, StringRef path) { + if (!fs::exists(path)) { + warn("directory not found for option -" + option + path); + return false; + } else if (!fs::is_directory(path)) { + warn("option -" + option + path + " references a non-directory path"); + return false; + } + return true; +} + +static std::vector getLibrarySearchPaths(opt::InputArgList &args, + bool isOSDarwin) { + std::vector paths; + for (auto const &path : args::getStrings(args, OPT_L)) { + if (isDirectory("L", path)) + paths.push_back(path); + } + if (isOSDarwin && !args.hasArg(OPT_Z)) { + StringRef usrLib("/usr/lib"); + StringRef usrLocalLib("/usr/local/lib"); + if (isDirectory("L", usrLib)) + paths.push_back(usrLib); + if (isDirectory("L", usrLocalLib)) + paths.push_back(usrLocalLib); + } + return paths; +} + +static std::vector getFrameworkSearchPaths(opt::InputArgList &args, + bool isOSDarwin) { + std::vector paths; + for (auto const &path : args::getStrings(args, OPT_F)) { + if (isDirectory("F", path)) + paths.push_back(path); + } + if (isOSDarwin && !args.hasArg(OPT_Z)) { + StringRef libFrames("/Library/Frameworks"); + StringRef sysLibFrames("/System/Library/Frameworks"); + if (isDirectory("F", libFrames)) + paths.push_back(libFrames); + if (isDirectory("F", sysLibFrames)) + paths.push_back(sysLibFrames); } - return ret; + return paths; } static void addFile(StringRef path) { @@ -378,14 +417,19 @@ config->outputFile = args.getLastArgValue(OPT_o, "a.out"); config->installName = args.getLastArgValue(OPT_install_name, config->outputFile); - config->searchPaths = getSearchPaths(args); + bool isOSDarwin = Triple(sys::getProcessTriple()).isOSDarwin(); + config->librarySearchPaths = getLibrarySearchPaths(args, isOSDarwin); + config->frameworkSearchPaths = getFrameworkSearchPaths(args, isOSDarwin); config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE; if (args.hasArg(OPT_v)) { message(getLLDVersion()); - std::vector &searchPaths = config->searchPaths; - message("Library search paths:\n" + - llvm::join(searchPaths.begin(), searchPaths.end(), "\n")); + message("Library search paths:" + + std::string(config->librarySearchPaths.size() ? "\n\t" : "") + + llvm::join(config->librarySearchPaths, "\n\t")); + message("Framework search paths:" + + std::string(config->frameworkSearchPaths.size() ? "\n\t" : "") + + llvm::join(config->frameworkSearchPaths, "\n\t")); freeArena(); return !errorCount(); } @@ -396,6 +440,8 @@ switch (opt.getID()) { case OPT_o: case OPT_dylib: + case OPT_L: + case OPT_F: // handled elsewhere ... break; default: diff --git a/lld/test/MachO/search-paths.test b/lld/test/MachO/search-paths.test --- a/lld/test/MachO/search-paths.test +++ b/lld/test/MachO/search-paths.test @@ -1,12 +1,33 @@ -RUN: mkdir -p %t - -RUN: lld -flavor darwinnew -v -L%t 2>&1 | FileCheck -DDIR=%t %s -CHECK: Library search paths: -CHECK-NEXT: [[DIR]] -CHECK-NEXT: /usr/lib -CHECK-NEXT: /usr/local/lib - -RUN: lld -flavor darwinnew -v -L%t -Z 2>&1 | FileCheck -DDIR=%t --check-prefix=CHECK_Z %s -CHECK_Z: Library search paths: -CHECK_Z-NEXT: [[DIR]] -CHECK_Z-NOT: /usr/ +RUN: rm -fr %t1 %t2 %t3 +RUN: mkdir -p %t1 +RUN: touch %t2 + +RUN: not lld -flavor darwinnew -L%t1 -L%t2 -L%t3 2>&1 \ +RUN: | FileCheck --check-prefix=CHECK_LF -DT1=%t1 -DT2=%t2 -DT3=%t3 %s +RUN: not lld -flavor darwinnew -L %t1 -L %t2 -L %t3 2>&1 \ +RUN: | FileCheck --check-prefix=CHECK_LF -DT1=%t1 -DT2=%t2 -DT3=%t3 %s +RUN: not lld -flavor darwinnew -F%t1 -F%t2 -F%t3 2>&1 \ +RUN: | FileCheck --check-prefix=CHECK_LF -DT1=%t1 -DT2=%t2 -DT3=%t3 %s +RUN: not lld -flavor darwinnew -F %t1 -F %t2 -F %t3 2>&1 \ +RUN: | FileCheck --check-prefix=CHECK_LF -DT1=%t1 -DT2=%t2 -DT3=%t3 %s + +CHECK_LF: warning: option -{{[LF]}}[[T2]] references a non-directory path +CHECK_LF-NEXT: warning: directory not found for option -{{[LF]}}[[T3]] +CHECK_LF-NEXT: undefined symbol: _main + +RUN: lld -flavor darwinnew -v -L %t1 2>&1 \ +RUN: | FileCheck --check-prefix=CHECK_vL -DT1=%t1 %s + +CHECK_vL: LLD {{[0-9.]+ .*}} +CHECK_vL-NEXT: Library search paths: +CHECK_vL-NEXT: [[T1]] +CHECK_vL-NEXT: Framework search paths: + +RUN: lld -flavor darwinnew -v -F %t1 2>&1 \ +RUN: | FileCheck --check-prefix=CHECK_vF -DT1=%t1 %s + +CHECK_vF: LLD {{[0-9.]+ .*}} +CHECK_vF-NEXT: Library search paths: +CHECK_vF-NEXT: Framework search paths: +CHECK_vF-NEXT: [[T1]] +