Index: llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp =================================================================== --- llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -19,6 +19,7 @@ #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/COFFModuleDefinition.h" #include "llvm/Object/WindowsMachineFlag.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" @@ -31,6 +32,7 @@ #include using namespace llvm; +using namespace llvm::object; namespace { @@ -60,7 +62,7 @@ public: LibOptTable() : opt::GenericOptTable(InfoTable, true) {} }; -} +} static std::string getDefaultOutputPath(const NewArchiveMember &FirstMember) { SmallString<128> Val = StringRef(FirstMember.Buf->getBufferIdentifier()); @@ -91,6 +93,18 @@ return Ret; } +// Opens a file. Path has to be resolved already. (used for def file) +std::unique_ptr openFile(const Twine &Path) { + ErrorOr> MB = MemoryBuffer::getFile(Path); + + if (std::error_code EC = MB.getError()) { + llvm::errs() << "cannot open file " << Path << ": " << EC.message() << "\n"; + return nullptr; + } + + return std::move(*MB); +} + static std::string findInputFile(StringRef File, ArrayRef Paths) { for (StringRef Dir : Paths) { SmallString<128> Path = Dir; @@ -302,6 +316,58 @@ for (auto *Arg : Args.filtered(OPT_ignore)) IgnoredWarnings.insert(Arg->getValue()); + COFF::MachineTypes LibMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; + std::string LibMachineSource; + if (auto *Arg = Args.getLastArg(OPT_machine)) { + LibMachine = getMachineType(Arg->getValue()); + if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) { + llvm::errs() << "unknown /machine: arg " << Arg->getValue() << '\n'; + return 1; + } + LibMachineSource = + std::string(" (from '/machine:") + Arg->getValue() + "' flag)"; + } + + // create an import library + if (Args.hasArg(OPT_DEF)) { + + if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) { + llvm::errs() << "/DEF option requires /machine to be specified" << '\n'; + return 1; + } + + std::unique_ptr MB = + openFile(Args.getLastArg(OPT_DEF)->getValue()); + if (!MB) + return 1; + + if (!MB->getBufferSize()) { + llvm::errs() << "definition file empty\n"; + return 1; + } + + Expected Def = + parseCOFFModuleDefinition(*MB, LibMachine, true); + + if (!Def) { + llvm::errs() << "error parsing definition\n" + << errorToErrorCode(Def.takeError()).message(); + return 1; + } + + std::string Path; + if (auto *Arg = Args.getLastArg(OPT_out)) { + Path = Arg->getValue(); + } + + if (Path.empty()) { + llvm::errs() << "no output path given\n"; + return 1; + } + + return writeImportLibrary(Def->OutputFile, Path, Def->Exports, LibMachine, true)? 1:0; + } + // If no input files and not told otherwise, silently do nothing to match // lib.exe if (!Args.hasArgNoClaim(OPT_INPUT) && !Args.hasArg(OPT_llvmlibempty)) { @@ -324,18 +390,6 @@ std::vector SearchPaths = getSearchPaths(&Args, Saver); - COFF::MachineTypes LibMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; - std::string LibMachineSource; - if (auto *Arg = Args.getLastArg(OPT_machine)) { - LibMachine = getMachineType(Arg->getValue()); - if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) { - llvm::errs() << "unknown /machine: arg " << Arg->getValue() << '\n'; - return 1; - } - LibMachineSource = - std::string(" (from '/machine:") + Arg->getValue() + "' flag)"; - } - std::vector> MBs; StringSet<> Seen; std::vector Members; Index: llvm/lib/ToolDrivers/llvm-lib/Options.td =================================================================== --- llvm/lib/ToolDrivers/llvm-lib/Options.td +++ llvm/lib/ToolDrivers/llvm-lib/Options.td @@ -22,6 +22,7 @@ // Can't be called "list" since that's a keyword. def lst : F<"list">, HelpText<"List contents of .lib file on stdout">; def out : P<"out", "Path to file to write output">; +def DEF : P<"DEF", "DEF file to use to generate import library">; def llvmlibthin : F<"llvmlibthin">, HelpText<"Make .lib point to .obj files instead of copying their contents">;