我想使用CMake设置项目,以便可以使用TDD进行开发,这意味着包括并测试内部标头。但是,使用CMake正确设置该库会在我的单元测试中隐藏这些实现细节(对于外部使用也是正确的)。
给出如下文件和文件夹结构:
Foo
|-- include
| `-- Foo
| `-- Foo.h
|-- CmakeLists.txt
|-- src
| |-- Bar
| | |-- Bar.h
| | `-- Bar.cpp
| |-- Baz
| | |-- Baz.h
| | `-- Baz.cpp
| |-- Foo.cpp
| `-- CMakeLists.txt
`-- test
|-- Bar
| `-- BarTest.cpp
|-- Baz
| `-- BazTest.cpp
|-- FooTest.cpp
`-- CMakeLists.txt
Foo / CMakeLists.txt
project(Foo)
include(CTest)
add_subdirectory(src)
if(BUILD_TESTING)
add_subdirectory(test)
endif()
Foo / src / CMakeLists.txt
add_library(Foo)
target_include_directories(Foo
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)
target_sources(Foo
PRIVATE
Foo.cpp
Bar/Bar.cpp
Baz/Baz.cpp
)
Foo / test / CMakeLists.txt
find_package(Catch2 REQUIRED)
include(Catch)
add_executable(FooTest
FooTest.cpp
Bar/BarTest.cpp # This file can't #include "Bar/Bar.h"
Baz/BazTest.cpp # This file can't #include "Baz/Baz.h"
)
target_link_libraries(FooTest
PRIVATE
Foo
Catch2::Catch2
)
现在的问题是,FooTest与Foo链接的方式与其他项目在需要Foo库作为依赖项时所采用的方式相同。这就产生了一个问题,我无法在包含文件Bar/BarTest.cpp
和Baz/BazTest.cpp
的{{1}}和#include "Bar/Bar.h"
中运行单元测试。
在我看来,理想的解决方案是能够为Foo获取一个内部#include "Baz/Baz.h
目标,该目标包括PUBLIC在内的所有内容,然后我可以对其进行测试。但是,安装后,内部标头是私有的,只有shortcut
中的文件是公共的。
我看到的解决方案是创建许多子目标,并仅包含每次测试所需的内容。但这似乎很麻烦,并且在非常模块化的设置中不适用于像柯南这样的软件包管理器。
其他解决方案是创建一个重复的Foo目标,其中所有内容都是公共的,但这需要我将所有内容编写两次。听起来对我来说是肮脏的方式。
我想到的最后一个解决方案是创建一个内部目标FooInternal,将每个标头和源都设置为public,然后FooTest可以链接到该目标。然后将包装库创建为Foo,它与FooInternal链接为私有,但将include/Foo/
文件夹设置为公共头。
但这需要Foo作为接口目标,然后将没有任何include/Foo
导出,需要我创建自定义逻辑来重命名,或者以某种方式设置CMake以将libFoo
用作正确的lib文件。同样,这听起来很脏,我不确定这在实践中如何工作。
我是否遗忘了任何明显的解决方案,或者有人对这个问题有好的解决方案?
答案 0 :(得分:0)
edit3: edit2的解决方案实际上不适用于包含多个库的构建树,因为它使目标可以访问链接的目标内部标头。 布拉德·金(Brad King)在Kitwares CMake gitlab上最终使用的解决方案是
add_library(foo foo.c)
target_include_directories(foo PUBLIC "$<BUILD_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:FOO_PRIVATE>>:/path/to/foo/private/include>>")
set_property(TARGET foo PROPERTY FOO_PRIVATE 1)
add_executable(test_foo test_foo.c)
target_link_libraries(test_foo foo)
set_property(TARGET test_foo PROPERTY FOO_PRIVATE 1)
来源:https://gitlab.kitware.com/cmake/cmake/issues/19048
edit2:最终的解决方案非常简单,那就是将包含路径设置为
target_include_directories(Foo
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
)
edit1:看完视频链接后,显示我最近进行的编程和测试太少,而面向devop的工作却过多。 我需要能够测试内部标头。回到有关如何使用给定设置使用CMake正确测试的原始问题。当我找到令人信服的解决方案时,将更新此答案。
原文:在听过Superlokkus对cpplang松弛的评论和讨论之后,似乎最好不要测试内部标头。 如果使用公共头文件和最里面的.cpp文件的测试之间的抽象数量太大,请将其拆分为独立的库。