Skip to content

Commit 395ec44

Browse files
author
Vadim Paretsky (Intel Americas Inc)
committed
[llvm-lib] 'llvm-lib' currently cannot generate an import library from a Windows
.def file, functionality supported by 'lib'. This incompatibility is breaking clang based Windows openmp builds. This revision adds basic support for this feature to llvm-lib by cloning the corresponding code from 'dlltool'. Differential Revision:https://reviews.llvm.org/D144765
1 parent 52ced14 commit 395ec44

File tree

3 files changed

+88
-22
lines changed

3 files changed

+88
-22
lines changed

llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp

Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/Bitcode/BitcodeReader.h"
2020
#include "llvm/Object/ArchiveWriter.h"
2121
#include "llvm/Object/COFF.h"
22+
#include "llvm/Object/COFFModuleDefinition.h"
2223
#include "llvm/Object/WindowsMachineFlag.h"
2324
#include "llvm/Option/Arg.h"
2425
#include "llvm/Option/ArgList.h"
@@ -31,6 +32,7 @@
3132
#include <optional>
3233

3334
using namespace llvm;
35+
using namespace llvm::object;
3436

3537
namespace {
3638

@@ -60,7 +62,7 @@ class LibOptTable : public opt::GenericOptTable {
6062
public:
6163
LibOptTable() : opt::GenericOptTable(InfoTable, true) {}
6264
};
63-
}
65+
} // namespace
6466

6567
static std::string getDefaultOutputPath(const NewArchiveMember &FirstMember) {
6668
SmallString<128> Val = StringRef(FirstMember.Buf->getBufferIdentifier());
@@ -91,6 +93,18 @@ static std::vector<StringRef> getSearchPaths(opt::InputArgList *Args,
9193
return Ret;
9294
}
9395

96+
// Opens a file. Path has to be resolved already. (used for def file)
97+
std::unique_ptr<MemoryBuffer> openFile(const Twine &Path) {
98+
ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = MemoryBuffer::getFile(Path);
99+
100+
if (std::error_code EC = MB.getError()) {
101+
llvm::errs() << "cannot open file " << Path << ": " << EC.message() << "\n";
102+
return nullptr;
103+
}
104+
105+
return std::move(*MB);
106+
}
107+
94108
static std::string findInputFile(StringRef File, ArrayRef<StringRef> Paths) {
95109
for (StringRef Dir : Paths) {
96110
SmallString<128> Path = Dir;
@@ -110,7 +124,7 @@ static void fatalOpenError(llvm::Error E, Twine File) {
110124
});
111125
}
112126

113-
static void doList(opt::InputArgList& Args) {
127+
static void doList(opt::InputArgList &Args) {
114128
// lib.exe prints the contents of the first archive file.
115129
std::unique_ptr<MemoryBuffer> B;
116130
for (auto *Arg : Args.filtered(OPT_INPUT)) {
@@ -302,6 +316,63 @@ int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) {
302316
for (auto *Arg : Args.filtered(OPT_ignore))
303317
IgnoredWarnings.insert(Arg->getValue());
304318

319+
// get output library path, if any
320+
std::string OutputPath;
321+
if (auto *Arg = Args.getLastArg(OPT_out)) {
322+
OutputPath = Arg->getValue();
323+
}
324+
325+
COFF::MachineTypes LibMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN;
326+
std::string LibMachineSource;
327+
if (auto *Arg = Args.getLastArg(OPT_machine)) {
328+
LibMachine = getMachineType(Arg->getValue());
329+
if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
330+
llvm::errs() << "unknown /machine: arg " << Arg->getValue() << '\n';
331+
return 1;
332+
}
333+
LibMachineSource =
334+
std::string(" (from '/machine:") + Arg->getValue() + "' flag)";
335+
}
336+
337+
// create an import library
338+
if (Args.hasArg(OPT_deffile)) {
339+
340+
if (OutputPath.empty()) {
341+
llvm::errs() << "no output path given\n";
342+
return 1;
343+
}
344+
345+
if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
346+
llvm::errs() << "/def option requires /machine to be specified" << '\n';
347+
return 1;
348+
}
349+
350+
std::unique_ptr<MemoryBuffer> MB =
351+
openFile(Args.getLastArg(OPT_deffile)->getValue());
352+
if (!MB)
353+
return 1;
354+
355+
if (!MB->getBufferSize()) {
356+
llvm::errs() << "definition file empty\n";
357+
return 1;
358+
}
359+
360+
Expected<COFFModuleDefinition> Def =
361+
parseCOFFModuleDefinition(*MB, LibMachine, true);
362+
363+
if (!Def) {
364+
llvm::errs() << "error parsing definition\n"
365+
<< errorToErrorCode(Def.takeError()).message();
366+
return 1;
367+
}
368+
369+
return writeImportLibrary(Def->OutputFile, OutputPath, Def->Exports,
370+
LibMachine,
371+
/*MinGW=*/false)
372+
? 1
373+
: 0;
374+
}
375+
305376
// If no input files and not told otherwise, silently do nothing to match
306377
// lib.exe
307378
if (!Args.hasArgNoClaim(OPT_INPUT) && !Args.hasArg(OPT_llvmlibempty)) {
@@ -324,18 +395,6 @@ int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) {
324395

325396
std::vector<StringRef> SearchPaths = getSearchPaths(&Args, Saver);
326397

327-
COFF::MachineTypes LibMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN;
328-
std::string LibMachineSource;
329-
if (auto *Arg = Args.getLastArg(OPT_machine)) {
330-
LibMachine = getMachineType(Arg->getValue());
331-
if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
332-
llvm::errs() << "unknown /machine: arg " << Arg->getValue() << '\n';
333-
return 1;
334-
}
335-
LibMachineSource =
336-
std::string(" (from '/machine:") + Arg->getValue() + "' flag)";
337-
}
338-
339398
std::vector<std::unique_ptr<MemoryBuffer>> MBs;
340399
StringSet<> Seen;
341400
std::vector<NewArchiveMember> Members;
@@ -373,14 +432,13 @@ int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) {
373432
}
374433

375434
// Create an archive file.
376-
std::string OutputPath;
377-
if (auto *Arg = Args.getLastArg(OPT_out)) {
378-
OutputPath = Arg->getValue();
379-
} else if (!Members.empty()) {
380-
OutputPath = getDefaultOutputPath(Members[0]);
381-
} else {
382-
llvm::errs() << "no output path given, and cannot infer with no inputs\n";
383-
return 1;
435+
if (OutputPath.empty()) {
436+
if (!Members.empty()) {
437+
OutputPath = getDefaultOutputPath(Members[0]);
438+
} else {
439+
llvm::errs() << "no output path given, and cannot infer with no inputs\n";
440+
return 1;
441+
}
384442
}
385443
// llvm-lib uses relative paths for both regular and thin archives, unlike
386444
// standard GNU ar, which only uses relative paths for thin archives and

llvm/lib/ToolDrivers/llvm-lib/Options.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def libpath: P<"libpath", "Object file search path">;
2222
// Can't be called "list" since that's a keyword.
2323
def lst : F<"list">, HelpText<"List contents of .lib file on stdout">;
2424
def out : P<"out", "Path to file to write output">;
25+
def deffile : P<"def", "def file to use to generate import library">;
2526

2627
def llvmlibthin : F<"llvmlibthin">,
2728
HelpText<"Make .lib point to .obj files instead of copying their contents">;

llvm/test/tools/llvm-lib/implibs.test

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,10 @@ RUN: llvm-lib -out:%t/newlib.lib %t/lib.lib
1010

1111
RUN: llvm-ar t %t/newlib.lib | FileCheck %s
1212
CHECK: lib.dll
13+
14+
Test that import libraries can be created from a def file
15+
16+
RUN: echo -e "NAME lib.dll\nEXPORTS\nMyFunc" > %t/implib.def
17+
RUN: llvm-lib -out:%t/implib.lib -def:%t/implib.def -machine:x64
18+
19+
RUN: llvm-ar t %t/implib.lib | FileCheck %s

0 commit comments

Comments
 (0)