COFF: Add /nodefaultlib option.

llvm-svn: 238679
This commit is contained in:
Rui Ueyama 2015-05-31 19:17:14 +00:00
parent 54b71daec4
commit d21b00bd7c
4 changed files with 93 additions and 29 deletions

View File

@ -20,6 +20,7 @@ namespace lld {
namespace coff {
using llvm::COFF::WindowsSubsystem;
using llvm::StringRef;
class Configuration {
public:
@ -28,6 +29,9 @@ public:
WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
std::string EntryName;
std::set<StringRef> NoDefaultLibs;
bool NoDefaultLibAll = false;
uint64_t ImageBase = 0x140000000;
uint64_t StackReserve = 1024 * 1024;
uint64_t StackCommit = 4096;

View File

@ -95,18 +95,15 @@ LinkerDriver::parseDirectives(StringRef S,
return EC;
std::unique_ptr<llvm::opt::InputArgList> Args = std::move(ArgsOrErr.get());
for (auto *Arg : Args->filtered(OPT_defaultlib)) {
StringRef Path = findLib(Arg->getValue());
if (!insertFile(Path))
continue;
Res->push_back(llvm::make_unique<ArchiveFile>(Path));
}
for (auto *Arg : Args->filtered(OPT_defaultlib))
if (Optional<StringRef> Path = findLib(Arg->getValue()))
Res->push_back(llvm::make_unique<ArchiveFile>(*Path));
return std::error_code();
}
// Find file from search paths. You can omit ".obj", this function takes
// care of that. Note that the returned path is not guaranteed to exist.
StringRef LinkerDriver::findFile(StringRef Filename) {
StringRef LinkerDriver::doFindFile(StringRef Filename) {
bool hasPathSep = (Filename.find_first_of("/\\") != StringRef::npos);
if (hasPathSep)
return Filename;
@ -125,17 +122,38 @@ StringRef LinkerDriver::findFile(StringRef Filename) {
return Filename;
}
StringRef LinkerDriver::findLib(StringRef Filename) {
StringRef S = addExtOpt(Filename, ".lib");
return findFile(S);
// Resolves a file path. This never returns the same path
// (in that case, it returns None).
Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
StringRef Path = doFindFile(Filename);
bool Seen = !VisitedFiles.insert(Path.lower()).second;
if (Seen)
return None;
return Path;
}
// Add Ext to Filename if Filename has no file extension.
StringRef LinkerDriver::addExtOpt(StringRef Filename, StringRef Ext) {
// Find library file from search path.
StringRef LinkerDriver::doFindLib(StringRef Filename) {
// Add ".lib" to Filename if that has no file extension.
bool hasExt = (Filename.find('.') != StringRef::npos);
if (hasExt)
return Filename;
return Alloc.save(Filename + Ext);
if (!hasExt)
Filename = Alloc.save(Filename + ".lib");
return doFindFile(Filename);
}
// Resolves a library path. /nodefaultlib options are taken into
// consideration. This never returns the same path (in that case,
// it returns None).
Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
if (Config->NoDefaultLibAll)
return None;
StringRef Path = doFindLib(Filename);
if (Config->NoDefaultLibs.count(Path))
return None;
bool Seen = !VisitedFiles.insert(Path.lower()).second;
if (Seen)
return None;
return Path;
}
// Parses LIB environment which contains a list of search paths.
@ -190,6 +208,14 @@ bool LinkerDriver::link(int Argc, const char *Argv[]) {
}
Config->MachineType = MTOrErr.get();
// Handle /nodefaultlib:<filename>
for (auto *Arg : Args->filtered(OPT_nodefaultlib))
Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
// Handle /nodefaultlib
if (Args->hasArg(OPT_nodefaultlib_all))
Config->NoDefaultLibAll = true;
// Handle /base
if (auto *Arg = Args->getLastArg(OPT_base)) {
if (auto EC = parseNumbers(Arg->getValue(), &Config->ImageBase)) {
@ -235,13 +261,20 @@ bool LinkerDriver::link(int Argc, const char *Argv[]) {
}
}
// Create a list of input files. Files can be given as arguments
// for /defaultlib option.
std::vector<StringRef> Inputs;
for (auto *Arg : Args->filtered(OPT_INPUT))
if (Optional<StringRef> Path = findFile(Arg->getValue()))
Inputs.push_back(*Path);
for (auto *Arg : Args->filtered(OPT_defaultlib))
if (Optional<StringRef> Path = findLib(Arg->getValue()))
Inputs.push_back(*Path);
// Parse all input files and put all symbols to the symbol table.
// The symbol table will take care of name resolution.
SymbolTable Symtab;
for (auto *Arg : Args->filtered(OPT_INPUT)) {
StringRef Path = findFile(Arg->getValue());
if (!insertFile(Path))
continue;
for (StringRef Path : Inputs) {
if (auto EC = Symtab.addFile(createFile(Path))) {
llvm::errs() << Path << ": " << EC.message() << "\n";
return false;
@ -289,9 +322,5 @@ bool LinkerDriver::link(int Argc, const char *Argv[]) {
return true;
}
bool LinkerDriver::insertFile(StringRef Path) {
return VisitedFiles.insert(Path.lower()).second;
}
} // namespace coff
} // namespace lld

View File

@ -11,6 +11,7 @@
#define LLD_COFF_DRIVER_H
#include "Memory.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Option/Arg.h"
@ -28,6 +29,7 @@ extern LinkerDriver *Driver;
using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
using llvm::Optional;
class InputFile;
// Entry point of the COFF linker.
@ -43,13 +45,13 @@ public:
parseDirectives(StringRef S, std::vector<std::unique_ptr<InputFile>> *Res);
private:
// Returns false if a given file has already been read.
bool insertFile(StringRef Path);
StringAllocator Alloc;
// Searches a file from search paths.
StringRef findFile(StringRef Filename);
StringRef findLib(StringRef Filename);
StringRef addExtOpt(StringRef Filename, StringRef Ext);
Optional<StringRef> findFile(StringRef Filename);
Optional<StringRef> findLib(StringRef Filename);
StringRef doFindFile(StringRef Filename);
StringRef doFindLib(StringRef Filename);
// Parses LIB environment which contains a list of search paths.
// The returned list always contains "." as the first element.
@ -57,7 +59,6 @@ private:
std::vector<StringRef> SearchPaths;
std::set<std::string> VisitedFiles;
StringAllocator Alloc;
};
ErrorOr<std::unique_ptr<llvm::opt::InputArgList>>

View File

@ -0,0 +1,30 @@
# RUN: cp %p/Inputs/hello64.obj %T
# RUN: cp %p/Inputs/std64.lib %T
# RUN: not lld -flavor link2 /out:%t.exe /entry:main /subsystem:console \
# RUN: hello64.obj /defaultlib:std64.lib >& %t.log
# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
# RUN: not lld -flavor link2 /out:%t.exe /entry:main /subsystem:console \
# RUN: hello64 /defaultlib:std64.lib >& %t.log
# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
### On Windows, "env" command does not propagate subcommand exit status.
### On Unix it does. "|| true" is a hack to deal with that.
# RUN: env LIB=%T lld -flavor link2 /out:%t.exe /entry:main \
# RUN: /subsystem:console hello64.obj /defaultlib:std64.lib \
# RUN: /nodefaultlib:std64.lib >& %t.log || true
# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log
# RUN: env LIB=%T lld -flavor link2 /out:%t.exe /entry:main \
# RUN: /subsystem:console hello64.obj /defaultlib:std64 \
# RUN: /nodefaultlib:std64.lib >& %t.log || true
# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log
CHECK1: hello64.obj: {{[Nn]}}o such file or directory
CHECK2: hello64: {{[Nn]}}o such file or directory
CHECK3: undefined symbol: MessageBoxA
# RUN: env LIB=%T lld -flavor link2 /out:%t.exe /entry:main \
# RUN: /subsystem:console hello64.obj /defaultlib:std64.lib