无需新增CMakeLists.txt,CMake项目引入子目录文件的报错解决
问题:子模块C文件函数未定义引用
项目结构
root/ | CMakeLists.txt | main.cc | a.cc | a.h | submodule/ | | b.c | | b.h
需求与尝试
不想为子模块添加额外的CMakeLists.txt(避免Git维护成本,且文件数量少,CMake配置冗余),尝试通过以下CMake配置引入子模块文件:
include_directories(${PROJECT_SOURCE_DIR}/submodule) ... add_executable(${NAME} submodule/b.c main.cpp server.cc )
还尝试添加了target_link_directories,但均出现函数未定义引用错误,报错信息如下:
/usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: CMakeFiles/light.dir/ server.cc.obj: in function `tcpRecvCallback(void*, tcp_pcb*, pbuf*, signed char) [clon e .part.0]': server.cc:(.text._Z15tcpRecvCallbackPvP7tcp_pcbP4pbufa.part.0+0x62): undefined referen ce to `http_req_parse(char*)' collect2: error: ld returned 1 exit status gmake[2]: *** [CMakeFiles/light.dir/build.make:3083: light.elf] Error 1 gmake[1]: *** [CMakeFiles/Makefile2:1520: CMakeFiles/light.dir/all] Error 2 gmake: *** [Makefile:156: all] Error 2
注:http_req_parse是b.c中的函数,server.cc(C++文件)包含了submodule/b.h,当前为Raspberry Pi Pico W构建项目。
解决方案
核心原因:C/C++混合编译的名字修饰差异
server.cc是C源文件,b.c是C源文件,C编译器会对函数名进行名字修饰(Name Mangling),导致链接时无法匹配C文件中未被修饰的原始函数名,从而出现未定义引用错误。
具体修复步骤
1. 用extern "C"包裹C头文件的包含
在C++文件(比如server.h或server.cc)中包含b.h时,添加extern "C"块:
#ifdef __cplusplus extern "C" { #endif #include "b.h" #ifdef __cplusplus } #endif
也可以直接修改b.h,在文件开头和结尾添加上述宏,这样所有包含该头文件的C/C++文件都能正确识别函数名。
2. 确认CMake配置的正确性
你的原有CMake配置已经满足需求,无需额外修改:
include_directories正确添加了子模块的头文件路径,确保编译时能找到b.hadd_executable中已经包含了submodule/b.c,该文件会被C编译器正常编译,无需额外链接库操作- 无需使用
target_link_directories,因为你是直接编译源文件,不是链接预编译库
3. 额外排查点
- 确认
b.c中确实实现了http_req_parse函数,而非仅在b.h中声明 - 检查CMake中
${NAME}变量是否正确指向你的目标可执行文件,避免拼写错误
内容的提问来源于stack exchange,提问作者confusedandsad
相关产品推荐
相关产品推荐

