如何以编程方式迭代所有CMake目标?

30

在顶层CMakeLists.txt中是否有一种方法可以获取CMake项目的所有目标,即以编程方式迭代所有目标?

我想这样做的原因是为了将一些XCode特定的设置应用于每个目标...

if (CMAKE_GENERATOR MATCHES "Xcode")
    include(sanitize_xcode)
    sanitize_xcode(myTarget)
endif()

供参考-清洁模块如下. .

macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
    set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
endmacro (set_xcode_property)

macro (sanitize_xcode TARGET)
    set_xcode_property(${TARGET} GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
    set_xcode_property(${TARGET} GCC_GENERATE_DEBUGGING_SYMBOLS[variant=MinSizeRel] "NO")
    set_xcode_property(${TARGET} GCC_GENERATE_DEBUGGING_SYMBOLS[variant=RelWithDebInfo] "YES")
    set_xcode_property(${TARGET} GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] "NO")

    set_xcode_property(${TARGET} COPY_PHASE_STRIP[variant=Debug] "NO")
    set_xcode_property(${TARGET} COPY_PHASE_STRIP[variant=MinSizeRel] "YES")
    set_xcode_property(${TARGET} COPY_PHASE_STRIP[variant=RelWithDebInfo] "NO")
    set_xcode_property(${TARGET} COPY_PHASE_STRIP[variant=Release] "YES")

    set_xcode_property(${TARGET} GCC_OPTIMIZATION_LEVEL[variant=Debug] "0")
    set_xcode_property(${TARGET} GCC_OPTIMIZATION_LEVEL[variant=MinSizeRel] "s")
    set_xcode_property(${TARGET} GCC_OPTIMIZATION_LEVEL[variant=RelWithDebInfo] "3")
    set_xcode_property(${TARGET} GCC_OPTIMIZATION_LEVEL[variant=Release] "3")

    set_xcode_property(${TARGET} IPHONEOS_DEPLOYMENT_TARGET[variant=Debug] "7.0")
    set_xcode_property(${TARGET} IPHONEOS_DEPLOYMENT_TARGET[variant=MinSizeRel] "7.0")
    set_xcode_property(${TARGET} IPHONEOS_DEPLOYMENT_TARGET[variant=RelWithDebInfo] "7.0")
    set_xcode_property(${TARGET} IPHONEOS_DEPLOYMENT_TARGET[variant=Release] "7.0")
endmacro (sanitize_xcode)

你的意思是在你的CMake脚本中以编程方式迭代目标吗? - Tamás Szelei
有什么目的?(嗅探X-Y问题。)你想做的任何事情最好在CMakeLists.txt本身完成。 - DevSolar
2
@DevSolar 请查看修改。 - learnvst
请问您能否提供 sanitize_xcode() 的代码?您是添加了 POST_BUILD 步骤还是只添加了编译器选项?如果是后者,那么就不需要迭代所有目标。 - Florian
谢谢。仅查看XCODE_ATTRIBUTE_<an-attribute>目标属性,将根级别设置等效的CMAKE_XCODE_ATTRIBUTE_<an-attribute>变量是否足以应用于所有目标? - Florian
3个回答

38

针对Florian的答案BUILDSYSTEM_TARGETS并不是真正的全局属性,而是一个目录作用域的属性。目前有一个增强请求开放,请求一个真正的全局属性。使用SUBDIRECTORIES属性可以在当前目录的范围内递归检索所有目标,并使用以下函数:

function(get_all_targets var)
    set(targets)
    get_all_targets_recursive(targets ${CMAKE_CURRENT_SOURCE_DIR})
    set(${var} ${targets} PARENT_SCOPE)
endfunction()

macro(get_all_targets_recursive targets dir)
    get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
    foreach(subdir ${subdirectories})
        get_all_targets_recursive(${targets} ${subdir})
    endforeach()

    get_property(current_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS)
    list(APPEND ${targets} ${current_targets})
endmacro()

get_all_targets(all_targets)
message("All targets: ${all_targets}")

7
哦天啊,我爱你,这解决了一整天困扰我的问题。+1 - Sprite
1
这太棒了,我一直想找一个方法来做这件事,但基本上已经放弃了。 - Andrew W
2
需要注意的是,此解决方案将生成一个包含所有目标的列表,包括那些已经使用以下方式明确排除在“all”之外的目标:add_executable(some_target EXCLUDE_FROM_ALL some_target.c)这对于添加一个目标非常有用,该目标将构建真正的全部,甚至包括被排除的目标:add_custom_target(really_all DEPENDS ${all_targets}) - n0dus

7

将我的评论转换成答案

想要一个所有目标的列表是很久以前就有的愿望,但是全局属性 TARGETS 还没有实现 (截至 2016 年 5 月,参见 "列出所有目标" 的讨论)。

编辑:现在已经实现了:全局 BUILDSYSTEM_TARGETS 属性已经随 CMake 3.7 发布。

因此,您可以使用 CMake 脚本自己实现这一点 - 如 @DevSolar 所评论/回答的那样,或者像 这里 - 但我在使用 CMake 工作的时间里学到,也可以全局地更改很多目标属性。例如,大多数目标属性默认为相当于全局变量设置的值。

你可以在你的情况下利用这个方法并通过将以下内容添加到你的全局 CMakeLists.txt 文件来解决问题:
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=MinSizeRel] "NO")
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=RelWithDebInfo] "YES")
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] "NO")

set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=MinSizeRel] "YES")
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=RelWithDebInfo] "NO")
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Release] "YES")

set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=Debug] "0")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=MinSizeRel] "s")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=RelWithDebInfo] "3")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=Release] "3")

set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET[variant=Debug] "7.0")
set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET[variant=MinSizeRel] "7.0")
set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET[variant=RelWithDebInfo] "7.0")
set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET[variant=Release] "7.0")

参考文献


3
不,全局的 BUILDSYSTEM_TARGETS 没有被添加,它是一个目录属性。这里有一个 rfe - ceztko
2
通过使用 BUILDSYSTEM_TARGETSSUBDIRECTORIES,可以递归检索当前目录范围内定义的目标。请参见我的答案 - ceztko

2
如果你想查看一系列目标,请先在你的CMakeLists.txt文件中进行设置以提供该列表。
if ( CMAKE_GENERATOR MATCHES "Xcode" )
    include(sanitize_xcode)
endif()

# A list of executables to build
set( project_EXECUTABLES
     foo
     bar
   )

# List of sources for each executable, following some naming scheme

# foo
set( EXE_foo_SOURCES
     foo/main.c
   )

# bar
set( EXE_bar_SOURCES
     bar/main.c
   )

# For each executable in the list...
foreach( exe ${project_EXECUTABLES} )
    # declare the target...
    add_executable( ${exe} ${EXE_${exe}_SOURCES} )

    # ...and do whatever additional configuration you need
    if ( CMAKE_GENERATOR MATCHES "Xcode" )
        sanitize_xcode( ${exe} )
    endif()
endforeach()

我发现在开始时有一系列的set()命令来设置所有内容并在最后完成所有“魔法”通常是一个好技巧。实际上,在我的可重用的CMake框架中,我在我的CMakeLists.txt中使用set(),然后include()一个包含所有“魔法”的文件。如果我添加/更改源文件,则只需“touch”CMakeLists.txt,如果我修改了“魔法”,则“touch”另一个文件。在我看来,这样更容易维护。 - DevSolar
这不是一个答案,因为目标列表可能是未知/不可预测的。 - ceztko
@ceztko:1)如果你的目标列表是不可预测的,那么你有其他问题。2)答案展示了一种设置要迭代的目标列表的方法。3)BUILDSYSTEM_TARGETS是在Florian和我写下我们(最初的)答案半年后引入的,因此你几乎不能责怪我们在写下答案时没有利用它。当时,这些就是问题的答案。更好的机制的后来出现可能使这个答案有点过时,但“不是答案”是不必要的。 - DevSolar
@ceztko :哦,我想我现在明白了。你也把 CMakeLists.txt 放在 子目录 中,这就是为什么你认为目标列表是“未知/不可预测”的原因吗?嗯,我不这样做,因为我来自“递归式 make 被认为是有害的”思想流派,只有一个顶层的 CMakeLists.txt。所以我们在这里面持有不同的假设。 - DevSolar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接