[COFF] Add vfsoverlay flag

This patch adds a new flag vfsoverlay similar to clang’s
ivfsoverlay flag. This is helpful when compiling on case
sensitive file systems when cross compiling to Windows.
Particularly when compiling third party code containing
\#pragma comment(“linker”, “/defaultlib:...”) which
can’t be easily changed.

Differential Revision: https://reviews.llvm.org/D125800
This commit is contained in:
Alex Brachet 2022-07-11 21:31:01 +00:00
parent c179bcc151
commit fd9962e75d
4 changed files with 73 additions and 1 deletions

View File

@ -15,6 +15,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/CachePruning.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <cstdint>
#include <map>
#include <set>
@ -238,6 +239,9 @@ struct Configuration {
// Used for /print-symbol-order:
StringRef printSymbolOrder;
// Used for /vfsoverlay:
std::unique_ptr<llvm::vfs::FileSystem> vfs;
uint64_t align = 4096;
uint64_t imageBase = -1;
uint64_t fileAlign = 512;

View File

@ -436,17 +436,26 @@ void LinkerDriver::parseDirectives(InputFile *file) {
// 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::doFindFile(StringRef filename) {
auto getFilename = [](StringRef filename) -> StringRef {
if (config->vfs)
if (auto statOrErr = config->vfs->status(filename))
return saver().save(statOrErr->getName());
return filename;
};
bool hasPathSep = (filename.find_first_of("/\\") != StringRef::npos);
if (hasPathSep)
return filename;
return getFilename(filename);
bool hasExt = filename.contains('.');
for (StringRef dir : searchPaths) {
SmallString<128> path = dir;
sys::path::append(path, filename);
path = SmallString<128>{getFilename(path.str())};
if (sys::fs::exists(path.str()))
return saver().save(path.str());
if (!hasExt) {
path.append(".obj");
path = SmallString<128>{getFilename(path.str())};
if (sys::fs::exists(path.str()))
return saver().save(path.str());
}
@ -1349,6 +1358,28 @@ Optional<std::string> getReproduceFile(const opt::InputArgList &args) {
return None;
}
static std::unique_ptr<llvm::vfs::FileSystem>
getVFS(const opt::InputArgList &args) {
using namespace llvm::vfs;
const opt::Arg *arg = args.getLastArg(OPT_vfsoverlay);
if (!arg)
return nullptr;
auto bufOrErr = llvm::MemoryBuffer::getFile(arg->getValue());
if (!bufOrErr) {
checkError(errorCodeToError(bufOrErr.getError()));
return nullptr;
}
if (auto ret = vfs::getVFSFromYAML(std::move(*bufOrErr), /*DiagHandler*/ nullptr,
arg->getValue()))
return ret;
error("Invalid vfs overlay");
return nullptr;
}
void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
ScopedTimer rootTimer(ctx.rootTimer);
@ -1390,6 +1421,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
errorHandler().errorLimit = n;
}
config->vfs = getVFS(args);
// Handle /help
if (args.hasArg(OPT_help)) {
printHelp(argsArr[0]);

View File

@ -278,6 +278,8 @@ def print_symbol_order: P<
"/call-graph-profile-sort into the specified file">;
def wrap : P_priv<"wrap">;
def vfsoverlay : P<"vfsoverlay", "Path to a vfsoverlay yaml file to optionally look for /defaultlib's in">;
// Flags for debugging
def lldmap : F<"lldmap">;
def lldmap_file : P_priv<"lldmap">;

View File

@ -0,0 +1,33 @@
# RUN: rm -rf %t
# RUN: split-file %s %t
# RUN: cp %p/Inputs/std64.lib %t/std64.lib
# RUN: sed -e "s|REPLACE|%/t/std64.lib|g" %t/overlay.yaml.in > %t/overlay.yaml
# RUN: lld-link %S/Inputs/hello64.obj /libpath:/noexist /out:%t.exe /entry:main /defaultlib:notstd64 /vfsoverlay:%t/overlay.yaml
# RUN: not lld-link %S/Inputs/hello64.obj /libpath:/noexist /out:%t.exe /entry:main /defaultlib:notstd64 /vfsoverlay:noexist 2>&1 \
# RUN: | FileCheck %s
# CHECK: error: No such file or directory
# RUN: sed -e "s|{|bad|g" %t/overlay.yaml > %t/badoverlay.yaml
# RUN: not lld-link %S/Inputs/hello64.obj /libpath:/noexist /out:%t.exe /entry:main /defaultlib:notstd64 /vfsoverlay:%t/badoverlay.yaml 2>&1 \
# RUN: | FileCheck %s --check-prefix=BAD-OVERLAY
# BAD-OVERLAY: error: Invalid vfs overlay
#--- overlay.yaml.in
{
'version': 0,
'roots' : [
{
'name': '/noexist',
'type': 'directory',
'contents': [
{
'name': 'notstd64.lib',
'type': 'file',
'external-contents': 'REPLACE'
}
]
}
]
}