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

编译GTest单元测试时出现undefined reference错误,求排查解决

问题描述

我有一个项目的目录结构如下:
Directory Structure

根目录的CMakeLists.txt内容:

cmake_minimum_required(VERSION 3.0.0)
project(yx_ip C)
set(CMAKE_C_STANDARD 99)

#########
# GTest #
#########
enable_testing()
add_subdirectory(libs/gtest-1.7.0)
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})

###########
# Project #
###########
add_executable(yx_ip main.c)
add_subdirectory(libs/arp)
add_subdirectory(libs/base)
add_subdirectory(unit_test)
target_link_libraries(yx_ip BASE ARP)

unit_test目录下的CMakeLists.txt内容:

cmake_minimum_required(VERSION 3.0.0)
set(TEST_PROJECT_NAME UnitsTests)
file(GLOB LIBRARY_TESTS_SOURCE *.cpp)
project(${TEST_PROJECT_NAME})
enable_testing()

if (NOT (TARGET gtest AND TARGET gtest_main))
    message(FATAL_ERROR "gtest and gtest_main targets NOT found")
endif()

add_executable(${TEST_PROJECT_NAME} ${LIBRARY_TESTS_SOURCE})
#target_link_libraries(${TEST_PROJECT_NAME} BASE)
target_link_libraries(${TEST_PROJECT_NAME} BASE gtest gtest_main)
add_test(${TEST_PROJECT_NAME}, ${TEST_PROJECT_NAME})

执行make编译时出现错误:

unit_test/utils_test.cpp:6: undefined reference to `pasrse_ip_address(char*)'
collect2: error: ld returned 1 exit status

但单独编译main.c时一切正常,请问该如何解决此问题?


解决方案

这个问题大概率和C/C++混合编译的符号差异或者库依赖配置有关,我给你一步步拆解排查:

1. 先检查函数名拼写

先看错误里的函数名pasrse_ip_address——是不是少写了一个e?正确的应该是parse_ip_address?如果是拼写失误,直接修正测试代码里的函数名就能解决问题。要是确认拼写没问题,继续往下看。

2. 处理C/C++混合编译的名称修饰问题

你的主项目是C语言(根目录project(yx_ip C),源码是.c文件),但单元测试是C代码(.cpp文件)。C编译器会对函数名做名称修饰(Name Mangling),而C编译器不会,这就导致C++代码找不到C编译出来的函数符号。

解决方法是在C语言的头文件中添加extern "C"声明,让C++编译器按照C的规则解析这些函数:
假设pasrse_ip_address定义在libs/base的某个C文件里,对应的头文件(比如base_utils.h)要改成这样:

#ifndef BASE_UTILS_H
#define BASE_UTILS_H

#ifdef __cplusplus
extern "C" {
#endif

// 声明你的函数
void pasrse_ip_address(char*);
// 其他C函数声明...

#ifdef __cplusplus
}
#endif

#endif // BASE_UTILS_H

然后在你的C测试文件utils_test.cpp中包含这个头文件,这样C编译器就会用C的符号规则去查找函数。

3. 确认BASE库包含了目标函数

检查libs/base目录下的CMakeLists.txt,确保包含pasrse_ip_address定义的C文件被加入到库构建中。比如:

add_library(BASE STATIC
    base_utils.c  # 假设这个文件里有pasrse_ip_address的实现
    # 其他源文件...
)

如果这个C文件没被加到BASE库,链接时自然找不到函数符号。

4. 优化库的头文件导出配置

为了让unit_test能正确找到BASE库的头文件,建议在libs/base/CMakeLists.txt中添加:

target_include_directories(BASE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

这样CMake会自动把BASE的头文件目录传递给依赖它的目标(比如你的单元测试),不用手动写include_directories。

5. 清理缓存重新构建

有时候CMake的缓存会导致奇怪的依赖问题,执行以下命令清理后重新构建试试:

rm -rf build/  # 如果用了build目录,没有的话跳过这步
mkdir build && cd build
cmake ..
make

按照上面的步骤排查,基本就能解决这个未定义引用的问题了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:46:53