diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -27,7 +27,7 @@ class LinkerDriver { public: void linkerMain(ArrayRef args); - void addFile(StringRef path, bool withLOption); + bool addFile(StringRef path, bool withLOption, bool skipDirectory = false); void addLibrary(StringRef name); private: @@ -66,10 +66,12 @@ void printHelp(); std::string createResponseFile(const llvm::opt::InputArgList &args); -llvm::Optional findFromSearchPaths(StringRef path); -llvm::Optional searchScript(StringRef path); -llvm::Optional searchLibraryBaseName(StringRef path); -llvm::Optional searchLibrary(StringRef path); +using PathExists = llvm::function_ref; + +llvm::Optional findFromSearchPaths(StringRef path, PathExists func); +llvm::Optional searchLibraryBaseName(StringRef name, PathExists func); +llvm::Optional searchLibrary(StringRef name, PathExists func); +llvm::Optional searchScript(StringRef name, PathExists func); } // namespace elf } // namespace lld diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -196,28 +196,28 @@ } // Opens a file and create a file object. Path has to be resolved already. -void LinkerDriver::addFile(StringRef path, bool withLOption) { +bool LinkerDriver::addFile(StringRef path, bool withLOption, bool skipDirectory) { using namespace sys::fs; - Optional buffer = readFile(path); + Optional buffer = readFile(path, skipDirectory); if (!buffer.hasValue()) - return; + return false; MemoryBufferRef mbref = *buffer; if (config->formatBinary) { files.push_back(make(mbref)); - return; + return true; } switch (identify_magic(mbref.getBuffer())) { case file_magic::unknown: readLinkerScript(mbref); - return; + break; case file_magic::archive: { if (inWholeArchive) { for (const auto &p : getArchiveMembers(mbref)) files.push_back(createObjectFile(p.first, path, p.second)); - return; + break; } std::unique_ptr file = @@ -239,17 +239,17 @@ error(path + ": archive member '" + p.first.getBufferIdentifier() + "' is neither ET_REL nor LLVM bitcode"); } - return; + break; } // Handle the regular case. files.push_back(make(std::move(file))); - return; + break; } case file_magic::elf_shared_object: if (config->isStatic || config->relocatable) { error("attempted static link of dynamic object " + path); - return; + break; } // Shared objects are identified by soname. soname is (if specified) @@ -259,7 +259,7 @@ path = mbref.getBufferIdentifier(); files.push_back( make(mbref, withLOption ? path::filename(path) : path)); - return; + break; case file_magic::bitcode: case file_magic::elf_relocatable: if (inLib) @@ -269,14 +269,16 @@ break; default: error(path + ": unknown file type"); + break; } + return true; } // Add a given library by searching it from input search paths. void LinkerDriver::addLibrary(StringRef name) { - if (Optional path = searchLibrary(name)) - addFile(*path, /*withLOption=*/true); - else + if (!searchLibrary(name, [&](StringRef path) { + return addFile(path, /*withLOption=*/true, /*skipDirectory=*/true); + })) error("unable to find library -l" + name, ErrorTag::LibNotFound, {name}); } @@ -1390,13 +1392,17 @@ if (Optional buffer = readFile(arg->getValue())) readDynamicList(*buffer); - for (auto *arg : args.filtered(OPT_version_script)) - if (Optional path = searchScript(arg->getValue())) { - if (Optional buffer = readFile(*path)) - readVersionScript(*buffer); - } else { + for (auto *arg : args.filtered(OPT_version_script)) { + if (!searchScript(arg->getValue(), [](StringRef path) { + if (Optional buffer = + readFile(path, /*skipDirectory=*/true)) { + readVersionScript(*buffer); + return true; + } + return false; + })) error(Twine("cannot find version script ") + arg->getValue()); - } + } } // Some Config members do not directly correspond to any particular @@ -1494,14 +1500,18 @@ readDefsym(from, MemoryBufferRef(to, "--defsym")); break; } - case OPT_script: - if (Optional path = searchScript(arg->getValue())) { - if (Optional mb = readFile(*path)) - readLinkerScript(*mb); - break; - } - error(Twine("cannot find linker script ") + arg->getValue()); + case OPT_script: { + if (!searchScript(arg->getValue(), [](StringRef path) { + if (Optional mb = + readFile(path, /*skipDirectory=*/true)) { + readLinkerScript(*mb); + return true; + } + return false; + })) + error(Twine("cannot find linker script ") + arg->getValue()); break; + } case OPT_as_needed: config->asNeeded = true; break; diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp --- a/lld/ELF/DriverUtils.cpp +++ b/lld/ELF/DriverUtils.cpp @@ -209,51 +209,51 @@ // Find a file by concatenating given paths. If a resulting path // starts with "=", the character is replaced with a --sysroot value. -static Optional findFile(StringRef path1, const Twine &path2) { +static Optional findFile(StringRef path1, const Twine &path2, PathExists func) { SmallString<128> s; if (path1.startswith("=")) path::append(s, config->sysroot, path1.substr(1), path2); else path::append(s, path1, path2); - if (fs::exists(s)) + if (func(s)) return std::string(s); return None; } -Optional elf::findFromSearchPaths(StringRef path) { +Optional elf::findFromSearchPaths(StringRef path, PathExists func) { for (StringRef dir : config->searchPaths) - if (Optional s = findFile(dir, path)) + if (Optional s = findFile(dir, path, func)) return s; return None; } // This is for -l. We'll look for lib.so or lib.a from // search paths. -Optional elf::searchLibraryBaseName(StringRef name) { +Optional elf::searchLibraryBaseName(StringRef name, PathExists func) { for (StringRef dir : config->searchPaths) { if (!config->isStatic) - if (Optional s = findFile(dir, "lib" + name + ".so")) + if (Optional s = findFile(dir, "lib" + name + ".so", func)) return s; - if (Optional s = findFile(dir, "lib" + name + ".a")) + if (Optional s = findFile(dir, "lib" + name + ".a", func)) return s; } return None; } // This is for -l. -Optional elf::searchLibrary(StringRef name) { +Optional elf::searchLibrary(StringRef name, PathExists func) { llvm::TimeTraceScope timeScope("Locate library", name); if (name.startswith(":")) - return findFromSearchPaths(name.substr(1)); - return searchLibraryBaseName(name); + return findFromSearchPaths(name.substr(1), func); + return searchLibraryBaseName(name, func); } // If a linker/version script doesn't exist in the current directory, we also // look for the script in the '-L' search paths. This matches the behaviour of // '-T', --version-script=, and linker script INPUT() command in ld.bfd. -Optional elf::searchScript(StringRef name) { - if (fs::exists(name)) +Optional elf::searchScript(StringRef name, PathExists func) { + if (func(name)) return name.str(); - return findFromSearchPaths(name); + return findFromSearchPaths(name, func); } diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -48,7 +48,8 @@ extern std::unique_ptr tar; // Opens a given file. -llvm::Optional readFile(StringRef path); +llvm::Optional readFile(StringRef path, + bool skipDirectory = false); // Add symbols in File to the symbol table. void parseFile(InputFile *file); diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -104,7 +104,7 @@ ++nextGroupId; } -Optional elf::readFile(StringRef path) { +Optional elf::readFile(StringRef path, bool skipDirectory) { llvm::TimeTraceScope timeScope("Load input files", path); // The --chroot option changes our virtual root directory. @@ -112,16 +112,18 @@ if (!config->chroot.empty() && path.startswith("/")) path = saver().save(config->chroot + path); - log(path); - config->dependencyFiles.insert(llvm::CachedHashString(path)); - auto mbOrErr = MemoryBuffer::getFile(path, /*IsText=*/false, /*RequiresNullTerminator=*/false); if (auto ec = mbOrErr.getError()) { - error("cannot open " + path + ": " + ec.message()); + int val = ec.value(); + if (!skipDirectory || (val != ENOENT && val != ENOTDIR && val != EISDIR)) + error("cannot open " + path + ": " + ec.message()); return None; } + log(path); + config->dependencyFiles.insert(llvm::CachedHashString(path)); + MemoryBufferRef mbref = (*mbOrErr)->getMemBufferRef(); memoryBuffers.push_back(std::move(*mbOrErr)); // take MB ownership @@ -490,16 +492,21 @@ static void addDependentLibrary(StringRef specifier, const InputFile *f) { if (!config->dependentLibraries) return; - if (fs::exists(specifier)) - driver->addFile(specifier, /*withLOption=*/false); - else if (Optional s = findFromSearchPaths(specifier)) - driver->addFile(*s, /*withLOption=*/true); - else if (Optional s = searchLibraryBaseName(specifier)) - driver->addFile(*s, /*withLOption=*/true); - else - error(toString(f) + - ": unable to find library from dependent library specifier: " + - specifier); + if (driver->addFile(specifier, /*withLOption=*/false, /*skipDirectory=*/true)) + return; + if (findFromSearchPaths(specifier, [](StringRef path) { + return driver->addFile(path, /*withLOption=*/true, + /*skipDirectory=*/true); + })) + return; + if (searchLibraryBaseName(specifier, [](StringRef path) { + return driver->addFile(path, /*withLOption=*/true, + /*skipDirectory=*/true); + })) + return; + error(toString(f) + + ": unable to find library from dependent library specifier: " + + specifier); } // Record the membership of a section group so that in the garbage collection diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -316,21 +316,19 @@ if (!directory.empty()) { SmallString<0> path(directory); sys::path::append(path, s); - if (sys::fs::exists(path)) { - driver->addFile(path, /*withLOption=*/false); + if (driver->addFile(path, /*withLOption=*/false, /*skipDirectory=*/true)) return; - } } // Then search in the current working directory. - if (sys::fs::exists(s)) { - driver->addFile(s, /*withLOption=*/false); - } else { - // Finally, search in the list of library paths. - if (Optional path = findFromSearchPaths(s)) - driver->addFile(saver().save(*path), /*withLOption=*/true); - else - setError("unable to find " + s); - } + if (driver->addFile(s, /*withLOption=*/false, /*skipDirectory=*/true)) + return; + // Finally, search in the list of library paths. + if (findFromSearchPaths(s, [](StringRef path) { + return driver->addFile(path, /*withLOption=*/true, + /*skipDirectory=*/true); + })) + return; + setError("unable to find " + s); } } @@ -375,12 +373,15 @@ return; } - if (Optional path = searchScript(tok)) { - if (Optional mb = readFile(*path)) - tokenize(*mb); - return; - } - setError("cannot find linker script " + tok); + if (!searchScript(tok, [&](StringRef path) { + if (Optional mb = + readFile(path, /*skipDirectory=*/true)) { + tokenize(*mb); + return true; + } + return false; + })) + setError("cannot find linker script " + tok); } void ScriptParser::readInput() { diff --git a/lld/test/ELF/deplibs-dir.s b/lld/test/ELF/deplibs-dir.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/deplibs-dir.s @@ -0,0 +1,26 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: echo ".global foo; foo:" | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %tfoo.o +# RUN: rm -rf %t.dir +# RUN: mkdir -p %t.dir +# RUN: cd %t.dir +# RUN: touch %t.dir/notdir +# RUN: mkdir -p %t.dir/foo +# RUN: mkdir -p %t.dir/bar/foo +# RUN: mkdir -p %t.dir/baz +# RUN: llvm-ar rc %t.dir/baz/libfoo.a %tfoo.o +# RUN: ld.lld %t.o -o /dev/null -L%t.dir/notdir -L %t.dir/bar -L %t.dir/baz --trace 2>&1 | \ +# RUN: FileCheck %s -DOBJ=%t.o -DDIR=%t.dir + +# CHECK: [[OBJ]] +# CHECK-NOT: [[DIR]]{{[\\/]}}foo: Is a directory +# CHECK-NOT: [[DIR]]{{[\\/]}}bar{{[\\/]}}foo: Is a directory +# CHECK-NEXT: [[DIR]]{{[\\/]}}baz{{[\\/]}}libfoo.a + +.global _start +_start: + call foo +.section ".deplibs","MS",@llvm_dependent_libraries,1 + .asciz "foo"