【问题标题】:How do I correctly pass CMake list (semicolon-sep) of flags to set_target_properties?如何正确地将标志的 CMake 列表(分号-sep)传递给 set_target_properties?
【发布时间】:2012-07-20 15:33:43
【问题描述】:

CMake 列表本质上只是用分号分隔的字符串,但如果将这样的变量传递给命令,它确实会扩展为多个参数 - 例如,

set(FLAGS f1 f2 f3)
# now FLAGS == 'f1;f2;f3'
add_custom_command(
  ...
  COMMAND my_cmd ${FLAGS}
  ...
)

会正确调用my_cmd f1 f2 f3

现在如果我用

set_target_properties(
  myTarget PROPERTIES
  LINK_FLAGS  "${LD_FLAGS}"
)

没有发生扩展,我最终得到一个包含分号的 LD_FLAG —— 没用,而不是将其扩展为以空格分隔的字符串。

有什么方法可以使当我将列表传递给 LINK_FLAGS 属性(或任何属性)时,它会扩展为多个参数,而不仅仅是一个?

谢谢, 丹

【问题讨论】:

    标签: cmake


    【解决方案1】:

    我不认为set_target_properties 可以自动进行扩展,但是您可以使用string (REPLACE ...) 将列表扩展为空格分隔的字符串:

    string (REPLACE ";" " " LD_FLAGS_STR "${LD_FLAGS}")
    set_target_properties(
      myTarget PROPERTIES
      LINK_FLAGS  "${LD_FLAGS_STR}"
    )
    

    【讨论】:

    • 这真的是最好的方法吗?为什么 CMake 设计为使用与其自己的set_target_properties 命令不兼容的列表格式?
    • 这种技术的主要问题通常是,如果任何标志包含空格,它们将导致问题。如果可能的话,需要进行一些转义以保留参数中的空格(例如,如果包含外部提供的文件名,可能包含空格)。
    • B+++T。它不起作用。 string (REPLACE ";" " " DEST ${SRC}) 将分号替换为...一个空字符串。只有这个有效:foreach(OPT ${LD_FLAGS}) set(LINK_FLAGS "${LINK_FLAGS} ${OPT}") endforeach()。这真的很有趣,除非这个 c++p 不是当今最流行的构建工具。
    • @Ethouris string (REPLACE ";" " " DEST "${SRC}") 工作;您似乎错过了最后一个论点的引号。也许所有这些 +s 都妨碍了?
    • 对。这个${SRC} 内部包含;,并且以这种形式,它在调用内部扩展了自身(因此替换甚至没有机会工作)。至少值得记住的是,cmake 会重复与 bash 和 perl 相同的愚蠢错误。
    【解决方案2】:

    要使用 cmake 列表作为列表,请使用

    ${LD_FLAG}
    

    对于使用 cmake 列表作为字符串,(即列表项用 ';' 分隔),使用

    "${LD_FLAG}"
    

    所以在你的情况下,只需删除 "" 就足够了。

    【讨论】:

    • 奇怪,但是这个对我不起作用,版本 3.9 :( set_target_properties called with incorrect number of arguments.
    • @Andry 如果在前面插入“MESSAGE("${LD_FLAG}")”会显示什么?
    • @Ding-Yi Chen 我没用那个。相反,我一直在使用一组 LINK_FLAGS_* 变量。这里的想法是尽量避免使用list as string。而是使用set(PROP_LIST "${PROP_LIST} ...")set_target_properties(... LINK_FLAGS_* "${PROP_LIST}") 之类的东西。尝试使用PROP_LIST 作为列表将破坏set_target_properties
    【解决方案3】:

    set_property 命令就是为此而设计的

    http://www.cmake.org/cmake/help/v3.0/command/set_property.html

    set_property(TARGET tgt PROPERTY LINK_FLAGS foo bar)
    

    【讨论】:

    • Steveire - 我错误地认为它不在 2.8.11 中,因为我试图将 set_target_properties(foo ...) 更改为 set_properties(TARGET foo ...)。但是现在我看到命令名称的复数形式(复数与单数)有所不同。正确的名称是set_property(以y 结尾)。
    • 是的,您可以按照此答案显示的方式使用 set_property(),但 CMake 将 LINK_FLAGS 视为纯字符串,而不是列表 - 这意味着在此答案中,链接传递了一个参数,@ 987654328@。很不幸。有趣的是,现在有一个 COMPILE_OPTIONS 属性是一个列表,但旧的 COMPILE_FLAGS 是一个普通字符串。
    【解决方案4】:

    我像字符串一样使用它

    set(FLAGS " f1 f2 f3")

    注意前面的空格,它允许您连接其他标志集。

    对于更复杂的项目,您也可以使用 双重扩展技巧来代替 if-else:

    set(GCC_FLAGS " -Wl,--relax")
    set(DIAB_FLAGS " -tPPCE500ES:cross")
    set(MSVC_FLAGS " /RAINBOW_CRAP)
    # ...
    # ...LINUX_FLAGS, WINDOWS_FLAGS, etc...
    
    
    set_target_properties(
      myTarget PROPERTIES
      LINK_FLAGS  "${${COMPILER}_FLAGS} ${${SYSTEM}_FLAGS}"
    )
    
    # COMPILER and SYSTEM is set somewhere else, in toolchain files for example
    

    【讨论】:

      【解决方案5】:
      separate_arguments(LD_FLAGS_AS_LIST  NATIVE_COMMAND  LD_FLAGS)
      
      set_target_properties(
        myTarget PROPERTIES
        LINK_FLAGS  "${LD_FLAGS_AS_LIST}"
      )
      

      【讨论】:

        【解决方案6】:

        在 cmake 3.x 中有一些方法

        顶级 CMakeLists.txt 文件如下所示:

        # The name of the included file could be anything,
        # it doesn't have to be called CMakeLists.txt
        include(foo/CMakeLists.txt)
        include(bar/CMakeLists.txt)
        
        add_executable(myApp ${myApp_SOURCES})
        

        子目录文件的结构如下:

        list(APPEND myApp_SOURCES
            ${CMAKE_CURRENT_LIST_DIR}/foo.cpp
            ${CMAKE_CURRENT_LIST_DIR}/foo_p.cpp
        )
        

        Enhanced source file handling with target_sources()

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-11
          • 2011-07-12
          • 2019-04-14
          • 1970-01-01
          • 2021-07-12
          相关资源
          最近更新 更多