C++ 创建 DLL 时导出所有符号
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/225432/
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
Export all symbols when creating a DLL
提问by Jazz
With VS2005, I want to create a DLL and automatically export all symbols without adding __declspec(dllexport) everywhere and without hand-creating .def files. Is threre a way to do this?
使用 VS2005,我想创建一个 DLL 并自动导出所有符号,而无需在任何地方添加 __declspec(dllexport) 并且无需手动创建 .def 文件。有没有办法做到这一点?
采纳答案by Andrew Stein
It can be done...
可以办到...
The way we do it here is to use the /DEF option of the linker to pass a "module definition file"containing a list of our exports. I see from your question that you know about these files. However, we do not do it by hand. The list of exports itself is created by the dumpbin/LINKERMEMBER command, and manipulating the output via a simple script to the format of a module definition file.
我们在这里的做法是使用链接器的 /DEF 选项来传递一个包含导出列表的“模块定义文件”。我从您的问题中了解到您了解这些文件。但是,我们不是手工完成的。导出列表本身由dumpbin/LINKERMEMBER 命令创建,并通过一个简单的脚本将输出处理为模块定义文件的格式。
It is a lot of work to setup, but it allows us to compile code created without dllexport declarations for Unix on Windows.
设置工作量很大,但它允许我们编译在 Windows 上为 Unix 没有 dllexport 声明的代码。
回答by Maks
Short answer
简答
You can do it with help of the new version of the CMake (any version cmake-3.3.20150721-g9cd2f-win32-x86.exe or higher).
您可以借助新版本的 CMake(任何版本 cmake-3.3.20150721-g9cd2f-win32-x86.exe 或更高版本)来完成。
Currently it's in the dev branch. Later, the feature will be added in the release version of the cmake-3.4.
目前它在开发分支中。稍后,该功能将添加到 cmake-3.4 的发布版本中。
Link to the cmake dev:
链接到 cmake 开发:
Link to an article which describe the technic:
链接到描述技术的文章:
Create dlls on Windows without declspec() using new CMake export all feature
使用新的 CMake 导出所有功能在不使用 declspec() 的情况下在 Windows 上创建 dll
Link to an example project:
链接到示例项目:
cmake_windows_export_all_symbols
cmake_windows_export_all_symbols
Long answer
长答案
Caution:All information below is related to the MSVC compiler or Visual Studio.
注意:以下所有信息均与 MSVC 编译器或 Visual Studio 相关。
If you use other compilers like gcc on Linux or MinGW gcc compiler on Windows you don't have linking errors due to not exported symbols, because gcc compiler export all symbols in a dynamic library (dll) by default instead of MSVC or Intel windows compilers.
如果您在 Linux 上使用其他编译器,例如 Linux 上的 gcc 或 Windows 上的 MinGW gcc 编译器,您不会因未导出符号而出现链接错误,因为 gcc 编译器默认导出动态库 (dll) 中的所有符号,而不是 MSVC 或 Intel Windows 编译器.
In windows you have to explicitly export symbol from a dll.
在 Windows 中,您必须明确地从 dll 导出符号。
More info about this is provided by links:
链接提供了有关此的更多信息:
HowTo: Export C++ classes from a DLL
So if you want to export all symbols from dll with MSVC (Visual Studio compiler) you have two options:
因此,如果您想使用 MSVC(Visual Studio 编译器)从 dll 导出所有符号,您有两个选择:
- Use the keyword __declspec(dllexport) in the class/function's definition.
- Create a module definition (.def) file and use the .def file when building the DLL.
- 在类/函数的定义中使用关键字 __declspec(dllexport)。
- 创建模块定义 (.def) 文件并在构建 DLL 时使用 .def 文件。
1. Use the keyword __declspec(dllexport) in the class/function's definition
1. 在类/函数的定义中使用关键字 __declspec(dllexport)
1.1. Add "__declspec(dllexport) / __declspec(dllimport)" macros to a class or method you want to use. So if you want to export all classes you should add this macros to all of them
1.1. 将“__declspec(dllexport) / __declspec(dllimport)”宏添加到要使用的类或方法。所以如果你想导出所有的类,你应该把这个宏添加到所有的类中
More info about this is provided by link:
链接提供了有关此的更多信息:
Exporting from a DLL Using __declspec(dllexport)
使用 __declspec(dllexport) 从 DLL 导出
Example of usage (replace "Project" by real project name):
使用示例(用真实项目名称替换“Project”):
// ProjectExport.h
#ifndef __PROJECT_EXPORT_H
#define __PROJECT_EXPORT_H
#ifdef USEPROJECTLIBRARY
#ifdef PROJECTLIBRARY_EXPORTS
#define PROJECTAPI __declspec(dllexport)
#else
#define PROJECTAPI __declspec(dllimport)
#endif
#else
#define PROJECTAPI
#endif
#endif
Then add "PROJECTAPI" to all classes. Define "USEPROJECTLIBRARY" only if you want export/import symbols from dll. Define "PROJECTLIBRARY_EXPORTS" for the dll.
然后将“PROJECTAPI”添加到所有类。仅当您想从 dll 导出/导入符号时才定义“USEPROJECTLIBRARY”。为 dll 定义“PROJECTLIBRARY_EXPORTS”。
Example of class export:
类导出示例:
#include "ProjectExport.h"
namespace hello {
class PROJECTAPI Hello {}
}
Example of function export:
函数导出示例:
#include "ProjectExport.h"
PROJECTAPI void HelloWorld();
Caution:don't forget to include "ProjectExport.h" file.
注意:不要忘记包含“ProjectExport.h”文件。
1.2. Export as C functions. If you use C++ compiler for compilation code is written on C, you could add extern "C" in front of a function to eliminate name mangling
1.2. 导出为 C 函数。如果您使用 C++ 编译器将编译代码写在 C 上,则可以在函数前添加 extern "C" 以消除名称修饰
More info about C++ name mangling is provided by link:
链接提供了有关 C++ 名称修改的更多信息:
Example of usage:
用法示例:
extern "C" __declspec(dllexport) void HelloWorld();
More info about this is provided by link:
链接提供了有关此的更多信息:
Exporting C++ Functions for Use in C-Language Executables
2. Create a module definition (.def) file and use the .def file when building the DLL
2.创建一个模块定义(.def)文件并在构建DLL时使用.def文件
More info about this is provided by link:
链接提供了有关此的更多信息:
Exporting from a DLL Using DEF Files
Further I describe three approach about how to create .def file.
我进一步描述了关于如何创建 .def 文件的三种方法。
2.1. Export C functions
2.1. 导出 C 函数
In this case you could simple add function declarations in the .def file by hand.
在这种情况下,您可以简单地手动在 .def 文件中添加函数声明。
Example of usage:
用法示例:
extern "C" void HelloWorld();
Example of .def file (__cdecl naming convention):
.def 文件示例(__cdecl 命名约定):
EXPORTS
_HelloWorld
2.2. Export symbols from static library
2.2. 从静态库导出符号
I tried approach suggested by "user72260".
我尝试了“user72260”建议的方法。
He said:
他说:
- Firstly, you could create static library.
- Then use "dumpbin /LINKERMEMBER" to export all symbols from static library.
- Parse the output.
- Put all results in a .def file.
- Create dll with the .def file.
- 首先,您可以创建静态库。
- 然后使用“dumpbin /LINKERMEMBER”从静态库中导出所有符号。
- 解析输出。
- 将所有结果放在一个 .def 文件中。
- 使用 .def 文件创建 dll。
I used this approach, but it's not very convinient to always create two builds (one as a static and the other as a dynamic library). However, I have to admit, this approach really works.
我使用了这种方法,但总是创建两个构建(一个作为静态库,另一个作为动态库)并不是很方便。但是,我不得不承认,这种方法确实有效。
2.3. Export symbols from .obj files or with help of the CMake
2.3. 从 .obj 文件或在 CMake 的帮助下导出符号
2.3.1. With CMake usage
2.3.1. 使用 CMake
Important notice:You don't need any export macros to a classes or functions!
重要提示:您不需要任何导出宏到类或函数!
Important notice:You can't use /GL (Whole Program Optimization) when use this approach!
重要提示:使用此方法时不能使用 /GL(Whole Program Optimization)!
- Create CMake project based on the "CMakeLists.txt" file.
- Add the following line to the "CMakeLists.txt" file: set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
- Then create Visual Studio project with help of "CMake (cmake-gui)".
- Compile the project.
- 根据“CMakeLists.txt”文件创建 CMake 项目。
- 将以下行添加到“CMakeLists.txt”文件中:set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
- 然后在“CMake (cmake-gui)”的帮助下创建 Visual Studio 项目。
- 编译项目。
Example of usage:
用法示例:
Root folder
根文件夹
CMakeLists.txt (Root folder)
CMakeLists.txt(根文件夹)
cmake_minimum_required(VERSION 2.6)
project(cmake_export_all)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(dir ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${dir}/bin")
set(SOURCE_EXE main.cpp)
include_directories(foo)
add_executable(main ${SOURCE_EXE})
add_subdirectory(foo)
target_link_libraries(main foo)
main.cpp (Root folder)
main.cpp(根文件夹)
#include "foo.h"
int main() {
HelloWorld();
return 0;
}
Foo folder (Root folder / Foo folder)
Foo 文件夹(根文件夹/Foo 文件夹)
CMakeLists.txt (Foo folder)
CMakeLists.txt(Foo 文件夹)
project(foo)
set(SOURCE_LIB foo.cpp)
add_library(foo SHARED ${SOURCE_LIB})
foo.h (Foo folder)
foo.h(Foo 文件夹)
void HelloWorld();
foo.cpp (Foo folder)
foo.cpp(Foo 文件夹)
#include <iostream>
void HelloWorld() {
std::cout << "Hello World!" << std::endl;
}
Link to the example project again:
再次链接到示例项目:
cmake_windows_export_all_symbols
cmake_windows_export_all_symbols
CMake uses the different from "2.2. Export symbols from static library" approach.
CMake 使用不同于“2.2. 从静态库中导出符号”的方法。
It does the following:
它执行以下操作:
1) Create "objects.txt" file in the build directory with information of .obj files are used in a dll.
1) 在 build 目录中创建“objects.txt”文件,其中 .obj 文件的信息用于 dll。
2) Compile the dll, that is create .obj files.
2) 编译dll,即创建.obj 文件。
3) Based on "objects.txt" file information extract all symbols from .obj file.
3) 根据“objects.txt”文件信息从.obj 文件中提取所有符号。
Example of usage:
用法示例:
DUMPBIN /SYMBOLS example.obj > log.txt
More info about this is provided by link:
链接提供了有关此的更多信息:
4) Parse extracted from .obj file information.
4) 从 .obj 文件信息中提取的解析。
In my opinion I would use calling convection, for example "__cdecl/__fastcall", "SECTx/UNDEF" symbol field (the third column), "External/Static" symbol field (the fifth column), "??", "?" information for parsing an .obj files.
在我看来,我会使用调用对流,例如“__cdecl/__fastcall”、“SECTx/UNDEF”符号字段(第三列)、“外部/静态”符号字段(第五列)、“??”、“? ” 用于解析 .obj 文件的信息。
I don't know how exactly CMake parse an .obj file. However, CMake is open source, so you could find out if it's interested for you.
我不知道 CMake 是如何解析 .obj 文件的。但是,CMake 是开源的,因此您可以了解它是否对您感兴趣。
Link to the CMake project:
链接到 CMake 项目:
5) Put all exported symbols in a .def file.
5) 将所有导出的符号放在一个 .def 文件中。
6) Link a dll with usage of a .def created file.
6) 使用 .def 创建的文件链接 dll。
Steps 4)-5), that is parse .obj files and create a .def file before linking and using the .def file CMake does with help of "Pre-Link event". While "Pre-Link event" fires you could call any program you want. So in case of "CMake usage" "Pre-Link event" call the CMake with the following information about where to put the .def file and where the "objects.txt" file and with argument "-E __create_def". You could check this information by creating CMake Visusal Studio project with "set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" and then check the ".vcxproj" project file for dll.
步骤 4)-5),即解析 .obj 文件并在链接和使用 .def 文件之前创建一个 .def 文件 CMake 在“预链接事件”的帮助下所做的。当“预链接事件”触发时,您可以调用您想要的任何程序。因此,在“CMake 使用”“预链接事件”的情况下,使用以下关于放置 .def 文件的位置和“objects.txt”文件的位置以及参数“-E __create_def”的信息调用 CMake。您可以通过使用“set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)”创建 CMake Visusal Studio 项目来检查此信息,然后检查“.vcxproj”项目文件中的 dll。
If you try to compile a project without "set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" or with "set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)" you will get linking errors, due to the fact that symbols are not exported from a dll.
如果您尝试在没有“set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)”或“set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)”的情况下编译项目,则会出现链接错误,因为符号不是从 dll 导出的。
More info about this is provided by link:
链接提供了有关此的更多信息:
Understanding Custom Build Steps and Build Events
2.3.2. Without CMake usage
2.3.2. 不使用 CMake
You simple could create a small program for parsing .obj file by youself without CMake usege. Hovewer, I have to admit that CMake is very usefull program especially for cross-platform development.
您可以简单地创建一个小程序来自己解析 .obj 文件,而无需使用 CMake。然而,我不得不承认 CMake 是非常有用的程序,尤其是对于跨平台开发。
回答by user72260
I've written a small program to parse the output of "dumpbin /linkermember" on the .lib file. I have upwards of 8,000 function references to export from one DLL.
我编写了一个小程序来解析 .lib 文件中“dumpbin /linkermember”的输出。我有超过 8,000 个函数引用要从一个 DLL 导出。
The problem with doing it on a DLL is that you have to link the DLL without the exported definitions once to create the .lib file, then generate the .def which means you now have to relink the DLL again with the .def file to actually have the references exported.
在 DLL 上执行此操作的问题在于,您必须在没有导出定义的情况下链接 DLL 一次以创建 .lib 文件,然后生成 .def,这意味着您现在必须再次将 DLL 与 .def 文件重新链接到实际导出引用。
Working with static libraries is easier. Compile all your sources into static libs, run dumbin, generate a .def with your little program, then link the libs together into a DLL now that the export names are available.
使用静态库更容易。将所有源代码编译为静态库,运行 dubbin,使用您的小程序生成一个 .def,然后将这些库链接到一个 DLL 中,因为导出名称可用。
Unfortunately my company won't allow me to show you the source. The work involved is recognizing which "public symbols" in the dump output are not needed in your def file. You have to throw away a lot of those references, NULL_IMPORT_DESCRIPTOR, NULL_THUNK_DATA, __imp*, etc.
不幸的是,我的公司不允许我向您展示来源。所涉及的工作是识别转储输出中的哪些“公共符号”在您的 def 文件中是不需要的。你必须扔掉很多这些引用,NULL_IMPORT_DESCRIPTOR、NULL_THUNK_DATA、__imp* 等。
回答by jww
I want to create a DLL and automatically export all symbols without adding __declspec(dllexport) everywhere and without hand-creating .def files. Is threre a way to do this?
我想创建一个 DLL 并自动导出所有符号,而无需在任何地方添加 __declspec(dllexport) 并且无需手动创建 .def 文件。有没有办法做到这一点?
This is a late answer, but it provides the details for Maks's answer in Section (2). It also avoids scripts and uses a C++ program called dump2def
. The source code for dump2def
is below.
这是一个迟到的答案,但它在第 (2) 节中提供了 Maks 答案的详细信息。它还避免使用脚本并使用名为dump2def
. 的源代码dump2def
如下。
Finally, the steps below assume you are working from a Visual Studio Developer Prompt, which is a Windows Terminal where vcvarsall.bat
has been run. You need to ensure the build tools like cl.exe
, lib.exe
, link.exe
and nmake.exe
are on-path.
最后,以下步骤假设您正在使用 Visual Studio Developer Prompt,这是一个vcvarsall.bat
已运行的 Windows 终端。您需要确保这样的构建工具cl.exe
,lib.exe
,link.exe
和nmake.exe
是在路径上。
More info about this is provided by link:
链接提供了有关此的更多信息:
The instruction below use:
下面的指令使用:
static.lib
- static library archive (*.a file on Linux)dynamic.dll
- dynamic library (*.so file on Linux)import.lib
- dynamic library (import library on Windows)
static.lib
- 静态库存档(Linux 上的 *.a 文件)dynamic.dll
- 动态库(Linux 上的 *.so 文件)import.lib
- 动态库(Windows 上的导入库)
Also note that though you are exporting everything from the DLL, clients still must use declspec(dllimport)
on all symbols (classes, functions and data) that they use. Also see on MSDN.
另请注意,尽管您从 DLL 中导出所有内容,但客户端仍必须declspec(dllimport)
在它们使用的所有符号(类、函数和数据)上使用。另见 MSDN。
First, take your objects and create a static archive:
首先,获取您的对象并创建一个静态存档:
AR = lib.exe
ARFLAGS = /nologo
CXX_SRCS = a.cpp b.cpp c.cpp ...
LIB_OBJS = a.obj b.obj c.obj ...
static.lib: $(LIB_OBJS)
$(AR) $(ARFLAGS) $(LIB_OBJS) /out:$@
Second, run dumpbin.exe /LINKERMEMEBER
on the archive to create a *.dump
file:
其次,dumpbin.exe /LINKERMEMEBER
在存档上运行以创建*.dump
文件:
dynamic.dump:
dumpbin /LINKERMEMBER static.lib > dynamic.dump
Third, run dump2def.exe
on the *.dump
file to produce the *.def
file. The source code for dump2def.exe
is below.
第三,dump2def.exe
在*.dump
文件上运行以生成*.def
文件。的源代码dump2def.exe
如下。
dynamic.def: static.lib dynamic.dump
dump2def.exe dynamic.dump dynamic.def
Fourth, build the DLL:
四、构建DLL:
LD = link.exe
LDFLAGS = /OPT:REF /MACHINE:X64
LDLIBS = kernel32.lib
dynamic.dll: $(LIB_OBJS) dynamic.def
$(LD) $(LDFLAGS) /DLL /DEF:dynamic.def /IGNORE:4102 $(LIB_OBJS) $(LDLIBS) /out:$@
/IGNORE:4102
is used to avoid this warning. It is expected in this case:
/IGNORE:4102
用于避免此警告。在这种情况下预计:
dynamic.def : warning LNK4102: export of deleting destructor 'public: virtual v
oid * __ptr64 __cdecl std::exception::`scalar deleting destructor'(unsigned int)
__ptr64'; image may not run correctly
When the dynamic.dll
recipe is invoked, it creates a dynamic.lib
import file and dynamic.exp
file, too:
当dynamic.dll
配方被调用时,它也会创建一个dynamic.lib
导入文件和dynamic.exp
文件:
> cls && nmake /f test.nmake dynamic.dll
...
Creating library dynamic.lib and object dynamic.exp
And:
和:
C:\Users\Test\testdll>dir *.lib *.dll *.def *.exp
Volume in drive C is Windows
Volume Serial Number is CC36-23BE
Directory of C:\Users\Test\testdll
01/06/2019 08:33 PM 71,501,578 static.lib
01/06/2019 08:33 PM 11,532,052 dynamic.lib
Directory of C:\Users\Test\testdll
01/06/2019 08:35 PM 5,143,552 dynamic.dll
Directory of C:\Users\Test\testdll
01/06/2019 08:33 PM 1,923,070 dynamic.def
Directory of C:\Users\Test\testdll
01/06/2019 08:35 PM 6,937,789 dynamic.exp
5 File(s) 97,038,041 bytes
0 Dir(s) 139,871,186,944 bytes free
Gluing it together here is what the Nmake makefile looks like. It is part of a real Nmake file:
在这里将它粘合在一起就是 Nmake 生成文件的样子。它是真正的 Nmake 文件的一部分:
all: test.exe
test.exe: pch.pch static.lib $(TEST_OBJS)
$(LD) $(LDFLAGS) $(TEST_OBJS) static.lib $(LDLIBS) /out:$@
static.lib: $(LIB_OBJS)
$(AR) $(ARFLAGS) $(LIB_OBJS) /out:$@
dynamic.map:
$(LD) $(LDFLAGS) /DLL /MAP /MAPINFO:EXPORTS $(LIB_OBJS) $(LDLIBS) /out:dynamic.dll
dynamic.dump:
dumpbin.exe /LINKERMEMBER static.lib /OUT:dynamic.dump
dynamic.def: static.lib dynamic.dump
dump2def.exe dynamic.dump
dynamic.dll: $(LIB_OBJS) dynamic.def
$(LD) $(LDFLAGS) /DLL /DEF:dynamic.def /IGNORE:4102 $(LIB_OBJS) $(LDLIBS) /out:$@
clean:
$(RM) /F /Q pch.pch $(LIB_OBJS) pch.obj static.lib $(TEST_OBJS) test.exe *.pdb
And here is the source code for dump2def.exe
:
这是源代码dump2def.exe
:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <set>
typedef std::set<std::string> SymbolMap;
void PrintHelpAndExit(int code)
{
std::cout << "dump2def - create a module definitions file from a dumpbin file" << std::endl;
std::cout << " Written and placed in public domain by Jeffrey Walton" << std::endl;
std::cout << std::endl;
std::cout << "Usage: " << std::endl;
std::cout << " dump2def <infile>" << std::endl;
std::cout << " - Create a def file from <infile> and write it to a file with" << std::endl;
std::cout << " the same name as <infile> but using the .def extension" << std::endl;
std::cout << " dump2def <infile> <outfile>" << std::endl;
std::cout << " - Create a def file from <infile> and write it to <outfile>" << std::endl;
std::exit(code);
}
int main(int argc, char* argv[])
{
// ******************** Handle Options ******************** //
// Convenience item
std::vector<std::string> opts;
for (size_t i=0; i<argc; ++i)
opts.push_back(argv[i]);
// Look for help
std::string opt = opts.size() < 3 ? "" : opts[1].substr(0,2);
if (opt == "/h" || opt == "-h" || opt == "/?" || opt == "-?")
PrintHelpAndExit(0);
// Add <outfile> as needed
if (opts.size() == 2)
{
std::string outfile = opts[1];
std::string::size_type pos = outfile.length() < 5 ? std::string::npos : outfile.length() - 5;
if (pos == std::string::npos || outfile.substr(pos) != ".dump")
PrintHelpAndExit(1);
outfile.replace(pos, 5, ".def");
opts.push_back(outfile);
}
// Check or exit
if (opts.size() != 3)
PrintHelpAndExit(1);
// ******************** Read MAP file ******************** //
SymbolMap symbols;
try
{
std::ifstream infile(opts[1].c_str());
std::string::size_type pos;
std::string line;
// Find start of the symbol table
while (std::getline(infile, line))
{
pos = line.find("public symbols");
if (pos == std::string::npos) { continue; }
// Eat the whitespace after the table heading
infile >> std::ws;
break;
}
while (std::getline(infile, line))
{
// End of table
if (line.empty()) { break; }
std::istringstream iss(line);
std::string address, symbol;
iss >> address >> symbol;
symbols.insert(symbol);
}
}
catch (const std::exception& ex)
{
std::cerr << "Unexpected exception:" << std::endl;
std::cerr << ex.what() << std::endl;
std::cerr << std::endl;
PrintHelpAndExit(1);
}
// ******************** Write DEF file ******************** //
try
{
std::ofstream outfile(opts[2].c_str());
// Library name, cryptopp.dll
std::string name = opts[2];
std::string::size_type pos = name.find_last_of(".");
if (pos != std::string::npos)
name.erase(pos);
outfile << "LIBRARY " << name << std::endl;
outfile << "DESCRIPTION \"Crypto++ Library\"" << std::endl;
outfile << "EXPORTS" << std::endl;
outfile << std::endl;
outfile << "\t;; " << symbols.size() << " symbols" << std::endl;
// Symbols from our object files
SymbolMap::const_iterator it = symbols.begin();
for ( ; it != symbols.end(); ++it)
outfile << "\t" << *it << std::endl;
}
catch (const std::exception& ex)
{
std::cerr << "Unexpected exception:" << std::endl;
std::cerr << ex.what() << std::endl;
std::cerr << std::endl;
PrintHelpAndExit(1);
}
return 0;
}
回答by Sergey
Thanks @Maks for the detailed answer.
感谢@Maks 的详细回答。
Below is an example of what I used in Pre-Link event to generate def file from obj. I hope it will be helpful for someone.
下面是我在 Pre-Link 事件中使用的从 obj 生成 def 文件的示例。我希望它会对某人有所帮助。
dumpbin /SYMBOLS $(Platform)$(Configuration)\mdb.obj | findstr /R "().*External.*mdb_.*" > $(Platform)$(Configuration)\mdb_symbols
(echo EXPORTS & for /F "usebackq tokens=2 delims==|" %%E in (`type $(Platform)$(Configuration)\mdb_symbols`) do @echo %%E) > $(Platform)$(Configuration)\lmdb.def
Basically I just took one of objects (mdb.obj) and grepped mdb_* functions. Then parsed output to keep just names taking into account amount of spaces for indentation (one after splitting into tokens and another in echo. I don't know if it's matter though).
基本上我只是拿了一个对象 (mdb.obj) 和 grepped mdb_* 函数。然后解析输出以仅保留名称,同时考虑缩进的空间量(一个在拆分为标记后,另一个在 echo 中。我不知道这是否重要)。
Real world script probably will kind of more complex though.
不过,现实世界的脚本可能会更复杂一些。
回答by Alexander Samoylov
Perhaps somebody finds useful my Python script for converting .dump to .def.
也许有人发现我的 Python 脚本将 .dump 转换为 .def 很有用。
import sys, os
functions = []
startPoint = False
# Exclude standard API like sprintf to avoid multiple definition link error
excluded_functions = [ 'sprintf', 'snprintf', 'sscanf', 'fprintf' ]
if len(sys.argv) < 2:
print('Usage: %s <Input .dump file> <Output .def file>.' % sys.argv[0])
print('Example: %s myStaticLib.dump exports.def' % sys.argv[0])
sys.exit(1)
print('%s: Processing %s to %s' % (sys.argv[0], sys.argv[1], sys.argv[2]))
fin = open(sys.argv[1], 'r')
lines = fin.readlines()
fin.close()
# Reading
for l in lines:
l_str = l.strip()
if (startPoint == True) and (l_str == 'Summary'): # end point
break
if (startPoint == False) and ("public symbols" in l_str):
startPoint = True
continue
if (startPoint == True) and l_str is not '':
funcName = l_str.split(' ')[-1]
if funcName not in excluded_functions:
functions.append(" " + funcName)
# Writing
fout = open(sys.argv[2], 'w')
fout.write('EXPORTS\n')
for f in functions:
fout.write('%s\n' % f)
fout.close()
With this script you can get the .def file for your .lib in two steps:
使用此脚本,您可以分两步获取 .lib 的 .def 文件:
dumpbin /LINKERMEMBER:1 myStaticLib.lib > myExports.dump
python dump2def.py myExports.dump myExports.def
回答by Adam Mitz
No, you will need a macro that resolves to __declspec(dllexport)
when it's included by the .cpp file that implements the exported functions, and resolves to __declspec(dllimport)
otherwise.
不,您将需要一个宏,该宏__declspec(dllexport)
在实现导出函数的 .cpp 文件中包含时解析为,__declspec(dllimport)
否则解析为。