<div dir="ltr">I'm copying some LLD code into my codebase like this:<div><br></div><div><div>// workaround for LLD not exposing ability to convert .def to .lib</div><div><br></div><div>#include <set></div><div><br></div><div>namespace lld {</div><div>namespace coff {</div><div><br></div><div>class SymbolBody;</div><div>class StringChunk;</div><div>struct Symbol;</div><div><br></div><div>struct Export {</div><div>  StringRef Name;       // N in /export:N or /export:E=N</div><div>  StringRef ExtName;    // E in /export:E=N</div><div>  SymbolBody *Sym = nullptr;</div><div>  uint16_t Ordinal = 0;</div><div>  bool Noname = false;</div><div>  bool Data = false;</div><div>  bool Private = false;</div><div><br></div><div>  // If an export is a form of /export:foo=dllname.bar, that means</div><div>  // that foo should be exported as an alias to bar in the DLL.</div><div>  // ForwardTo is set to "dllname.bar" part. Usually empty.</div><div>  StringRef ForwardTo;</div><div>  StringChunk *ForwardChunk = nullptr;</div><div><br></div><div>  // True if this /export option was in .drectves section.</div><div>  bool Directives = false;</div><div>  StringRef SymbolName;</div><div>  StringRef ExportName; // Name in DLL</div><div><br></div><div>  bool operator==(const Export &E) {</div><div>    return (Name == E.Name && ExtName == E.ExtName &&</div><div>            Ordinal == E.Ordinal && Noname == E.Noname &&</div><div>            Data == E.Data && Private == E.Private);</div><div>  }</div><div>};</div><div><br></div><div>enum class DebugType {</div><div>  None  = 0x0,</div><div>  CV    = 0x1,  /// CodeView</div><div>  PData = 0x2,  /// Procedure Data</div><div>  Fixup = 0x4,  /// Relocation Table</div><div>};</div><div><br></div><div>struct Configuration {</div><div>  enum ManifestKind { SideBySide, Embed, No };</div><div>  llvm::COFF::MachineTypes Machine = llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;</div><div>  bool Verbose = false;</div><div>  llvm::COFF::WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;</div><div>  SymbolBody *Entry = nullptr;</div><div>  bool NoEntry = false;</div><div>  std::string OutputFile;</div><div>  bool DoGC = true;</div><div>  bool DoICF = true;</div><div>  bool Relocatable = true;</div><div>  bool Force = false;</div><div>  bool Debug = false;</div><div>  bool WriteSymtab = true;</div><div>  unsigned DebugTypes = static_cast<unsigned>(DebugType::None);</div><div>  StringRef PDBPath;</div><div><br></div><div>  // Symbols in this set are considered as live by the garbage collector.</div><div>  std::set<SymbolBody *> GCRoot;</div><div><br></div><div>  std::set<StringRef> NoDefaultLibs;</div><div>  bool NoDefaultLibAll = false;</div><div><br></div><div>  // True if we are creating a DLL.</div><div>  bool DLL = false;</div><div>  StringRef Implib;</div><div>  std::vector<Export> Exports;</div><div>  std::set<std::string> DelayLoads;</div><div>  std::map<std::string, int> DLLOrder;</div><div>  SymbolBody *DelayLoadHelper = nullptr;</div><div><br></div><div>  // Used for SafeSEH.</div><div>  Symbol *SEHTable = nullptr;</div><div>  Symbol *SEHCount = nullptr;</div><div><br></div><div>  // Used for /opt:lldlto=N</div><div>  unsigned LTOOptLevel = 2;</div><div><br></div><div>  // Used for /opt:lldltojobs=N</div><div>  unsigned LTOJobs = 1;</div><div><br></div><div>  // Used for /merge:from=to (e.g. /merge:.rdata=.text)</div><div>  std::map<StringRef, StringRef> Merge;</div><div><br></div><div>  // Used for /section=.name,{DEKPRSW} to set section attributes.</div><div>  std::map<StringRef, uint32_t> Section;</div><div><br></div><div>  // Options for manifest files.</div><div>  ManifestKind Manifest = SideBySide;</div><div>  int ManifestID = 1;</div><div>  StringRef ManifestDependency;</div><div>  bool ManifestUAC = true;</div><div>  std::vector<std::string> ManifestInput;</div><div>  StringRef ManifestLevel = "'asInvoker'";</div><div>  StringRef ManifestUIAccess = "'false'";</div><div>  StringRef ManifestFile;</div><div><br></div><div>  // Used for /failifmismatch.</div><div>  std::map<StringRef, StringRef> MustMatch;</div><div><br></div><div>  // Used for /alternatename.</div><div>  std::map<StringRef, StringRef> AlternateNames;</div><div><br></div><div>  uint64_t ImageBase = -1;</div><div>  uint64_t StackReserve = 1024 * 1024;</div><div>  uint64_t StackCommit = 4096;</div><div>  uint64_t HeapReserve = 1024 * 1024;</div><div>  uint64_t HeapCommit = 4096;</div><div>  uint32_t MajorImageVersion = 0;</div><div>  uint32_t MinorImageVersion = 0;</div><div>  uint32_t MajorOSVersion = 6;</div><div>  uint32_t MinorOSVersion = 0;</div><div>  bool DynamicBase = true;</div><div>  bool AllowBind = true;</div><div>  bool NxCompat = true;</div><div>  bool AllowIsolation = true;</div><div>  bool TerminalServerAware = true;</div><div>  bool LargeAddressAware = false;</div><div>  bool HighEntropyVA = false;</div><div><br></div><div>  // This is for debugging.</div><div>  bool DebugPdb = false;</div><div>  bool DumpPdb = false;</div><div>};</div><div><br></div><div>extern Configuration *Config;</div><div><br></div><div>void writeImportLibrary();</div><div>void parseModuleDefs(MemoryBufferRef MB);</div><div><br></div><div>} // namespace coff</div><div>} // namespace lld</div><div><br></div><div>//=========================================================================</div><div><br></div><div><br></div><div><br></div><div><br></div><div>This is so that I can write the following user code:</div><div><br></div><div><br></div><div><br></div><div>// writes the output to dll_path with .dll replaced with .lib</div><div>void ZigLLDDefToLib(Buf *def_contents, Buf *dll_path) {</div><div>    lld::coff::Config = new lld::coff::Configuration;</div><div>    auto mem_buf = MemoryBuffer::getMemBuffer(buf_ptr(def_contents));</div><div>    MemoryBufferRef mbref(*mem_buf);</div><div>    lld::coff::parseModuleDefs(mbref);</div><div>    lld::coff::Config->OutputFile = buf_ptr(dll_path);</div><div>    lld::coff::writeImportLibrary();</div><div>}</div></div><div><br></div><div><br></div><div>Then I give it def_contents that looks like:</div><div><div>LIBRARY kernel32</div><div>EXPORTS</div><div>ExitProcess</div><div>GetConsoleMode</div><div>GetStdHandle</div><div>GetFileInformationByHandleEx</div><div>WriteFile</div><div>GetLastError</div></div><div><br></div><div><br></div><div>with dll_path set to ./zig-cache/all.dll. This generates ./zig-cache/all.lib.</div><div><br></div><div>The generated LLVM IR looks like:</div><div><br></div><div><div>; Function Attrs: noreturn nounwind</div><div>declare void @ExitProcess(i32) #6</div></div><div><div>; Function Attrs: nounwind</div><div>declare i1 @GetConsoleMode(i8* nonnull, i32* nonnull) #3</div><div>; Function Attrs: nounwind</div><div>declare i8* @GetStdHandle(i32) #3</div></div><div><div>; Function Attrs: nounwind</div><div>declare i1 @GetFileInformationByHandleEx(i8* nonnull, i32, i8* nonnull, i32) #3</div></div><div><div>; Function Attrs: nounwind</div><div>declare i1 @WriteFile(i8* nonnull, i8* nonnull readonly, i32, i32*, %OVERLAPPED*) #3</div><div>; Function Attrs: nounwind</div><div>declare i32 @GetLastError() #3</div></div><div><br></div><div>...with code you would expect to call these functions.</div><div><br></div><div>Then I link with </div><div><div>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</div></div><div><br></div><div><br></div><div>and I get the following errors:</div><div><div>./zig-cache/hello.obj: undefined symbol: ExitProcess</div><div>./zig-cache/hello.obj: undefined symbol: GetConsoleMode</div><div>./zig-cache/hello.obj: undefined symbol: GetStdHandle</div><div>./zig-cache/hello.obj: undefined symbol: GetFileInformationByHandleEx</div><div>./zig-cache/hello.obj: undefined symbol: GetLastError</div><div>./zig-cache/hello.obj: undefined symbol: WriteFile</div><div>error: link failed</div></div><div><br></div><div><br></div><div><br></div><div>1. Is there something else I need to be doing to make this work correctly?</div><div>(Note: I already tried renaming "all" to "kernel32". Ideally I could generate 1 .lib file for all the DLL calls needed.)</div><div>2. Can LLD expose this ability directly so I don't have to copy paste a bunch of LLD internal stuff?</div><div><br></div><div>Regards,</div><div>Andrew Kelley</div><div><a href="http://ziglang.org">ziglang.org</a><br></div><div><br></div></div>