C 测试 - Unity 和 CMake 的未定义引用
C Testing - undefined reference with Unity and CMake
我目前正在尝试使用 C 中的代码覆盖和测试进行项目设置。我当前的堆栈是 IDE 的 CLion,编译器的 Clang,覆盖的 gcov 和 lcov,Unity 的一个测试框架,以及在测试期间用于 mocking/stubbing 的 CMock。
我目前的包结构如下:
app/root
| build
| *.*
|- cmake
|- modules
|- CodeCoverage.cmake
|- coverage
|- coverage.info
|- external
|- Unity
|- CMock
|- CMakeLists.txt
|- src
|- *.c
|- *.h
|- CMakeLists.txt
|- tests
|- *.c
|- *.h
|- CMakeLists.txt
|- CMakeLists.txt
我的更高级别 CMakeLists.txt 看起来像:
cmake_minimum_required(VERSION 3.6)
project(my_c_app)
set(CMAKE_C_COMPILER "/usr/bin/clang")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake/modules)
set(CMAKE_VERBOSE_MAKEFILE ON)
add_subdirectory(external)
add_subdirectory(src)
add_subdirectory(tests)
我的应用级别 CMakeLists.txt 看起来像:
SET(CMAKE_CXX_FLAGS "-O0")
SET(CMAKE_C_FLAGS "-DLINUX -O0 -Wall -std=c99")
set(SOURCE_FILES
util.c
util.h)
add_executable(my_c_app ${SOURCE_FILES})
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(my_c_app Threads::Threads)
target_include_directories(my_c_app PUBLIC ${PROJECT_SOURCE_DIR}/include)
我的测试水平CMakeLists.txt看起来像:
enable_testing()
include(CodeCoverage)
include(CTest)
SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS "-DLINUX -O0 -Wall -std=c99 -g -fprofile-arcs -ftest-coverage")
SETUP_TARGET_FOR_COVERAGE(coverage tests ${PROJECT_SOURCE_DIR}/coverage/coverage "'/usr/*';'tests/*';'external/*'")
add_executable(tests util_test.c)
target_link_libraries(tests Unity CMock)
add_test(tests util_test.c)
目前我的问题是我做的事情不正确。我在尝试测试 util.c:
中的函数时收到未定义的引用
CMakeFiles/tests.dir/util_test.c.o: In function `test_my_method':
/home/patches/my_c_app/tests/util_test.c:6: undefined reference to `my_method'
我的 util_test.c 目前是:
#include <unity.h>
#include "../src/util.h"
void test_my_method(void) {
uchar result = my_method();
// assertion and other logic would go here
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_my_method);
return UNITY_END();
}
我是测试驱动的 c 开发和 CMake 的新手,所以我应该以什么正确的方式设置我的测试,以便它们依赖于 src 中的 c 文件?
如果我只是执行 TEST_ASSERT_EQUAL(1,1) 而不是调用 util.c 函数,我会看到:
1 Tests 0 Failures 0 Ignores
OK
Process finished with exit code 0
所以我觉得我 100% 陷入某种链接器问题。
util.c
不是 tests
源的一部分,也不是在 link 到 tests
的库中编译的。因此,您没有为 my_method
提供 tests
的任何定义,因此是未定义的引用。
您的可执行文件 my_c_app
的源代码中没有 main.c
文件。我猜你的主要功能是在 util.c
中定义的。如果我是对的,把它拿出来放在一个 main.c
文件中,然后将你的应用级别 CMakeLists.txt 更改为:
SET(CMAKE_CXX_FLAGS "-O0")
SET(CMAKE_C_FLAGS "-DLINUX -O0 -Wall -std=c99")
set(SOURCE_FILES
util.c
util.h)
add_library(my_c_lib STATIC ${SOURCE_FILES})
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(my_c_app Threads::Threads)
target_include_directories(my_c_app PUBLIC ${PROJECT_SOURCE_DIR}/include)
add_executable(my_c_app main.c)
target_link_libraries(my_c_app my_c_lib)
现在您的源代码编译在静态库中 my_c_lib
您可以 link 反对。您的应用已针对它 link 进行了测试,您也可以 link 在您的测试级别 CMakeLists.txt 中针对它进行测试:
enable_testing()
include(CodeCoverage)
include(CTest)
SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS "-DLINUX -O0 -Wall -std=c99 -g -fprofile-arcs -ftest-coverage")
SETUP_TARGET_FOR_COVERAGE(coverage tests ${PROJECT_SOURCE_DIR}/coverage/coverage "'/usr/*';'tests/*';'external/*'")
add_executable(tests util_test.c)
target_link_libraries(tests Unity CMock my_c_lib)
^^^^^^^^
add_test(tests util_test.c)
关于这条线:
add_test(tests util_test.c)
我在 documentation 中看不到目标及其来源的签名。你想用这个达到什么目的?
请注意,您可以使用 C_STANDARD
而不是 CMAKE_C_FLAGS
来指定 C 版本:
SET(CMAKE_C_STANDARD 99)
编译定义也可以用 target_compile_definitions
声明以避免全局污染。
我目前正在尝试使用 C 中的代码覆盖和测试进行项目设置。我当前的堆栈是 IDE 的 CLion,编译器的 Clang,覆盖的 gcov 和 lcov,Unity 的一个测试框架,以及在测试期间用于 mocking/stubbing 的 CMock。
我目前的包结构如下:
app/root
| build
| *.*
|- cmake
|- modules
|- CodeCoverage.cmake
|- coverage
|- coverage.info
|- external
|- Unity
|- CMock
|- CMakeLists.txt
|- src
|- *.c
|- *.h
|- CMakeLists.txt
|- tests
|- *.c
|- *.h
|- CMakeLists.txt
|- CMakeLists.txt
我的更高级别 CMakeLists.txt 看起来像:
cmake_minimum_required(VERSION 3.6)
project(my_c_app)
set(CMAKE_C_COMPILER "/usr/bin/clang")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake/modules)
set(CMAKE_VERBOSE_MAKEFILE ON)
add_subdirectory(external)
add_subdirectory(src)
add_subdirectory(tests)
我的应用级别 CMakeLists.txt 看起来像:
SET(CMAKE_CXX_FLAGS "-O0")
SET(CMAKE_C_FLAGS "-DLINUX -O0 -Wall -std=c99")
set(SOURCE_FILES
util.c
util.h)
add_executable(my_c_app ${SOURCE_FILES})
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(my_c_app Threads::Threads)
target_include_directories(my_c_app PUBLIC ${PROJECT_SOURCE_DIR}/include)
我的测试水平CMakeLists.txt看起来像:
enable_testing()
include(CodeCoverage)
include(CTest)
SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS "-DLINUX -O0 -Wall -std=c99 -g -fprofile-arcs -ftest-coverage")
SETUP_TARGET_FOR_COVERAGE(coverage tests ${PROJECT_SOURCE_DIR}/coverage/coverage "'/usr/*';'tests/*';'external/*'")
add_executable(tests util_test.c)
target_link_libraries(tests Unity CMock)
add_test(tests util_test.c)
目前我的问题是我做的事情不正确。我在尝试测试 util.c:
中的函数时收到未定义的引用CMakeFiles/tests.dir/util_test.c.o: In function `test_my_method':
/home/patches/my_c_app/tests/util_test.c:6: undefined reference to `my_method'
我的 util_test.c 目前是:
#include <unity.h>
#include "../src/util.h"
void test_my_method(void) {
uchar result = my_method();
// assertion and other logic would go here
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_my_method);
return UNITY_END();
}
我是测试驱动的 c 开发和 CMake 的新手,所以我应该以什么正确的方式设置我的测试,以便它们依赖于 src 中的 c 文件?
如果我只是执行 TEST_ASSERT_EQUAL(1,1) 而不是调用 util.c 函数,我会看到:
1 Tests 0 Failures 0 Ignores
OK
Process finished with exit code 0
所以我觉得我 100% 陷入某种链接器问题。
util.c
不是 tests
源的一部分,也不是在 link 到 tests
的库中编译的。因此,您没有为 my_method
提供 tests
的任何定义,因此是未定义的引用。
您的可执行文件 my_c_app
的源代码中没有 main.c
文件。我猜你的主要功能是在 util.c
中定义的。如果我是对的,把它拿出来放在一个 main.c
文件中,然后将你的应用级别 CMakeLists.txt 更改为:
SET(CMAKE_CXX_FLAGS "-O0")
SET(CMAKE_C_FLAGS "-DLINUX -O0 -Wall -std=c99")
set(SOURCE_FILES
util.c
util.h)
add_library(my_c_lib STATIC ${SOURCE_FILES})
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(my_c_app Threads::Threads)
target_include_directories(my_c_app PUBLIC ${PROJECT_SOURCE_DIR}/include)
add_executable(my_c_app main.c)
target_link_libraries(my_c_app my_c_lib)
现在您的源代码编译在静态库中 my_c_lib
您可以 link 反对。您的应用已针对它 link 进行了测试,您也可以 link 在您的测试级别 CMakeLists.txt 中针对它进行测试:
enable_testing()
include(CodeCoverage)
include(CTest)
SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS "-DLINUX -O0 -Wall -std=c99 -g -fprofile-arcs -ftest-coverage")
SETUP_TARGET_FOR_COVERAGE(coverage tests ${PROJECT_SOURCE_DIR}/coverage/coverage "'/usr/*';'tests/*';'external/*'")
add_executable(tests util_test.c)
target_link_libraries(tests Unity CMock my_c_lib)
^^^^^^^^
add_test(tests util_test.c)
关于这条线:
add_test(tests util_test.c)
我在 documentation 中看不到目标及其来源的签名。你想用这个达到什么目的?
请注意,您可以使用 C_STANDARD
而不是 CMAKE_C_FLAGS
来指定 C 版本:
SET(CMAKE_C_STANDARD 99)
编译定义也可以用 target_compile_definitions
声明以避免全局污染。