如何复制cmake目标

Mat*_*szL 6 cmake

我正在我的 cmake 项目中编写函数,该函数需要从一个目标创建两个目标,并稍微更改其中之一:

option(BORG_STRIP_TEST_BINARIES OFF "Strip symbols from test binaries to reduce disk space usage" )
function(add_borg_test target)
    add_test(${target} ${target} --gtest_color=yes)
    if(BORG_STRIP_TEST_BINARIES)
        # copy target, but make it optional
        duplicate_target(FROM ${target} TO ${target}_debug )
        set_target_properties(${target}_debug PROPERTIES EXCLUDE_FROM_ALL TRUE)
        # alter
        target_link_options(${target} PRIVATE -s)
    endif()
endfunction()
Run Code Online (Sandbox Code Playgroud)

所以这应该是这样工作的:

  1. 我创建使用 gtest 的二进制目标。设置所有target_link_libraries一切。示例名称example-utests
  2. 相反添加通用add_test,我使用自定义add_borg_test
  3. 现在example-utests与标志链接-s并包含在all目标中。
  4. example-utests_debug不包含在all目标中,但当明确请求时,它链接时不带-s.

如何实现duplicate_target上面的代码片段?

sta*_*all 0

我的第一直觉(抱歉)是质疑为什么要这样做。我不是你,我不知道你的背景,所以问问你自己:你确定仅仅通过生成多个构建系统并为每个构建系统指定单独的配置选项就不能实现你想要的吗?毕竟,CMake 的整个设计就是为了让生成构建系统变得容易。


话虽这么说,如果您确信您有充分的理由想要在同一构建系统中复制/克隆/复制目标定义,那么请按照 Brad King(CMake 维护者之一)在此邮件线程中的建议进行操作:

没有内置的方法可以做到这一点,尽管您可能可以使用从原始文件中读取目标属性的宏来接近,以便使用适当的命令重现它们。

使用如何获取目标的所有属性可能会有所帮助。请注意,我在我的回答帖子中列出了一些重大限制。我所知道的最佳解决方案仅允许读取内置到 CMake 目标属性,而不允许读取您或任何其他 CMake 配置代码自定义定义的任何属性。因此,同样的限制也适用于这里的解决方案,大致如下:

execute_process(COMMAND "${CMAKE_COMMAND}" "--help-property-list" "${CMAKE_BINARY_DIR}/--help-property-list.txt")
file(STRINGS "${CMAKE_BINARY_DIR}/--help-property-list.txt" property_list)
function(copy_target_props src_target dest_target)
  set(config_types "${CMAKE_CONFIGURATION_TYPES}")
  if(NOT DEFINED CMAKE_CONFIGURATION_TYPES)
    set(config_types "Release;Debug;RelWithDebInfo;MinSizeRel")
  endif()
  foreach(prop_name ${property_list})
    if("${prop_name}" MATCHES "(^LOCATION)|^VS_DEPLOYMENT_LOCATION$|^MACOSX_PACKAGE_LOCATION$|^CXX_MODULE_SETS$|^HEADER_SETS$|^IMPORTED_GLOBAL$|^INTERFACE_CXX_MODULE_SETS$|^INTERFACE_HEADER_SETS$|^NAME$|^TYPE$")
      continue()
    endif()
    if("${prop_name}" MATCHES "<CONFIG>")
      foreach(config ${config_types})
        string(REPLACE "<CONFIG>" "${config}" config_prop_name "${prop_name}")
        get_target_property(prop_val "${src_target}" "${config_prop_name}")
        if(NOT "${prop_val}" STREQUAL "prop_val-NOTFOUND")
          #message("${config_prop_name}: ${prop_val}")
          set_property(TARGET "${dest_target}" PROPERTY "${config_prop_name}" "${prop_val}")
        endif()
      endforeach()
    else()
      get_target_property(prop_val "${src_target}" "${prop_name}")
      if(NOT "${prop_val}" STREQUAL "prop_val-NOTFOUND")
        #message("${prop_name}: ${prop_val}")
        set_property(TARGET "${dest_target}" PROPERTY "${prop_name}" "${prop_val}")
      endif()
    endif()
  endforeach()
  set(prop_name "IMPORTED_GLOBAL")
  get_target_property(prop_val "${src_target}" "${prop_name}")
  if((NOT "${prop_val}" STREQUAL "prop_val-NOTFOUND") AND "${prop_val}")
    #message("${config_prop_name}: ${prop_val}")
    set_property(TARGET "${dest_target}" PROPERTY "${prop_name}" "${prop_val}")
  endif()
endfunction()

# example usage
add_executable(foo1 foo.c)
add_executable(foo2)
copy_target_props(foo1 foo2)
Run Code Online (Sandbox Code Playgroud)

我太懒了,无法编写一个不需要手动定义第二个目标的实际复制函数。但是您可以通过读取TYPE源目标的 target 属性,然后对所有add_executable/变体进行 if-elsing 来做到这一点(在首次定义目标( sourceadd_library )后,您无法更改目标的类型)。


还有另一种适用性有限的技术 - 与其说是为了复制目标,不如说是为了使通用目标属性设置可重用(同样,适用性有限):在接口库上定义 INTERFACE 属性,然后将多个相似的目标链接到接口目标因此它们从接口目标继承值。


最后一点:我有一个项目,我使用 CMake 来驱动 PGO 两个阶段的训练和优化构建,我在其中创建了项目ExternalProject本身,并为训练和使用阶段定义了两个自定义构建配置,这需要不同的编译标志。也就是说(相当无益),您所采取的方法的适用性可能取决于上下文。