C++中如何在一个DLL声明extern函数并在另一个DLL实现?
跨DLL实现extern函数的可行方案(VS2022 + CMake + C++23)
问题背景
在Visual Studio 2022、CMake和C++23环境下,尝试在DLL A的头文件声明无实现的extern函数,在DLL B中提供实现,但链接器报错找不到函数定义。
原尝试代码
// DLL A的头文件 extern int MyFunction(); // 无实现体的声明 // DLL B的源文件 int MyFunction() { return 42; // 具体实现 }
方案可行性说明
该方案完全可行,链接错误的核心原因是:Windows平台下DLL中的函数默认不会被导出到符号表,仅靠extern关键字无法让跨DLL的模块解析到函数符号。需要通过显式的导出/导入标记和CMake配置来完成跨DLL符号链接。
正确实现步骤
1. 代码层面:显式标记导出与导入
通过条件编译宏区分函数的导出(DLL B中)和导入(DLL A中):
公共头文件(FunctionShared.h)
用于统一函数声明,放在两个DLL都能访问的路径下:
#ifndef FUNCTION_SHARED_H #define FUNCTION_SHARED_H // 定义导出/导入宏:编译DLL B时导出,其他场景导入 #ifdef BUILD_DLL_B #define FUNCTION_API __declspec(dllexport) #else #define FUNCTION_API __declspec(dllimport) #endif // 带标记的函数声明 extern FUNCTION_API int MyFunction(); #endif // FUNCTION_SHARED_H
DLL B的源文件实现
#define BUILD_DLL_B // 触发导出宏 #include "FunctionShared.h" int MyFunction() { return 42; }
DLL A中调用函数
直接包含公共头文件即可:
#include "FunctionShared.h" void UseMyFunction() { int result = MyFunction(); }
2. CMake配置:处理依赖与编译宏
DLL B的CMakeLists.txt
add_library(DllB SHARED src/DllB.cpp include/FunctionShared.h ) # 暴露公共头文件路径,让DLL A能找到 target_include_directories(DllB PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ) # 定义BUILD_DLL_B宏,确保函数被导出 target_compile_definitions(DllB PRIVATE BUILD_DLL_B) # 指定C++23标准 target_compile_features(DllB PRIVATE cxx_std_23)
DLL A的CMakeLists.txt
add_library(DllA SHARED src/DllA.cpp ) # 引入DllB的头文件 target_include_directories(DllA PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../DllB/include ) # 链接DllB的导入库,解析函数符号 target_link_libraries(DllA PRIVATE DllB) # 指定C++23标准 target_compile_features(DllA PRIVATE cxx_std_23)
关键注意点
__declspec(dllexport):让编译器将函数写入DLL的符号表,并生成对应的.lib导入库。__declspec(dllimport):告诉编译器该函数来自外部DLL,需从导入库中查找符号。- CMake中通过
target_compile_definitions为DLL B单独定义宏,避免其他模块误触发导出逻辑。 - 编译后需确保DLL A运行时能找到DLL B的
.dll文件(可将输出目录统一,或手动复制)。
内容的提问来源于stack exchange,提问作者LagowiecDev
相关产品推荐
相关产品推荐

