解决 Windows C++ DLL 导出类不可见的编译错误

张开发
2026/4/11 4:19:40 15 分钟阅读

分享文章

解决 Windows C++ DLL 导出类不可见的编译错误
在把C类/函数编译成动态链接库过程中Windows 默认所有函数、类都不导出。虽然程序确实被编译成DLL了但是由于类/函数不写进符号表因此外部程序找不到它。我们可以写一个小程序测试一下my_print.h:#pragmaonceclassMyPrint{public:MyPrint();voidPrintHello();};my_print.cpp:#includemy_print.h#includeiostreamMyPrint::MyPrint(){}voidMyPrint::PrintHello(){std::couthellostd::endl;}主函数main.cpp#includemy_print.hintmain(){MyPrint my_print;my_print.PrintHello();return0;}我们希望把类MyPrint编译为dll同时main.cpp编译成可执行程序调用这个动态链接库。我们在CMakeLists.txt中写cmake_minimum_required(VERSION3.10)project(test)# 强制 MSVC 使用 UTF-8编码if(MSVC)add_compile_options(/utf-8)endif()# 编译动态库add_library(my_print_lib SHAREDmy_print.cppmy_print.h)# 编译可执行文件add_executable(testmain.cpp)# 链接动态库target_link_libraries(test PRIVATE my_print_lib)VS中使用MSVC编译器编译成功但运行后报错编译目录下面是存在DLL文件my_print_lib.dll但为什么会报这个错误呢这是因为Linux/macOS中默认所有类/函数都公开外部随便调用但Windows中默认所有函数都隐藏你不主动声明导出外部根本找不到函数。我们需要改造一下my_print.h加入导出宏#pragmaonce// 必须加导出/导入宏Windows 动态库才能正常使用#ifdef_WIN32// 判断当前编译平台是否为 Windows 系统#ifdefMYLIB// 判断是否正在编译生成动态库MYLIB 为自定义宏#defineDLL_TYPE__declspec(dllexport)// 定义为导出符号用于生成 DLL#else// 否则为使用动态库的场景#defineDLL_TYPE__declspec(dllimport)// 定义为导入符号用于调用 DLL#endif// 结束 MYLIB 宏判断#else// 非 Windows 平台Linux/macOS 等#defineDLL_TYPE// 类 Unix 系统无需导入导出宏定义为空#endifclassDLL_TYPEMyPrint{public:MyPrint();voidPrintHello();};同时我们还需要修改CMakeLists.txt文件:cmake_minimum_required(VERSION3.10)project(test)# 强制 MSVC 使用 UTF-8编码if(MSVC)add_compile_options(/utf-8)endif()# 编译动态库add_library(my_print_lib SHAREDmy_print.cppmy_print.h)target_compile_definitions(my_print_lib PRIVATE MYLIB)# 编译可执行文件add_executable(testmain.cpp)# 链接动态库target_link_libraries(test PRIVATE my_print_lib)最重要的是在编译my_print_lib这个库的时候定义一个叫MYLIB的宏只给库内部使用。清理编译目录后再次编译运行程序成功运行输出hello。我们在编译的目录下面除了my_print_lib.dll外还可以找到一个my_print_lib.lib文件这个文件用于在编译期帮助链接器完成符号解析运行期引导程序加载 DLL 并调用真实函数。

更多文章