使用CMake链接C++项目与C共享库时出现未解析外部符号错误
我尝试用CMake将一个新C项目链接到某C库,单独克隆编译该库时测试运行正常,但将其作为git子模块加入我的C项目后,链接main.cpp时出现大量类似如下的链接错误:
Error LNK2019 unresolved external symbol "__declspec(dllimport) void __cdecl wimp_instr_queue_high_prio_lock(struct _WimpInstrQueue *)" (_imp?wimp_instr_queue_high_prio_lock@@YAXPEAU_WimpInstrQueue@@@Z) referenced in function main magnum-wimp main.obj
.dll文件已生成并放置在二进制目录,用于链接符号的.lib文件也已生成在lib目录中。我的C++项目结构包含dependencies文件夹和src文件夹,核心配置是两个CMakeLists.txt文件:
根目录CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(magnum-wimp CXX) set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}) add_subdirectory(dependencies) add_subdirectory(magnum-wimp) set_target_properties(wimp PROPERTIES FOLDER Dependencies) set_target_properties(wimp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}" )
magnum-wimp/src目录CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(magnum-wimp) add_executable(${PROJECT_NAME} main.cpp) # Include the directory containing the wimp library headers target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/dependencies/wimp/wimp/src) # Add the directory containing the wimp library target_link_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}) # Link against the wimp shared library target_link_libraries(${PROJECT_NAME} PRIVATE wimp)
我的src目录CMakeLists配置和该库测试目录的配置类似,但无法成功链接。加载Visual Studio解决方案时已指向.lib文件,但单独编译库时测试能正常链接使用,这点和预期一致。
1. 修复C/C++名称修饰(Name Mangling)问题
C库的函数在C++编译环境中会被自动进行名称修饰,导致链接器无法匹配符号。解决方法是在包含库头文件时用extern "C"包裹:
在你的main.cpp中修改头文件引入方式:
extern "C" { #include "wimp.h" // 替换为库实际的头文件名 }
或者直接修改库的头文件,添加C++兼容宏(如果有权限修改库代码):
#ifdef __cplusplus extern "C" { #endif // 库的函数声明、结构体定义等内容 #ifdef __cplusplus } #endif
2. 简化CMake依赖关联,避免手动路径配置
不要手动设置target_link_directories,让CMake自动处理依赖关联:
- 确保根目录CMakeLists.txt中正确添加wimp子模块的路径,比如将
add_subdirectory(dependencies)改为add_subdirectory(dependencies/wimp)(根据子模块实际路径调整),这样CMake能正确识别wimp库的目标。 - 修改magnum-wimp/src目录的CMakeLists.txt,直接关联wimp目标,CMake会自动处理头文件包含和链接路径:
cmake_minimum_required(VERSION 3.5) project(magnum-wimp) add_executable(${PROJECT_NAME} main.cpp) # 直接关联wimp目标,无需手动配置路径 target_link_libraries(${PROJECT_NAME} PRIVATE wimp)
3. 检查库的编译类型(静态/动态)
如果wimp库编译为静态库,需要确认是否需要定义特定宏来禁用__declspec(dllimport)。查看库的CMakeLists.txt或头文件,找到对应宏(比如WIMP_STATIC),在你的项目中添加:
target_compile_definitions(${PROJECT_NAME} PRIVATE WIMP_STATIC)
4. 确保构建类型一致
确认你的项目和wimp库使用相同的构建类型(Debug/Release)。CMake的CMAKE_BUILD_TYPE需要统一,避免Debug项目链接Release库或反之,这会导致符号不匹配。
内容的提问来源于stack exchange,提问作者erb nobbles

