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

MinGW下CMake项目链接DLL报undefined reference问题求解

问题根因

MinGW环境下CMake链接预编译动态库时出现undefined reference to 函数名编译错误、或运行时返回0x0135(依赖库未找到)错误,本质是三类配置或环境问题:

  • 链接阶段未正确匹配MinGW格式的导入库(.dll.a),要么误使用MSVC编译的.lib文件,要么库路径配置错误导致链接器无法扫描到目标库文件
  • 预编译库与当前使用的MinGW工具链不兼容:包括32/64位架构不匹配、异常模型(dwarf/seh/sjlj)不匹配、C++运行时版本不匹配,这类问题无论怎么改路径都会报符号找不到
  • 编译阶段成功链接了导入库,但运行时.dll文件不在可执行文件同目录、也不在系统PATH搜索路径中,导致系统加载程序时找不到依赖dll
MinGW环境CMake链接预编译动态库通用方案

不要使用老式的include_directories/link_directories全局配置,这类配置作用域不可控、容易出现路径匹配问题,优先使用IMPORTED导入目标方式配置,步骤固定、兼容性最好:

  1. 先统一第三方库的目录结构,避免路径混乱,推荐按如下结构存放所有预编译库:
    项目根目录/
    ├─ libs/
    │  └─ [库名]/
    │     ├─ include/    # 存放所有公开.h头文件
    │     ├─ lib/        # 存放.dll.a导入库、.a静态库文件
    │     └─ bin/        # 存放.dll动态库文件
    ├─ CMakeLists.txt
    └─ 源码文件
    
  2. 提前校验库兼容性,避免无意义的配置调试:
    打开当前项目使用的MinGW命令行,进入库的lib目录,执行nm [库的.dll.a文件名] | grep [报错的函数名],如果能搜索到对应函数符号,说明库本身与工具链兼容;如果搜不到符号,直接更换和当前MinGW同版本、同架构、同异常模型编译的库即可,不用继续调配置。
  3. 套用通用CMake配置模板:
    cmake_minimum_required(VERSION 3.22)
    project(你的项目名)
    set(CMAKE_CXX_STANDARD 23)
    # 统一输出编译产物到固定目录,方便管理依赖
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
    
    # ============== 第三方库配置块开始 ==============
    # 1. 定义库的根路径,根据实际库存放位置修改
    set([LIB_NAME]_ROOT ${CMAKE_SOURCE_DIR}/libs/[库文件夹名])
    # 2. 创建SHARED类型的导入目标
    add_library([LIB_NAME]::[LIB_NAME] SHARED IMPORTED)
    # 3. 配置头文件路径、导入库路径、动态库路径
    set_target_properties([LIB_NAME]::[LIB_NAME] PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES "${[LIB_NAME]_ROOT}/include"
        IMPORTED_IMPLIB "${[LIB_NAME]_ROOT}/lib/[导入库全名,比如libxxx.dll.a]"
        IMPORTED_LOCATION "${[LIB_NAME]_ROOT}/bin/[动态库全名,比如xxx.dll]"
    )
    # ============== 第三方库配置块结束 ==============
    
    add_executable(你的项目名 你的源码文件列表)
    # 链接时直接引用导入目标即可,自动继承头文件路径配置
    target_link_libraries(你的项目名 PRIVATE [LIB_NAME]::[LIB_NAME])
    
    # 自动拷贝dll到exe输出目录,彻底解决运行时找不到dll的0x0135错误
    add_custom_command(TARGET 你的项目名 POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        $<TARGET_FILE:[LIB_NAME]::[LIB_NAME]>
        $<TARGET_FILE_DIR:你的项目名>
    )
    
现有配置的修正示例

SDL2配置修正

你原有配置的核心问题:

  • 使用add_subdirectory(SDL2)是源码编译子项目的写法,如果你存放的是预编译版SDL2,目录下没有对应的CMakeLists.txt,根本不会生成可供链接的SDL2目标,自然报符号找不到
  • 没有处理SDL2在Windows平台的入口宏逻辑,容易触发SDL_main相关链接错误
    修正后的配置(按前面的目录结构把SDL2放到libs/SDL2下):
cmake_minimum_required(VERSION 3.22)
project(untitled)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

set(SDL2_ROOT ${CMAKE_SOURCE_DIR}/libs/SDL2)
add_library(SDL2::SDL2 SHARED IMPORTED)
set_target_properties(SDL2::SDL2 PROPERTIES
    INTERFACE_INCLUDE_DIRECTORIES "${SDL2_ROOT}/include"
    IMPORTED_IMPLIB "${SDL2_ROOT}/lib/libSDL2.dll.a"
    IMPORTED_LOCATION "${SDL2_ROOT}/bin/SDL2.dll"
)
# 不使用SDL自带的main入口框架时必须加这个宏,否则会报main相关链接错误
target_compile_definitions(SDL2::SDL2 INTERFACE SDL_MAIN_HANDLED)

add_executable(untitled main.cpp)
target_link_libraries(untitled PRIVATE SDL2::SDL2)

add_custom_command(TARGET untitled POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_FILE:SDL2::SDL2>
    $<TARGET_FILE_DIR:untitled>
)

SIGIL配置修正

你原有配置的核心问题:

  • link_directories是全局目录配置,作用域存在传递限制,且MinGW链接器搜索库时要求文件名严格匹配,你直接传入sigil作为库名,如果导入库实际文件名是libsigil.dll.a,链接器无法自动识别匹配
  • 没有配置运行时dll的拷贝逻辑,就算编译通过也会触发0x0135错误
    修正方法:将SIGIL的头文件、.dll.a、.dll按前面的目录结构放到libs/sigil对应子目录下,直接套用通用导入目标模板即可,完全不需要使用link_directories配置。
避坑提示
  • 不要混用不同发行版的MinGW:比如用CLion自带的MinGW编译项目,就不要使用MSYS2、TDM-GCC等其他发行版MinGW编译的预编译库,大概率因为运行时、异常模型不兼容出现链接错误
  • 手动管理的预编译库不要依赖find_package查找,除非你手动指定了库的搜索路径,否则find_package大概率会匹配到系统中其他版本的同名库,引发奇怪的问题
  • 不要为了省事把dll拷贝到系统System32目录,换编译环境、换设备运行时会直接失效,用编译后自动拷贝的方式是最稳妥的方案

内容的提问来源于stack exchange,提问作者dimanchique

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:36:27