MSVC编译共享库时未实现函数的LNK2019链接错误修复咨询
问题:MSVC下动态库符号解析失败,GCC正常运行
库代码与编译配置
lib.hh
#ifdef WIN32 #ifdef BUILDING #define EXPORT_THIS __declspec(dllexport) #else #define EXPORT_THIS __declspec(dllimport) #endif #elif defined(__linux__) #define EXPORT_THIS extern "C" #endif EXPORT_THIS void Function(); void UseThatFunction();
lib.cc
#include "lib.hh" void UseThatFunction() { Function(); }
库的CMake脚本
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS on) add_library(ThatLibrary SHARED lib.cc lib.hh) target_compile_definitions(ThatLibrary PRIVATE BUILDING) add_subdirectory(backend)
用户侧代码与编译配置
using.cc
#include "../lib.hh" void EXPORT_THIS Function() { /* implementation */ }
用户侧CMake脚本
add_library(UsingThatLibrary SHARED using.cc) target_link_libraries(UsingThatLibrary PUBLIC ThatLibrary )
报错信息
lib.obj : error LNK2019: unresolved external symbol "void __cdecl Function(void)" (?Function@@YAXXZ) referenced in function "void __cdecl UseThatFunction(void)" (?UseThatFunction@@YAXXZ)
补充说明:静态编译lib时可正常运行,但动态库版本出现上述链接错误,需满足以下限制:
- 不能使用虚函数
- 无法在用户侧实现
UseThatFunction - 需兼容GCC(>=11)和MSVC(>=2020)
问题原因
MSVC与GCC对动态库未定义符号的处理逻辑存在差异:
- GCC允许动态库中存在未定义符号,运行时由后续加载的其他动态库提供实现;
- MSVC默认要求动态库编译阶段所有引用的符号必须有定义,否则触发LNK2019错误。静态编译时因为最终将所有代码链接为一个整体,能找到
Function的实现,但动态库编译阶段无法感知用户侧的实现,因此报错。
修复方案
1. 修改lib.hh的宏定义
调整MSVC下EXPORT_THIS的行为,让编译库时告知链接器Function来自外部DLL:
#ifdef WIN32 #ifdef BUILDING // 编译库时,标记Function为dllimport,说明符号来自外部DLL #define EXPORT_THIS __declspec(dllimport) #else // 用户侧实现时,标记Function为dllexport以导出符号 #define EXPORT_THIS __declspec(dllexport) #endif #elif defined(__linux__) // GCC下保持extern "C",避免C++名字修饰导致符号不匹配 #define EXPORT_THIS extern "C" #endif EXPORT_THIS void Function(); void UseThatFunction();
2. 保持原有编译脚本不变
- 库的CMake脚本仍将
BUILDING设为私有宏,确保编译ThatLibrary时触发dllimport分支; - 用户侧代码编译时不定义
BUILDING,因此EXPORT_THIS自动变为dllexport,正确导出Function的实现。
原理说明
- MSVC环境:编译
ThatLibrary时,Function被声明为__declspec(dllimport),链接器会识别该符号需从外部DLL导入,不再要求当前库提供定义,顺利通过编译;运行时加载用户侧的UsingThatLibrary后,系统会自动解析Function的实现。 - GCC环境:
extern "C"确保符号名保持C风格,避免C++名字修饰,同时GCC默认允许动态库引用未定义符号,运行时可正常解析用户侧的实现。
该方案满足所有限制条件,完美兼容指定版本的GCC和MSVC。
内容的提问来源于stack exchange,提问作者Ghasem Ramezani
相关产品推荐
相关产品推荐

