C++ 在子目录中调用目标链接库的替代方法 案例:
我已经在一个单独的.cmake脚本中声明了一个函数C++ 在子目录中调用目标链接库的替代方法 案例:,c++,cmake,code-coverage,gcov,lcov,C++,Cmake,Code Coverage,Gcov,Lcov,我已经在一个单独的.cmake脚本中声明了一个函数setup\u target\u,该脚本添加到cmake\u模块路径,它为代码覆盖率分析准备了一个目标(mylib)设置覆盖范围的目标从子目录调用到mylib(mylib\u测试) 要求与测试和代码覆盖率相关的所有事情(仅针对该目标)都发生在mylib/tests和setup\u target\u for\u coverage,并且从mylib/CMakeLists.txt中,我们只添加测试子目录,不添加其他内容。最后,mylib既不知道测试细节
setup\u target\u,该脚本添加到cmake\u模块路径
,它为代码覆盖率分析准备了一个目标(mylib
)<代码>设置覆盖范围的目标从子目录调用到mylib
(mylib\u测试
)
要求与测试和代码覆盖率相关的所有事情(仅针对该目标)都发生在mylib/tests
和setup\u target\u for\u coverage
,并且从mylib/CMakeLists.txt
中,我们只添加测试子目录,不添加其他内容。最后,mylib
既不知道测试细节也不知道代码覆盖率的存在,它只是“盲目”调用add\u子目录(tests)
例子:
看起来是这样的:
mylib:
# ./mylib/CMakeLists.txt:
project( mylib )
add_library( mylib main.cpp )
# This is all mylib should be aware of, everything else is hidden
add_subdirectory( tests )
mylib_测试:
# ./mylib/tests/CMakeLists.txt:
project( mylib_tests )
# ...
include(code-coverage)
setup_target_for_coverage(
TARGET mylib
TEST_RUNNER mylib_tests
)
代码覆盖范围:
# ./cmake/code-coverage.txt:
function(setup_target_for_coverage)
# Parse arguments...
# Setting compile flags: Works as expected
target_compile_options( ${args_TARGET}
PRIVATE
-g -O0 --coverage
)
# Setting linker flags: THIS FAILS <---------------
target_link_libraries( ${args_TARGET}
PRIVATE
--coverage
)
add_custom_target( ${args_TARGET}_coverage}
# Setup lcov, run "TEST_RUNNER", generate html...
COMMAND ...
)
endfunction()
我试图通过直接使用set\u属性
来解决这个问题
set_property(
TARGET ${TARGET}
APPEND_STRING PROPERTY LINK_FLAGS "--coverage"
)
无济于事。即使在同一个CMakeLists.txt中,也会出现以下错误:
"undefined reference to `__gcov_merge_add'"
如果target\u link\u libraries
移动到/mylib/CMakeLists.txt
,它就可以工作了,但正如前面提到的,这不符合我的要求
有什么想法吗?用宏
替换功能
:
macro(setup_target_for_coverage)
[...]
endmacro()
CMake宏与C宏类似:您可以将其视为文本替换,因此其行为就像代码位于原始文件中一样。将注释转换为答案。正如您所强调的,您只能对同一目录范围中定义的目标调用target\u link\u libraries()
。调用add_subdirectory()
时,您输入了一个新的目录范围,因此遇到了您所问的问题
另一方面,include()
命令不会创建新的目录范围。这有两个直接相关的影响:
- 在包含目录的文件中,您仍然可以为包含目录范围内的目标调用
target\u link\u libraries()
CMAKE\u CURRENT\u SOURCE\u DIR
的值不会更改,因此您可能希望在包含的文件中使用CMAKE\u CURRENT\u LIST\u DIR
。请注意,CMAKE\u CURRENT\u BINARY\u DIR
没有等价物,它也不会改变
典型的模式可能是这样的:
mylib/CMakeLists.txt:
"undefined reference to `__gcov_merge_add'"
mylib/tests/CMakeLists.txt:
"undefined reference to `__gcov_merge_add'"
也许至少与此相关,你也可能会发现书中的想法很有趣。它展示了如何跨目录管理源和目标,涉及到add_子目录()
与include()
的讨论。您能给出一个建议吗?从你的表现来看,我不清楚你想做什么。你能给出“设置函数”的代码吗?或者至少给出有问题的target\u link\u libraries()!我昨晚写这封信时眼睛很疲劳,意识到它相当模糊。。。我会尽快编辑的。在CMake术语中,“当前目录”仅与add_subdirectory()
一起引入,它不区分函数在包含文件中定义时的情况。这种用例(从函数调用target\u link\u库
,未在当前目录中定义)适用于CMake 3.4。@Tsyvarev哦,我的坏!我的例子有一点在于,覆盖率的setup\u target\u实际上是在tests
子目录中运行的。。!原因是直到这里我才知道测试目标的目标名称(mylib不知道测试做什么)。我将修复这个示例。您的需求是否可以稍微放宽一点,允许使用include()
而不是add\u子目录()
?如果是这样,则允许使用target\u link\u libraries()
。主要的缺点是,在tests
目录中,您必须记住CMake将当前源目录视为mylib
,而不是mylib/tests
(与相应的二进制目录类似)。很抱歉,我的示例中遗漏了一些关键信息。查看更新的问题!谢谢这确实是一个有效的替代方案,只需稍作修改。不过,这种方法有一点让我感到困扰,那就是它将更改向上推,一直推到mylib
。就我个人而言,我宁愿通过code coverage.cmake
中的“hack”来解决它(类似于set\u property
,如果它能像广告那样工作的话)。这样,增加的复杂性将对更高级别的实体隐藏。如果我不能很快找到这样的解决方案,我会把它作为答案!我同意这个解决方案!这是(国际海事组织)最干净的“变通办法”,不会使事情变得太复杂。见实施。
add_executable( someTest "${CMAKE_CURRENT_LIST_DIR}/someTest.cpp" )
# ...