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

CMake中使用多个GTest测试用例出现链接错误,求解决方案

问题与解决方案

项目结构

- include
  - func.h
- src
  - main.cpp
  - func.cpp
- tests
  - CMakeLists.txt
  - func1_test.cpp
  - func2_test.cpp
- CMakeLists.txt

相关配置与代码

根目录CMakeLists.txt

cmake_minimum_required (VERSION 3.12)

option(BUILD_TESTS "BuildTests" ON)
set(PROJECT_VERSION "0.0.3" CACHE INTERNAL "Version")

project ("test_project" VERSION ${PROJECT_VERSION})
add_executable (test_project "src/main.cpp" "src/func.cpp" "include/func.h")
include_directories("include")

set_property(TARGET test_project PROPERTY CXX_STANDARD 20)

# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)
  cmake_policy(SET CMP0141 NEW)
  set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()

set_target_properties(test_project
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)

# Tests.
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

测试目录CMakeLists.txt

include(FetchContent)
if (POLICY CMP0135)
  cmake_policy(SET CMP0135 NEW)
endif()
FetchContent_Declare(
  googletest
  URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

include(GoogleTest)

set(TestsToRun
  func1_test.cpp
  func2_test.cpp
)
create_test_sourcelist (Tests CppTests.cpp ${TestsToRun})
add_executable (CppTests ${Tests})
target_include_directories(CppTests PRIVATE "include")
set_property(TARGET CppTests PROPERTY CXX_STANDARD 20)
target_link_libraries(CppTests GTest::gtest_main)
set_target_properties(CppTests
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
foreach (test ${TestsToRun})
    get_filename_component (TName ${test} NAME_WE)
    add_test (NAME ${TName} COMMAND CppTests ${TName})
    #gtest_discover_tests(${test})
endforeach ()

func.h

#pragma once
int func1();
int func2();

func.cpp

#include "func.h"

int func1()
{
    return 33;
}

int func2()
{
    return 77;
}

func1_test.cpp(func2_test.cpp类似)

#include <sstream>
#include <limits>
#include <gtest/gtest.h>

#include "../include/func.h"

TEST(Func1Test, Func1Test)
{
    ASSERT_EQ(func1(), 33);
}

编译错误

[main] Building folder: /home/user/Code/Test/build/linux-debug 
[build] Starting build
[proc] Executing command: /usr/bin/cmake --build /home/user/Code/Test/build/linux-debug --parallel 22 --
[build] [ 20%] Built target test_project
[build] [ 33%] Built target gtest
[build] [ 46%] Built target gtest_main
[build] [ 60%] Built target gmock
[build] [ 73%] Built target gmock_main
[build] [ 80%] Linking CXX executable ../bin/CppTests
[build] /usr/bin/ld: CMakeFiles/CppTests.dir/CppTests.cpp.o:(.data.rel.ro+0x8): undefined reference to `func1_test(int, char**)'
[build] /usr/bin/ld: CMakeFiles/CppTests.dir/CppTests.cpp.o:(.data.rel.ro+0x18): undefined reference to `func2_test(int, char**)'
[build] /usr/bin/ld: CMakeFiles/CppTests.dir/func1_test.cpp.o: in function `Func1Test_Func1Test_Test::TestBody()':
[build] /home/user/Code/Test/tests/func1_test.cpp:9:(.text+0x28): undefined reference to `func1()'
[build] /usr/bin/ld: CMakeFiles/CppTests.dir/func2_test.cpp.o: in function `Func21Test_Func2Test_Test::TestBody()':
[build] /home/user/Code/Test/tests/func2_test.cpp:(.text+0x28): undefined reference to `func2()'
[build] collect2: error: ld returned 1 exit status
[build] gmake[2]: *** [tests/CMakeFiles/CppTests.dir/build.make:131: bin/CppTests] Error 1
[build] gmake[1]: *** [CMakeFiles/Makefile2:180: tests/CMakeFiles/CppTests.dir/all] Error 2
[build] gmake: *** [Makefile:146: all] Error 2
[proc] The command: /usr/bin/cmake --build /home/user/Code/Test/build/linux-debug --parallel 22 -- exited with code: 2
[driver] Build completed: 00:00:00.352
[build] Build finished with exit code 2

问题分析与解决

1. 未链接核心函数实现

错误中的undefined reference to func1()/func2(),是因为测试程序CppTests只包含测试代码,未关联src/func.cpp的编译结果,导致链接时找不到函数实现。

解决方法:将核心代码封装为库
修改根目录CMakeLists.txt,把核心代码做成静态库,主程序和测试程序都链接这个库:

cmake_minimum_required (VERSION 3.12)

option(BUILD_TESTS "BuildTests" ON)
set(PROJECT_VERSION "0.0.3" CACHE INTERNAL "Version")

project ("test_project" VERSION ${PROJECT_VERSION})

# 核心代码封装为静态库
add_library(core_lib STATIC "src/func.cpp" "include/func.h")
target_include_directories(core_lib PUBLIC "include")
set_property(TARGET core_lib PROPERTY CXX_STANDARD 20)

# 主程序链接核心库
add_executable(test_project "src/main.cpp")
target_link_libraries(test_project PRIVATE core_lib)
set_property(TARGET test_project PROPERTY CXX_STANDARD 20)

# ... 其余原有配置不变 ...

# Tests.
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

然后在测试目录CMakeLists.txt中,让CppTests链接核心库:

# ... FetchContent部分不变 ...

include(GoogleTest)

# 直接添加测试文件,无需create_test_sourcelist
add_executable(CppTests func1_test.cpp func2_test.cpp)
target_include_directories(CppTests PRIVATE "../include")
set_property(TARGET CppTests PROPERTY CXX_STANDARD 20)
# 链接核心库与GTest
target_link_libraries(CppTests PRIVATE core_lib GTest::gtest_main)

# ... 输出目录配置不变 ...

# 自动发现测试用例
gtest_discover_tests(CppTests)

2. 错误使用create_test_sourcelist

create_test_sourcelist是CMake为传统非GTest测试框架设计的工具,要求每个测试文件必须定义与文件名同名的函数(比如func1_test.cpp中需写int func1_test(int argc, char** argv)),但GTest的测试用例是通过TEST宏自动生成的,不符合该要求,因此出现undefined reference to func1_test(int, char**)错误。

解决方法:完全移除create_test_sourcelist相关代码,直接将测试文件添加到可执行目标,使用GTest原生方式管理测试用例。

gtest_discover_tests的正确用法

gtest_discover_tests是CMake集成GTest的推荐方式,它会自动运行测试可执行文件,扫描所有用TEST/TEST_F定义的测试用例,并为每个用例生成对应的CTest测试项,无需手动编写add_test循环。

使用规则:

  • 必须先创建测试可执行目标(如CppTests)
  • 调用gtest_discover_tests(目标名),替代所有手动add_test逻辑
  • 调用前需先执行include(GoogleTest)

修改后的测试目录CMakeLists核心部分:

# ... FetchContent部分不变 ...

include(GoogleTest)

add_executable(CppTests func1_test.cpp func2_test.cpp)
target_include_directories(CppTests PRIVATE "../include")
set_property(TARGET CppTests PROPERTY CXX_STANDARD 20)
target_link_libraries(CppTests PRIVATE core_lib GTest::gtest_main)

set_target_properties(CppTests
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)

gtest_discover_tests(CppTests)

修改后即可解决所有链接错误,同时CTest会自动发现并管理所有GTest测试用例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 06:28:09