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

Andrew Kelley via llvm-dev llvm-dev at lists.llvm.org
Thu Jun 15 09:29:25 PDT 2017


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_UN
>>> KNOWN;
>>>   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/20170615/07786d5b/attachment.html>


More information about the llvm-dev mailing list