[llvm-dev] Using LLD to create a .lib from a .def

Andrew Kelley via llvm-dev llvm-dev at lists.llvm.org
Fri Jun 16 11:53:45 PDT 2017


I saw this change come in yesterday:

commit 572ad839e2f66eaa82ffc71b1061eb3d06a4d126
Author: Saleem Abdulrasool <compnerd at compnerd.org>
Date:   Thu Jun 15 20:39:58 2017 +0000

    COFF: add support for lib mode usage

    When link is invoked with `/def:` and no input files, it behaves as if
    `lib.exe` was invoked.  Emulate this behaviour, generating the import
    library from the def file that was passed.  Because there is no input to
    actually generate the dll, we simply process the def file early and exit
    once we have created the import library.


Thank you for this, Saleem.

I still have this problem though, with latest master of llvm-project, which
is bd8af0ee30bc1a308bf286089b172f2ae87f3de5

llvm-config: error: component libraries and shared library

llvm-config: error: missing: /home/andy/local/lib/libLLVMTestingSupport.a

I'm pretty sure it's not just me, anyone should be able to reproduce this
issue with a clean build.

Regards,
Andrew

On Thu, Jun 15, 2017 at 12:29 PM, Andrew Kelley <superjoe30 at gmail.com>
wrote:

> When I build llvm-project from source (revision
> 53a3cb539f7e92e70d4eef8d1b219cbef7c8ba1c from https://github.com/llvm-
> project/llvm-project-20170507)
>
> The build and install seemed to work correctly. But then when I run
> `llvm-config --libfiles`, I get this:
>
> llvm-config: error: component libraries and shared library
>
> llvm-config: error: missing: /home/andy/local/lib/libLLVMTestingSupport.a
>
>
> The library got built: ./llvm/build/lib/libLLVMTestingSupport.a
> But `make install` didn't copy it to the prefix path.
>
>
> On Thu, Jun 15, 2017 at 10:33 AM, Andrew Kelley <superjoe30 at gmail.com>
> wrote:
>
>>
>>
>> On Wed, Jun 14, 2017 at 7:37 PM, Rui Ueyama <ruiu at google.com> wrote:
>>
>>> On Wed, Jun 14, 2017 at 4:24 PM, Andrew Kelley via llvm-dev <
>>> llvm-dev at lists.llvm.org> wrote:
>>>
>>>> I'm copying some LLD code into my codebase like this:
>>>>
>>>> // workaround for LLD not exposing ability to convert .def to .lib
>>>>
>>>> #include <set>
>>>>
>>>> namespace lld {
>>>> namespace coff {
>>>>
>>>> class SymbolBody;
>>>> class StringChunk;
>>>> struct Symbol;
>>>>
>>>> struct Export {
>>>>   StringRef Name;       // N in /export:N or /export:E=N
>>>>   StringRef ExtName;    // E in /export:E=N
>>>>   SymbolBody *Sym = nullptr;
>>>>   uint16_t Ordinal = 0;
>>>>   bool Noname = false;
>>>>   bool Data = false;
>>>>   bool Private = false;
>>>>
>>>>   // If an export is a form of /export:foo=dllname.bar, that means
>>>>   // that foo should be exported as an alias to bar in the DLL.
>>>>   // ForwardTo is set to "dllname.bar" part. Usually empty.
>>>>   StringRef ForwardTo;
>>>>   StringChunk *ForwardChunk = nullptr;
>>>>
>>>>   // True if this /export option was in .drectves section.
>>>>   bool Directives = false;
>>>>   StringRef SymbolName;
>>>>   StringRef ExportName; // Name in DLL
>>>>
>>>>   bool operator==(const Export &E) {
>>>>     return (Name == E.Name && ExtName == E.ExtName &&
>>>>             Ordinal == E.Ordinal && Noname == E.Noname &&
>>>>             Data == E.Data && Private == E.Private);
>>>>   }
>>>> };
>>>>
>>>> enum class DebugType {
>>>>   None  = 0x0,
>>>>   CV    = 0x1,  /// CodeView
>>>>   PData = 0x2,  /// Procedure Data
>>>>   Fixup = 0x4,  /// Relocation Table
>>>> };
>>>>
>>>> struct Configuration {
>>>>   enum ManifestKind { SideBySide, Embed, No };
>>>>   llvm::COFF::MachineTypes Machine = llvm::COFF::IMAGE_FILE_MACHINE
>>>> _UNKNOWN;
>>>>   bool Verbose = false;
>>>>   llvm::COFF::WindowsSubsystem Subsystem =
>>>> llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
>>>>   SymbolBody *Entry = nullptr;
>>>>   bool NoEntry = false;
>>>>   std::string OutputFile;
>>>>   bool DoGC = true;
>>>>   bool DoICF = true;
>>>>   bool Relocatable = true;
>>>>   bool Force = false;
>>>>   bool Debug = false;
>>>>   bool WriteSymtab = true;
>>>>   unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
>>>>   StringRef PDBPath;
>>>>
>>>>   // Symbols in this set are considered as live by the garbage
>>>> collector.
>>>>   std::set<SymbolBody *> GCRoot;
>>>>
>>>>   std::set<StringRef> NoDefaultLibs;
>>>>   bool NoDefaultLibAll = false;
>>>>
>>>>   // True if we are creating a DLL.
>>>>   bool DLL = false;
>>>>   StringRef Implib;
>>>>   std::vector<Export> Exports;
>>>>   std::set<std::string> DelayLoads;
>>>>   std::map<std::string, int> DLLOrder;
>>>>   SymbolBody *DelayLoadHelper = nullptr;
>>>>
>>>>   // Used for SafeSEH.
>>>>   Symbol *SEHTable = nullptr;
>>>>   Symbol *SEHCount = nullptr;
>>>>
>>>>   // Used for /opt:lldlto=N
>>>>   unsigned LTOOptLevel = 2;
>>>>
>>>>   // Used for /opt:lldltojobs=N
>>>>   unsigned LTOJobs = 1;
>>>>
>>>>   // Used for /merge:from=to (e.g. /merge:.rdata=.text)
>>>>   std::map<StringRef, StringRef> Merge;
>>>>
>>>>   // Used for /section=.name,{DEKPRSW} to set section attributes.
>>>>   std::map<StringRef, uint32_t> Section;
>>>>
>>>>   // Options for manifest files.
>>>>   ManifestKind Manifest = SideBySide;
>>>>   int ManifestID = 1;
>>>>   StringRef ManifestDependency;
>>>>   bool ManifestUAC = true;
>>>>   std::vector<std::string> ManifestInput;
>>>>   StringRef ManifestLevel = "'asInvoker'";
>>>>   StringRef ManifestUIAccess = "'false'";
>>>>   StringRef ManifestFile;
>>>>
>>>>   // Used for /failifmismatch.
>>>>   std::map<StringRef, StringRef> MustMatch;
>>>>
>>>>   // Used for /alternatename.
>>>>   std::map<StringRef, StringRef> AlternateNames;
>>>>
>>>>   uint64_t ImageBase = -1;
>>>>   uint64_t StackReserve = 1024 * 1024;
>>>>   uint64_t StackCommit = 4096;
>>>>   uint64_t HeapReserve = 1024 * 1024;
>>>>   uint64_t HeapCommit = 4096;
>>>>   uint32_t MajorImageVersion = 0;
>>>>   uint32_t MinorImageVersion = 0;
>>>>   uint32_t MajorOSVersion = 6;
>>>>   uint32_t MinorOSVersion = 0;
>>>>   bool DynamicBase = true;
>>>>   bool AllowBind = true;
>>>>   bool NxCompat = true;
>>>>   bool AllowIsolation = true;
>>>>   bool TerminalServerAware = true;
>>>>   bool LargeAddressAware = false;
>>>>   bool HighEntropyVA = false;
>>>>
>>>>   // This is for debugging.
>>>>   bool DebugPdb = false;
>>>>   bool DumpPdb = false;
>>>> };
>>>>
>>>> extern Configuration *Config;
>>>>
>>>> void writeImportLibrary();
>>>> void parseModuleDefs(MemoryBufferRef MB);
>>>>
>>>> } // namespace coff
>>>> } // namespace lld
>>>>
>>>> //==========================================================
>>>> ===============
>>>>
>>>>
>>>>
>>>>
>>>> This is so that I can write the following user code:
>>>>
>>>>
>>>>
>>>> // writes the output to dll_path with .dll replaced with .lib
>>>> void ZigLLDDefToLib(Buf *def_contents, Buf *dll_path) {
>>>>     lld::coff::Config = new lld::coff::Configuration;
>>>>     auto mem_buf = MemoryBuffer::getMemBuffer(buf_ptr(def_contents));
>>>>     MemoryBufferRef mbref(*mem_buf);
>>>>     lld::coff::parseModuleDefs(mbref);
>>>>     lld::coff::Config->OutputFile = buf_ptr(dll_path);
>>>>     lld::coff::writeImportLibrary();
>>>> }
>>>>
>>>>
>>>> Then I give it def_contents that looks like:
>>>> LIBRARY kernel32
>>>> EXPORTS
>>>> ExitProcess
>>>> GetConsoleMode
>>>> GetStdHandle
>>>> GetFileInformationByHandleEx
>>>> WriteFile
>>>> GetLastError
>>>>
>>>>
>>>> with dll_path set to ./zig-cache/all.dll. This generates
>>>> ./zig-cache/all.lib.
>>>>
>>>> The generated LLVM IR looks like:
>>>>
>>>> ; Function Attrs: noreturn nounwind
>>>> declare void @ExitProcess(i32) #6
>>>> ; Function Attrs: nounwind
>>>> declare i1 @GetConsoleMode(i8* nonnull, i32* nonnull) #3
>>>> ; Function Attrs: nounwind
>>>> declare i8* @GetStdHandle(i32) #3
>>>> ; Function Attrs: nounwind
>>>> declare i1 @GetFileInformationByHandleEx(i8* nonnull, i32, i8*
>>>> nonnull, i32) #3
>>>> ; Function Attrs: nounwind
>>>> declare i1 @WriteFile(i8* nonnull, i8* nonnull readonly, i32, i32*,
>>>> %OVERLAPPED*) #3
>>>> ; Function Attrs: nounwind
>>>> declare i32 @GetLastError() #3
>>>>
>>>> ...with code you would expect to call these functions.
>>>>
>>>> Then I link with
>>>> lld -NOLOGO -MACHINE:X64 -OUT:hello.exe -NODEFAULTLIB -ENTRY:_start
>>>> ./zig-cache/hello.obj ./zig-cache/builtin.obj ./zig-cache/compiler_rt.obj
>>>> ./zig-cache/all.lib
>>>>
>>>>
>>>> and I get the following errors:
>>>> ./zig-cache/hello.obj: undefined symbol: ExitProcess
>>>> ./zig-cache/hello.obj: undefined symbol: GetConsoleMode
>>>> ./zig-cache/hello.obj: undefined symbol: GetStdHandle
>>>> ./zig-cache/hello.obj: undefined symbol: GetFileInformationByHandleEx
>>>> ./zig-cache/hello.obj: undefined symbol: GetLastError
>>>> ./zig-cache/hello.obj: undefined symbol: WriteFile
>>>> error: link failed
>>>>
>>>>
>>>>
>>>> 1. Is there something else I need to be doing to make this work
>>>> correctly?
>>>>
>>>
>>> The first thing I would check is to make sure that you created your .lib
>>> file for x86-64. Windows uses different name mangling scheme for x86 and
>>> x86-64, so if you mix the two, it could result in an "undefined symbol"
>>> error.
>>>
>>
>> I tested this by setting the machine in the config directly to AMD64.
>>
>>
>>>
>>>
>>>> (Note: I already tried renaming "all" to "kernel32". Ideally I could
>>>> generate 1 .lib file for all the DLL calls needed.)
>>>> 2. Can LLD expose this ability directly so I don't have to copy paste a
>>>> bunch of LLD internal stuff?
>>>>
>>>
>>> Martell recently factored out the code to parse and generate module
>>> definition files. You might be able to use that. See
>>> llvm/Object/COFFModuleDefinition.h.
>>>
>>> The location at where LLD uses COFFModuleDefinition.h is in
>>> parseModuleDefs and createImportLibrary in COFF/Driver.cpp.
>>>
>>
>> OK, thanks. I'll get a build going with latest trunk and see if I can get
>> it to work.
>>
>>
>>>
>>> Regards,
>>>> Andrew Kelley
>>>> ziglang.org
>>>>
>>>>
>>>> _______________________________________________
>>>> LLVM Developers mailing list
>>>> llvm-dev at lists.llvm.org
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170616/e3023734/attachment.html>


More information about the llvm-dev mailing list