[PECOFF] Create an empty PDB file if debug option is enabled.

There are many build files in the wild that depend on the fact that
link.exe produces a PDB file if /DEBUG option is given. They fail
if the file is not created.

This patch is to make LLD create an empty (dummy) file to satisfy
such build targets. This doesn't do anything other than "touching"
the file.

If a target depends on the content of the PDB file, this workaround
is no help, of course. Otherwise this patch should help build some
stuff.

llvm-svn: 222773
This commit is contained in:
Rui Ueyama 2014-11-25 19:01:01 +00:00
parent bda193edff
commit 0d9a181d9d
6 changed files with 90 additions and 11 deletions

View File

@ -47,8 +47,8 @@ public:
_createManifest(true), _embedManifest(false), _manifestId(1),
_manifestUAC(true), _manifestLevel("'asInvoker'"),
_manifestUiAccess("'false'"), _isDll(false), _highEntropyVA(true),
_requireSEH(false), _noSEH(false), _implib(""),
_dosStub(llvm::makeArrayRef(DEFAULT_DOS_STUB)) {
_requireSEH(false), _noSEH(false), _implib(""), _debug(false),
_pdbFilePath(""), _dosStub(llvm::makeArrayRef(DEFAULT_DOS_STUB)) {
setDeadStripping(true);
}
@ -231,6 +231,12 @@ public:
void setOutputImportLibraryPath(const std::string &val) { _implib = val; }
std::string getOutputImportLibraryPath() const;
void setDebug(bool val) { _debug = val; }
bool getDebug() { return _debug; }
void setPDBFilePath(StringRef str) { _pdbFilePath = str; }
std::string getPDBFilePath() const;
void addDelayLoadDLL(StringRef dll) {
_delayLoadDLLs.insert(dll.lower());
}
@ -390,6 +396,12 @@ private:
// /IMPLIB command line option.
std::string _implib;
// True if /DEBUG is given.
bool _debug;
// PDB file output path. NB: this is dummy -- LLD just creates the empty file.
std::string _pdbFilePath;
// /DELAYLOAD option.
std::set<std::string> _delayLoadDLLs;

View File

@ -1180,6 +1180,7 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
// any effect.
// TODO: This should disable dead stripping. Currently we can't do that
// because removal of associative sections depends on dead stripping.
ctx.setDebug(true);
break;
case OPT_verbose:
@ -1267,6 +1268,10 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
inputFiles.push_back(ctx.allocate(inputArg->getValue()));
break;
case OPT_pdb:
ctx.setPDBFilePath(inputArg->getValue());
break;
case OPT_lldmoduledeffile:
ctx.setModuleDefinitionFile(inputArg->getValue());
break;

View File

@ -39,6 +39,7 @@ def stub : P<"stub", "Specify DOS stub file">;
def opt : P<"opt", "Control optimizations">;
def implib : P<"implib", "Import library name">;
def delayload : P<"delayload", "Delay loaded DLL name">;
def pdb : P<"pdb", "PDB file path">;
def manifest : F<"manifest">;
def manifest_colon : P<"manifest", "Create manifest file">;
@ -110,7 +111,6 @@ def delay : QF<"delay">;
def errorreport : QF<"errorreport">;
def idlout : QF<"idlout">;
def ignore : QF<"ignore">;
def pdb : QF<"pdb">;
def pdbaltpath : QF<"pdbaltpath">;
def tlbid : QF<"tlbid">;
def tlbout : QF<"tlbout">;

View File

@ -0,0 +1,41 @@
//===- lib/ReaderWriter/PECOFF/PDBPass.h ----------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_PE_COFF_PDB_PASS_H
#define LLD_READER_WRITER_PE_COFF_PDB_PASS_H
#include "lld/Core/Pass.h"
#include "llvm/ADT/StringRef.h"
namespace lld {
namespace pecoff {
class PDBPass : public lld::Pass {
public:
PDBPass(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
void perform(std::unique_ptr<MutableFile> &file) override {
if (_ctx.getDebug())
touch(_ctx.getPDBFilePath());
}
private:
void touch(StringRef path) {
int fd;
if (llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Append))
llvm::report_fatal_error("failed to create a PDB file");
}
PECOFFLinkingContext &_ctx;
};
} // namespace pecoff
} // namespace lld
#endif

View File

@ -14,6 +14,7 @@
#include "InferSubsystemPass.h"
#include "LinkerGeneratedSymbolFile.h"
#include "LoadConfigPass.h"
#include "PDBPass.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Simple.h"
#include "lld/Passes/LayoutPass.h"
@ -274,15 +275,27 @@ void PECOFFLinkingContext::addDllExport(ExportDesc &desc) {
_dllExports.push_back(desc);
}
static std::string replaceExtension(StringRef path, StringRef ext) {
SmallString<128> ss = path;
llvm::sys::path::replace_extension(ss, ext);
return ss.str();
}
std::string PECOFFLinkingContext::getOutputImportLibraryPath() const {
if (!_implib.empty())
return _implib;
SmallString<128> path = outputPath();
llvm::sys::path::replace_extension(path, ".lib");
return path.str();
return replaceExtension(outputPath(), ".lib");
}
std::string PECOFFLinkingContext::getPDBFilePath() const {
assert(_debug);
if (!_pdbFilePath.empty())
return _pdbFilePath;
return replaceExtension(outputPath(), ".pdb");
}
void PECOFFLinkingContext::addPasses(PassManager &pm) {
pm.add(std::unique_ptr<Pass>(new pecoff::PDBPass(*this)));
pm.add(std::unique_ptr<Pass>(new pecoff::EdataPass(*this)));
pm.add(std::unique_ptr<Pass>(new pecoff::IdataPass(*this)));
pm.add(std::unique_ptr<Pass>(new LayoutPass(registry())));

View File

@ -546,8 +546,16 @@ TEST_F(WinLinkParserTest, SwapRunFromNet) {
}
TEST_F(WinLinkParserTest, Debug) {
EXPECT_TRUE(parse("link.exe", "/debug", "a.out", nullptr));
EXPECT_TRUE(parse("link.exe", "/debug", "a.obj", nullptr));
EXPECT_TRUE(_context.deadStrip());
EXPECT_TRUE(_context.getDebug());
EXPECT_EQ("a.pdb", _context.getPDBFilePath());
}
TEST_F(WinLinkParserTest, PDB) {
EXPECT_TRUE(parse("link.exe", "/debug", "/pdb:foo.pdb", "a.obj", nullptr));
EXPECT_TRUE(_context.getDebug());
EXPECT_EQ("foo.pdb", _context.getPDBFilePath());
}
TEST_F(WinLinkParserTest, Fixed) {
@ -690,10 +698,10 @@ TEST_F(WinLinkParserTest, Ignore) {
// compatibility with link.exe.
EXPECT_TRUE(parse("link.exe", "/nologo", "/errorreport:prompt",
"/incremental", "/incremental:no", "/delay:unload",
"/disallowlib:foo", "/pdb:foo",
"/pdbaltpath:bar", "/verbose", "/verbose:icf", "/wx",
"/wx:no", "/tlbid:1", "/tlbout:foo", "/idlout:foo",
"/ignore:4000", "/ignoreidl", "/implib:foo", "/safeseh",
"/disallowlib:foo", "/pdbaltpath:bar", "/verbose",
"/verbose:icf", "/wx", "/wx:no", "/tlbid:1",
"/tlbout:foo", "/idlout:foo", "/ignore:4000",
"/ignoreidl", "/implib:foo", "/safeseh",
"/safeseh:no", "/functionpadmin", "a.obj", nullptr));
EXPECT_EQ("", errorMessage());
EXPECT_EQ(3, inputFileCount());