首页 > 解决方案 > 将 C++ 和 C/C++ 静态库与 CMake 混合

问题描述

我搜索了各种论坛,但找不到解决问题的方法。
我正在尝试在 C 文件中编写函数的单元测试。我正在使用谷歌测试库。
尽管我按照指南进行操作,但该项目无法正确编译。
用 C++ 编写的测试看不到 C 文件中的函数。(未定义参考)
下面我附上我的文件,也许有人会注意到我在哪里犯了错误。我没主意了。

项目树

pir_driver.h

#ifndef PIR_DRIVER_H_
#define PIR_DRIVER_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdint.h>

uint32_t xTaskGetTickCount();


#ifdef __cplusplus
} /* extern "C" */
#endif

pir_driver.c

#include "pir_driver.h"

uint32_t xTaskGetTickCount()
{
    return 1000;
}

pir_test.cpp

#include <gtest/gtest.h>
#include "../pir_driver.h"

TEST(PIR_Timer_Test, Start)
{
    uint32_t test =  xTaskGetTickCount() * 2;
    EXPECT_EQ(test, test);

}

项目根 CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
set(This pir_driver)
project(${This} C CXX)
include(Dart)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
enable_testing()
add_subdirectory(googletest)
set(Headers
    pir_driver.h
)
set(Source
    pir_driver.c
)
add_library(${This} STATIC ${Sources} ${Headers})
set_target_properties(${This} PROPERTIES LINKER_LANGUAGE C)
add_subdirectory(test)

测试 CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
set(This pir_test)
set(Sources pir_test.cpp )

add_executable(${This} ${Sources})
set_target_properties(${This} PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(${This} PUBLIC pir_driver gtest_main )

add_test( NAME ${This} COMMAND ${This})

编译日志:

[proc] Wykonywanie polecenia: "C:\Program Files\CMake\bin\cmake.EXE" --build c:/Users/xxx/ansi_c_projects/pir_test/build --config Debug --target all -- -j 10
[build] [ 14%] Linking C static library libpir_driver.a
[build] [ 28%] Building CXX object googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.obj
[build] [ 28%] Built target pir_driver
[build] [ 42%] Linking CXX static library ..\lib\libgtestd.a
[build] [ 42%] Built target gtest
[build] [ 57%] Building CXX object googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.obj
[build] [ 71%] Linking CXX static library ..\lib\libgtest_maind.a
[build] [ 71%] Built target gtest_main
[build] [ 85%] Building CXX object test/CMakeFiles/pir_test.dir/pir_test.cpp.obj
[build] [100%] Linking CXX executable pir_test.exe
[build] CMakeFiles\pir_test.dir/objects.a(pir_test.cpp.obj): In function `PIR_Timer_Test_Start_Test::TestBody()':
[build] C:/Users/xxx/ansi_c_projects/pir_test/test/pir_test.cpp:13: undefined reference to `xTaskGetTickCount'
[build] collect2.exe: error: ld returned 1 exit status
[build] mingw32-make.exe[2]: *** [test\CMakeFiles\pir_test.dir\build.make:108: test/pir_test.exe] Error 1
[build] mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:1004: test/CMakeFiles/pir_test.dir/all] Error 2
[build] mingw32-make.exe: *** [Makefile:113: all] Error 2

标签: c++gcccmakeg++c99

解决方案


它不起作用的原因是您在 main 中有一个错字CMakeLists.txt:您定义了变量Source,但Sources在填充pir_driver目标源时使用了变量。因此 .c 文件未编译,链接器无法找到其中定义的符号。

缺少的 .c 文件也是您首先需要手动设置链接器语言的原因。添加源文件后,您可以删除该set_target_properties(${This} PROPERTIES LINKER_LANGUAGE C)行,因为 CMake 将根据源文件的扩展名自行确定。

为避免将来出现此类问题,您可以使用

add_library(pir_driver STATIC)
target_sources(pir_driver
  PRIVATE
    pir_driver.h
    pir_driver.c
)

而不是 CMake 变量来收集 CMake 3.11 及更高版本中的源和标头。


推荐阅读