首次使用CMake为C++项目集成snappy-c库出现未定义引用错误的咨询
报错原因
两个问题叠加导致了链接失败:
- 核心问题:你使用的snappy-c是纯C编写的库,头文件没有做C兼容处理。C编译器在引入头文件时,会默认对所有函数做名称修饰(把参数类型编码到最终生成的符号名里,你报错信息里的
snappy_init_env(snappy_env*)就是典型的修饰后符号),但你提前用Makefile编译出的snappy.o是C语言编译的产物,里面的函数符号是不带参数信息的纯snappy_init_env,两边符号完全无法匹配,就会抛出未定义引用错误。 - 次要问题:你的CMake配置里写的snappy.o路径和实际使用的路径不一致。从
make VERBOSE=1的输出能看到,最终链接环节用的是../../server-side/libs/snappy.o,但你CMake里指定的是libs/snappy-c/snappy.o,路径不对应,就算符号问题解决了也容易出问题。
解决方案
快速修复代码
修改你调用snappy的C代码,用extern "C"包裹头文件引入,告诉C编译器不要对这批C函数做名称修饰:
#include <iostream> // 告诉编译器以下是C语言符号,不要做名称修饰 extern "C" { #include "snappy.h" } int main(){ struct snappy_env env; snappy_init_env(&env); }
同时修正CMakeLists里的snappy.o路径,确保路径指向你实际编译生成的snappy.o的位置。
更规范的CMake集成方式
不用手动跑snappy-c自带的Makefile,直接在CMake项目里自动编译snappy为静态库,从根源上避免路径写错的问题:
修改你的CMakeLists.txt,删掉原来手动链接snappy.o的逻辑,替换为以下内容:
cmake_minimum_required(VERSION 3.5) add_definitions(-std=c++11) # 项目公共头文件路径 include_directories("include") # 自动编译snappy-c源码为静态库 add_library(snappy STATIC ${CMAKE_CURRENT_SOURCE_DIR}/libs/snappy-c/snappy.c) # 给snappy库设置公开头文件路径,依赖它的目标会自动继承这个路径 target_include_directories(snappy PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libs/snappy-c) # 收集项目所有源码 file(GLOB_RECURSE SOURCES "src/*.cpp" main.cpp) # 生成可执行文件 add_executable(common-main ${SOURCES}) # 链接依赖库 target_link_libraries(common-main snappy) find_library(LIBRT rt) if(LIBRT) target_link_libraries(common-main ${LIBRT}) endif()
一劳永逸的适配方法
如果不想每次引入snappy.h都手动写extern "C",可以直接修改libs/snappy-c/snappy.h的内容:
- 在文件最顶部添加兼容宏:
#ifdef __cplusplus extern "C" { #endif - 在文件最末尾添加闭合宏:
#ifdef __cplusplus } #endif
之后不管是C还是C++代码引入这个头文件,都会自动适配编译规则。
内容的提问来源于stack exchange,提问作者0Nicholas
相关产品推荐
相关产品推荐

