Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -19,6 +19,7 @@ llvm::StringRef OutputFile; llvm::StringRef DynamicLinker; std::string RPath; + std::vector InputSearchPaths; bool Shared = false; bool DiscardAll = false; bool DiscardLocals = false; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" using namespace llvm; @@ -59,6 +60,28 @@ return createELFFile(MB); } +// Searches a given library from input search paths, which are filled +// from -L command line switches. Returns a path to an existent library file. +static std::string searchLibrary(StringRef Path) { + SmallVector, 2> Names; + if (Path[0] == ':') { + Names.emplace_back(Path.drop_front()); + } else { + Names.emplace_back((Twine("lib", Path) + ".so").str()); + Names.emplace_back((Twine("lib", Path) + ".a").str()); + } + SmallString<128> FullPath; + for (StringRef Dir : Config->InputSearchPaths) { + for (const auto &Name : Names) { + FullPath = Dir; + sys::path::append(FullPath, Name); + if (sys::fs::exists(FullPath.str())) + return FullPath.str().str(); + } + } + error(Twine("Unable to find library -l", Path)); +} + void LinkerDriver::link(ArrayRef ArgsArr) { // Parse command line options. opt::InputArgList Args = Parser.parse(ArgsArr); @@ -79,6 +102,9 @@ if (!RPaths.empty()) Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":"); + for (auto *Arg : Args.filtered(OPT_L)) + Config->InputSearchPaths.push_back(Arg->getValue()); + if (Args.hasArg(OPT_shared)) Config->Shared = true; @@ -97,8 +123,13 @@ // Create a list of input files. std::vector Inputs; - for (auto *Arg : Args.filtered(OPT_INPUT)) { + for (auto *Arg : Args.filtered(OPT_l, OPT_INPUT)) { StringRef Path = Arg->getValue(); + if (Arg->getOption().getID() == OPT_l) { + auto LibraryPath = searchLibrary(Path); + Inputs.push_back(openFile(LibraryPath)); + continue; + } Inputs.push_back(openFile(Path)); } Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -33,3 +33,15 @@ def export_dynamic : Flag<["--"], "export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; + +def L : Joined<["-"], "L">, MetaVarName<"">, + HelpText<"Directory to search for libraries">; + +def alias_L : Joined<["--"], "library-path=">, + Alias; + +def l : Joined<["-"], "l">, MetaVarName<"">, + HelpText<"Root name of library to use">; + +def alias_l : Joined<["--"], "library=">, + Alias; Index: test/elf2/Inputs/libsearch-dyn.s =================================================================== --- /dev/null +++ test/elf2/Inputs/libsearch-dyn.s @@ -0,0 +1,3 @@ +.globl _bar,_dynamic; +_bar: +_dynamic: Index: test/elf2/Inputs/libsearch-st.s =================================================================== --- /dev/null +++ test/elf2/Inputs/libsearch-st.s @@ -0,0 +1,3 @@ +.globl _bar,_static; +_bar: +_static: Index: test/elf2/libsearch.s =================================================================== --- /dev/null +++ test/elf2/libsearch.s @@ -0,0 +1,46 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +// RUN: %p/Inputs/libsearch-dyn.s -o %tdyn.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +// RUN: %p/Inputs/libsearch-st.s -o %tst.o +// RUN: lld -flavor gnu2 -shared %tdyn.o -o %T/libls.so +// RUN: rm -f %T/libls.a +// RUN: llvm-ar rcs %T/libls.a %tst.o +// REQUIRES: x86 + +// Should not link because of undefined symbol _bar +// RUN: not lld -flavor gnu2 -o %t3 %t.o 2>&1 \ +// RUN: | FileCheck --check-prefix=UNDEFINED %s +// UNDEFINED: undefined symbol: _bar + +// Should fail if cannot find specified library (without -L switch) +// RUN: not lld -flavor gnu2 -o %t3 %t.o -lls 2>&1 \ +// RUN: | FileCheck --check-prefix=NOLIB %s +// NOLIB: Unable to find library -lls + +// Should use explicitly specified static library +// RUN: lld -flavor gnu2 -o %t3 %t.o -L%T -l:libls.a +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s +// STATIC: Symbols [ +// STATIC: Name: _static +// STATIC: ] + +// Should use explicitly specified dynamic library +// RUN: lld -flavor gnu2 -o %t3 %t.o -L%T -l:libls.so +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s +// DYNAMIC: Symbols [ +// DYNAMIC-NOT: Name: _static +// DYNAMIC: ] + +// Should prefer dynamic to static +// RUN: lld -flavor gnu2 -o %t3 %t.o -L%T -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s + +// -L can be placed after -l +// RUN: lld -flavor gnu2 -o %t3 %t.o -lls -L%T + +// Check long forms as well +// RUN: lld -flavor gnu2 -o %t3 %t.o --library-path=%T --library=ls + +.globl _start,_bar; +_start: