You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:20:49