使用VS2005,我想创建一个DLL并自动导出所有符号,而无需在任何地方添加__declspec(dllexport),也无需手工创建.def文件.这是一种方法吗?
可以办到...
我们这样做的方法是使用链接器的/ DEF选项传递包含导出列表的"模块定义文件".我从你的问题中看到你知道这些文件.但是,我们不是手工完成的.导出列表本身由dumpbin/LINKERMEMBER命令创建,并通过简单脚本将输出操作为模块定义文件的格式.
设置需要做很多工作,但它允许我们编译在Windows上没有针对Unix的dllexport声明创建的代码.
你可以借助新版本的CMake(任何版本的cmake-3.3.20150721-g9cd2f-win32-x86.exe或更高版本)来实现.
目前它在dev分支中.稍后,该功能将添加到cmake-3.4的发行版中.
链接到cmake dev:
cmake_dev
链接到描述技术的文章:
使用新的CMake export all功能在没有declspec()的情况下在Windows上创建dll
链接到示例项目:
cmake_windows_export_all_symbols
警告: 以下所有信息都与MSVC编译器或Visual Studio有关.
如果您在Linux上使用其他编译器(如Linux上的gcc或Windows上的MinGW gcc编译器),则由于未导出符号而导致链接错误,因为gcc编译器默认导出动态库(dll)中的所有符号而不是MSVC或Intel Windows编译器.
在Windows中,您必须从dll显式导出符号.
有关这个的更多信息,请参见链接:
从DLL导出
HowTo:从DLL导出C++类
因此,如果要使用MSVC(Visual Studio编译器)从dll导出所有符号,则有两个选项:
在类/函数的定义中使用关键字__declspec(dllexport).
创建模块定义(.def)文件并在构建DLL时使用.def文件.
1.在类/函数的定义中使用关键字__declspec(dllexport)
1.1.将"__declspec(dllexport)/ __declspec(dllimport)"宏添加到要使用的类或方法中.因此,如果要导出所有类,则应将此宏添加到所有类中
有关此内容的更多信息,请访问:
使用__declspec(dllexport)从DLL导出
用法示例(用实际项目名称替换"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
然后将"PROJECTAPI"添加到所有类.仅当您需要来自dll的导出/导入符号时才定义"USEPROJECTLIBRARY".为dll定义"PROJECTLIBRARY_EXPORTS".
类导出示例:
#include "ProjectExport.h" namespace hello { class PROJECTAPI Hello {} }
功能导出示例:
#include "ProjectExport.h" PROJECTAPI void HelloWorld();
警告:不要忘记包含"ProjectExport.h"文件.
1.2.导出为C函数.如果使用C++编译器编译代码是用C语言编写的,你可以在函数前添加extern"C"以消除名称错误
有关C++ name mangling的更多信息,请链接:
名称装饰
用法示例:
extern "C" __declspec(dllexport) void HelloWorld();
有关此内容的更多信息,请访问:
导出用于C语言可执行文件的C++函数
2.创建模块定义(.def)文件,并在构建DLL时使用.def文件
有关此内容的更多信息,请访问:
使用DEF文件从DLL导出
此外,我描述了有关如何创建.def文件的三种方法.
2.1.导出C函数
在这种情况下,您可以手动在.def文件中简单地添加函数声明.
用法示例:
extern "C" void HelloWorld();
.def文件的示例(__cdecl命名约定):
EXPORTS _HelloWorld
2.2.从静态库导出符号
我尝试了"user72260"建议的方法.
他说:
首先,您可以创建静态库.
然后使用"dumpbin/LINKERMEMBER"从静态库中导出所有符号.
解析输出.
将所有结果放在.def文件中.
使用.def文件创建dll.
我使用这种方法,但总是创建两个构建(一个作为静态,另一个作为动态库)并不是很方便.但是,我必须承认,这种方法确实有效.
2.3.从.obj文件中导出符号或在CMake的帮助下导出符号
2.3.1.使用CMake
重要提示:您不需要任何类或函数的导出宏!
重要提示:使用此方法时,不能使用/ GL(整个程序优化)!
基于"CMakeLists.txt"文件创建CMake项目.
将以下行添加到"CMakeLists.txt"文件中:set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
然后在"CMake(cmake-gui)"的帮助下创建Visual Studio项目.
编译项目.
用法示例:
根文件夹
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(根文件夹)
#include "foo.h" int main() { HelloWorld(); return 0; }
Foo文件夹(Root文件夹/ Foo文件夹)
CMakeLists.txt(Foo文件夹)
project(foo) set(SOURCE_LIB foo.cpp) add_library(foo SHARED ${SOURCE_LIB})
foo.h(Foo文件夹)
void HelloWorld();
foo.cpp(Foo文件夹)
#includevoid HelloWorld() { std::cout << "Hello World!" << std::endl; }
再次链接到示例项目:
cmake_windows_export_all_symbols
CMake使用与"2.2.从静态库导出符号"方法不同的方法.
它执行以下操作:
1)在构建目录中创建"objects.txt"文件,并在dll中使用.obj文件的信息.
2)编译dll,即创建.obj文件.
3)基于"objects.txt"文件信息从.obj文件中提取所有符号.
用法示例:
DUMPBIN /SYMBOLS example.obj > log.txt
有关此内容的更多信息,请访问:
/符号
4)从.obj文件信息中提取的解析.
在我看来,我会用打电话的对流,例如"__cdecl/__ FASTCALL","SECTx /民主基金"符号字段(第三列),"外部/静"符号字段(第五列)," - ","? " 用于解析.obj文件的信息.
我不知道CMake究竟是如何解析.obj文件的.但是,CMake是开源的,所以你可以找出它是否对你感兴趣.
链接到CMake项目:
CMake_github
5)将所有导出的符号放在.def文件中.
6)使用.def创建的文件链接dll.
步骤4)-5),即解析.obj文件并在链接和使用.def文件之前创建.def文件.CMake在"Pre-Link事件"的帮助下完成.当"Pre-Link事件"触发时,您可以调用任何您想要的程序.因此,在"CMake usage""Pre-Link事件"的情况下,使用以下信息调用CMake,其中包含.def文件的放置位置以及"objects.txt"文件和参数"-E __create_def"的位置.您可以通过使用"set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)"创建CMake Visusal Studio项目来检查此信息,然后检查dll的".vcxproj"项目文件.
如果您尝试编译没有"set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)"或"set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)"的项目,您将得到链接错误,因为符号不是从dll导出的.
有关此内容的更多信息,请访问:
了解自定义构建步骤和构建事件
2.3.2.没有CMake使用
你可以简单地创建一个小程序来自己解析.obj文件而不需要使用CMake usege.Hovewer,我不得不承认CMake是非常有用的程序,特别是对于跨平台开发.
我编写了一个小程序来解析.lib文件中"dumpbin/linkermember"的输出.我有超过8,000个函数引用从一个DLL导出.
在DLL上执行此操作的问题是,您必须链接DLL而不导出定义一次以创建.lib文件,然后生成.def,这意味着您现在必须使用.def文件再次重新链接DLL将引用导出.
使用静态库更容易.将所有源代码编译为静态库,运行dumbin,使用您的小程序生成.def,然后将libs链接到DLL中,因为导出名称可用.
不幸的是,我的公司不允许我向您展示来源.所涉及的工作是识别def文件中不需要转储输出中的"公共符号".你必须扔掉很多这些引用,NULL_IMPORT_DESCRIPTOR,NULL_THUNK_DATA,__ imp*等.