windows 如何从 DLL 生成导入库(LIB 文件)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9946322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to generate an import library (LIB-file) from a DLL?
提问by Albert
Is it possible to autogenerate a MSVC import library (LIB-file) from a DLL? How?
是否可以从 DLL 自动生成 MSVC 导入库(LIB 文件)?如何?
回答by Dark Falcon
You can generate a DEF file using dumpbin /exports:
您可以使用 dumpbin /exports 生成 DEF 文件:
dumpbin /exports sqlite3.dll > exports.txt
echo LIBRARY SQLITE3 > sqlite3.def
echo EXPORTS >> sqlite3.def
for /f "skip=19 tokens=4" %A in (exports.txt) do echo %A >> sqlite3.def
The librarian can use this DEF file to generate the LIB:
图书管理员可以使用这个 DEF 文件来生成 LIB:
lib /def:sqlite3.def /out:sqlite3.lib /machine:x86
All of the filenames (exports.txt
, sqlite3.dll
, sqlite3.def
, etc.) should be prepended with full paths.
所有文件名(exports.txt
、sqlite3.dll
、sqlite3.def
等)都应该在前面加上完整路径。
回答by Conrad Poelman
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:
我知道这个主题很旧,但我仍然无法在 Internet 上的任何地方找到脚本或批处理文件来执行此操作。因此,基于 Dark Falcon 的回答,我制作了这个脚本,您可以将其另存为 dll2lib.bat 并运行:
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 http://stackoverflow.com/questions/9946322/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.
我确信脚本可以使用改进,但我希望它有用。
回答by vyshulga
This script creates *.lib from *.dll passed in %1:
此脚本从 %1 中传递的 *.dll 创建 *.lib:
@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
您可以将其命名为 implib.bat 并运行:implib.bat C:\folder\mydll.dll
它生成 C:\folder\mydll.lib
回答by Lekensteyn
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:
对于那些在 Linux 上并且想要为 MinGW 生成的 .dll 创建适当的导入库 (.lib) 的人,再次涉及两个步骤:
- Create .def file from .dll
- Create .lib file from .def
- 从 .dll 创建 .def 文件
- 从 .def 创建 .lib 文件
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 definitionfile should look like:
使用 MSVC,可以处理dumpbin /exports foo.dll
. 在 Linux 上,您必须处理objdump -p
(来自 binutils)的输出。生成的模块定义文件应如下所示:
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 notsuitable). Example invocation for a 64-bit library:
到DEF文件转换成的.lib文件,使用LLVM-dlltool(MinGW的(binutils的)dlltool
是不适合的)。64 位库的示例调用:
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 filefoo.def
-l foo.lib
: write an import library tofoo.lib
- If a
.def
file does not contain aLIBRARY
line, you have to append the-D foo.dll
option (with justthe filename and no directory prefix).
-m i386:x86-64
: 生成 64 位库。使用-m i386
,如果你需要一个32位的库,而不是。-d foo.def
: 从文件中读取导出的符号foo.def
-l foo.lib
: 写一个导入库到foo.lib
- 如果
.def
文件不包含LIBRARY
行,则必须附加该-D foo.dll
选项(仅包含文件名而无目录前缀)。
And here is a script to automate it:
这是一个自动化的脚本:
# Given libxyz-1.dll, create import library libxyz-1.lib
make_implib() {
local machine= dll="" 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 " " " @" ;
++p; next
}
p > 1 && /^$/ { exit }
p { print "; unexpected objdump output:", ##代码##; 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)
(请注意,如果库名超过 15 个字符,llvm-dlltool 中存在一个错误,该错误会生成比所需更大的 .lib 文件。除了大小之外,它还是功能齐全的。这是由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)
- 来自 LLVM 7.0.0-1 (Arch Linux) 的 llvm-dlltool
- 来自 binutils 2.31.1-3 (Arch Linux) 的 objdump
- dlltool 来自 binutils-mingw-w64-x86 64_2.30-7ubuntu1+8ubuntu1 (Ubuntu 18.04)
- 来自 Visual Studio 2015 14.00.24215.1 (Windows 7) 的 link.exe
回答by jww
Is it possible to autogenerate a MSVC import library (LIB-file) from a DLL? How?
是否可以从 DLL 自动生成 MSVC 导入库(LIB 文件)?如何?
In addition to Dark Falcon's answer, Microsoft has published procedures at How To Create Import Libraries Without .OBJs or Source.
除了 Dark Falcon 的回答之外,微软还在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.
Microsoft 的第一个程序与 Dark Falcon 相同。第二个过程稍微麻烦一些,但它显示了如何使用存根对目标文件进行操作。它适用于不同的调用约定和类。
Here's the second procedure from the KB:
这是知识库中的第二个过程:
- When "__declspec(dllimport)" is used in a prototype or declaration, change it to "__declspec(dllexport)."
- 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 ("{}").
- 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.
- 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.
- 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.
- 在原型或声明中使用“__declspec(dllimport)”时,将其更改为“__declspec(dllexport)”。
- 对于不返回值的函数、C 源代码中的 C 函数以及 C++ 源代码中的 C 函数(与 'extern "C"' 构造一起使用),将终止函数原型的分号替换为匹配的大括号 (”{}”)。
- 对于返回值的 C++ 函数(全局或成员),您必须为该函数创建一个虚拟体,并返回一个正确类型的虚拟值。(在函数中没有 return 语句是非法的。)这也适用于类成员函数。请记住,此过程的目的是诱使 LIB 实用程序生成正确的导入库,因此这些虚拟实体不起作用。
- 对于 C++ 类,只要在编译时禁用函数内联,就可以通过使用类声明中的原型来删除成员函数。
- 函数参数通常仅由头文件中的类型指定。例如,Geta(int)。添加虚拟函数体 Geta(int x) 时,必须指定虚拟参数标识符。否则会生成错误 C2055。