C++ 在子目录中调用目标链接库的替代方法 案例:

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既不知道测试细节

我已经在一个单独的.cmake脚本中声明了一个函数
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" )
# ...