How to generate an import library (LIB-file) from a DLL?
Asked Answered
S

5

86

Is it possible to autogenerate a MSVC import library (LIB-file) from a DLL? How?

Souse answered 30/3, 2012 at 15:48 Comment(6)
May I ask about the downvotes? And why without comment?Souse
looks like a good question to me -- helpfulRomanist
@Lyn: It was closed as a consequence from a flamewar from people who wanted to point out that they disagree with me: meta.stackexchange.com/questions/127567/…Souse
It is really beyond me why would anyone think this question is not constructive. That someone with moderator privileges would think so - well, I'm at a loss for words. Sigh.Transmissible
I mean, this is a very basic thing that people often run into. There should be a canonical answer for this question on SO. It's a good question, at most it could be a duplicate, but since it was the first one that google gave me, I think this counts for something :)Transmissible
possible duplicate of How to make a .lib file when have a .dll file and a header fileNahshon
A
96

You can generate a DEF file using dumpbin /exports:

echo LIBRARY SQLITE3 > sqlite3.def
echo EXPORTS >> sqlite3.def
for /f "skip=19 tokens=4" %A in ('dumpbin /exports sqlite3.dll') do echo %A >> sqlite3.def

The librarian can use this DEF file to generate the LIB:

lib /def:sqlite3.def /out:sqlite3.lib /machine:x86

All of the filenames (sqlite3.dll, sqlite3.def, etc.) should be prepended with full paths.

Algolagnia answered 30/3, 2012 at 15:52 Comment(4)
this works perfectly. if your DLL is 64 bit, you may use /machine:x64 or /machine:x86-64 depending on your environment setup.Wideangle
Had to change %A in the last line to %%A (in both places)Despot
@Despot You need %%A instead of %A if you put it in a batch file instead of invoking directly from the command line.Constructive
To be safe, check the contents of the exports.txt file before running the loop. On an old dll the function names were the 3rd token, not the 4th.Uppsala
B
25

I know the topic is old, but I still couldn't find a script or batch file anywhere on the Internet to do this. So based on Dark Falcon's answer, I've made this script, which you can save as dll2lib.bat and run:

REM Usage: dll2lib [32|64] some-file.dll
REM
REM Generates some-file.lib from some-file.dll, making an intermediate
REM some-file.def from the results of dumpbin /exports some-file.dll.
REM Currently must run without path on DLL.
REM (Fix by removing path when of lib_name for LIBRARY line below?)
REM
REM Requires 'dumpbin' and 'lib' in PATH - run from VS developer prompt.
REM 
REM Script inspired by https://mcmap.net/q/238735/-how-to-generate-an-import-library-lib-file-from-a-dll
SETLOCAL
if "%1"=="32" (set machine=x86) else (set machine=x64)
set dll_file=%2
set dll_file_no_ext=%dll_file:~0,-4%
set exports_file=%dll_file_no_ext%-exports.txt
set def_file=%dll_file_no_ext%.def
set lib_file=%dll_file_no_ext%.lib
set lib_name=%dll_file_no_ext%

dumpbin /exports %dll_file% > %exports_file%

echo LIBRARY %lib_name% > %def_file%
echo EXPORTS >> %def_file%
for /f "skip=19 tokens=1,4" %%A in (%exports_file%) do if NOT "%%B" == "" (echo %%B @%%A >> %def_file%)

lib /def:%def_file% /out:%lib_file% /machine:%machine%

REM Clean up temporary intermediate files
del %exports_file% %def_file% %dll_file_no_ext%.exp

I'm sure the script can use improvement, but I hope it's useful.

Beecher answered 11/6, 2016 at 4:54 Comment(1)
Made some small improvements to allow passing a dll path.Cupro
L
13

This script creates *.lib from *.dll passed in %1:

@echo off

setlocal enabledelayedexpansion
for /f "tokens=1-4" %%1 in ('dumpbin /exports %1') do (
    set /a ordinal=%%1 2>nul
    set /a hint=0x%%2 2>nul
    set /a rva=0x%%3 2>nul
    if !ordinal! equ %%1 if !hint! equ 0x%%2 if !rva! equ 0x%%3 set exports=!exports! /export:%%4
)

for /f %%i in ("%1") do set dllpath=%%~dpni
start lib /out:%dllpath%.lib /machine:x86 /def: %exports%

You could name it implib.bat and run: implib.bat C:\folder\mydll.dll which produces C:\folder\mydll.lib

Layer answered 7/10, 2016 at 12:1 Comment(0)
A
12

For those who are on Linux and would like to create an appropriate import library (.lib) for a .dll produced by MinGW, there are again two steps involved:

  • Create .def file from .dll
  • Create .lib file from .def

Using MSVC, one could process the output of dumpbin /exports foo.dll. On Linux, you have to process the output of objdump -p (from binutils). The generated module definition file should look like:

LIBRARY foo.dll
EXPORTS
    your_symbol @1
     another_symbol @2
     ; ... et cetera

To convert the .def file to a .lib file, use llvm-dlltool (MinGW (binutils) dlltool is not suitable). Example invocation for a 64-bit library:

llvm-dlltool -m i386:x86-64 -d foo.def -l foo.lib

Explanation:

  • -m i386:x86-64: generate a 64-bit library. Use -m i386 if you need a 32-bit library instead.
  • -d foo.def: read exported symbols from file foo.def
  • -l foo.lib: write an import library to foo.lib
  • If a .def file does not contain a LIBRARY line, you have to append the -D foo.dll option (with just the filename and no directory prefix).

And here is a script to automate it:

# Given libxyz-1.dll, create import library libxyz-1.lib
make_implib() {
    local machine=$1 dll="$2" dllname deffile libfile

    dllname="${dll##*/}"
    deffile="${dll%.dll}.def"
    libfile="${dll%.dll}.lib"

    # Extract exports from the .edata section, writing results to the .def file.
    LC_ALL=C objdump -p "$dll" | awk -vdllname="$dllname" '
    /^\[Ordinal\/Name Pointer\] Table$/ {
        print "LIBRARY " dllname
        print "EXPORTS"
        p = 1; next
    }
    p && /^\t\[ *[0-9]+\] [a-zA-Z0-9_]+$/ {
        gsub("\\[|\\]", "");
        print "    " $2 " @" $1;
        ++p; next
    }
    p > 1 && /^$/ { exit }
    p { print "; unexpected objdump output:", $0; exit 1 }
    END { if (p < 2) { print "; cannot find export data section"; exit 1 } }
    ' > "$deffile"

    # Create .lib suitable for MSVC. Cannot use binutils dlltool as that creates
    # an import library (like the one found in lib/*.dll.a) that results in
    # broken executables. For example, assume executable foo.exe that uses fnA
    # (from liba.dll) and fnB (from libb.dll). Using link.exe (14.00.24215.1)
    # with these broken .lib files results in an import table that lists both
    # fnA and fnB under both liba.dll and libb.dll. Use of llvm-dlltool creates
    # the correct archive that uses Import Headers (like official MS tools).
    llvm-dlltool -m "$machine" -d "$deffile" -l "$libfile"
    rm -f "$deffile"
}

# Example invocations:
make_implib i386:x86_64 usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgnutls-30.dll
make_implib i386 usr/i686-w64-mingw32/sys-root/mingw/bin/libgnutls-30.dll

(Note that there is a bug in llvm-dlltool that produces a larger .lib file than necessary if the library name is longer than 15 characters. Aside from the size, it is fully functional though. This is fixed by https://reviews.llvm.org/D55860)

Tested with:

  • llvm-dlltool from LLVM 7.0.0-1 (Arch Linux)
  • objdump from binutils 2.31.1-3 (Arch Linux)
  • dlltool from binutils-mingw-w64-x86 64_2.30-7ubuntu1+8ubuntu1 (Ubuntu 18.04)
  • link.exe from Visual Studio 2015 14.00.24215.1 (Windows 7)
Arella answered 18/12, 2018 at 18:20 Comment(1)
I use "gendef foo.dll" to generate the .def file and "llvm-dlltool -m i386:x86-64 -d foo.def -D foo.dll -l foo.lib". Working fine for my linux-cross-build rust libraries.Biondo
N
6

Is it possible to autogenerate a MSVC import library (LIB-file) from a DLL? How?

In addition to Dark Falcon's answer, Microsoft has published procedures at How To Create Import Libraries Without .OBJs or Source.

Microsoft's first procedure is the same as Dark Falcon's. The second procedure is a little more cumbersome, but it shows how to do it with an object file using stubs. It works with different calling convention and classes.

Here's the second procedure from the KB:

  1. When "__declspec(dllimport)" is used in a prototype or declaration, change it to "__declspec(dllexport)."
  2. For functions that do not return a value, for C functions in C source, and for C functions in C++ source code (used with the 'extern "C"' construct), replace the semicolon that terminates the function prototype with a matched pair of curly braces ("{}").
  3. For C++ functions (global or member) that return a value, you must create a dummy body for the function, and return a dummy value of the proper type. (Not having a return statement in the function is illegal.) This goes for class member functions, as well. Keep in mind that the purpose of this procedure is to trick the LIB utility into generating the correct import library, so these dummy bodies have no effect.
  4. For C++ classes, you can stub out the member functions by using the prototypes in the class declaration, as long as you disable function inlining when you compile.
  5. Function arguments are usually just specified by type in a header file. For example, Geta(int). A dummy argument identifier must be specified when adding the dummy function body Geta(int x). Otherwise the error C2055 is generated.
Nahshon answered 17/11, 2014 at 6:44 Comment(1)
could you pls throw some lights here, what does the page mean by "For _cdecl functions, the symbol appears just as it would when used in the calling program. Just place this symbol in the EXPORTS section of the .DEF file."?Williford

© 2022 - 2024 — McMap. All rights reserved.