如何在CMake中根据目标名称列表获取对应的目标文件名列表?
解决CMake批量获取可执行目标文件路径的问题
我来帮你搞定这个CMake的问题~你遇到的target_file-NOTFOUND其实是因为配置阶段和生成阶段的时机差异,以及你用错了属性,下面给你详细解释和解决方法:
为什么你的方法会失败?
你用get_target_property获取RUNTIME_OUTPUT_NAME有两个核心问题:
RUNTIME_OUTPUT_NAME只是可执行文件的文件名(默认和目标名一致,除非你手动设置过),并不是完整的文件路径。- 更关键的是:
$<TARGET_FILE:target_x>是生成器表达式,它是在CMake的生成阶段(也就是生成Makefile/VS工程之后)才会被解析成实际路径的;而get_target_property是在配置阶段(你运行cmake ..的时候)执行的,这时候CMake还没确定最终的输出路径(比如Debug/Release的子目录、平台相关的后缀),所以自然拿不到有效结果。
正确的批量处理方式
方法一:用生成器表达式批量收集(推荐,最可靠)
我们不需要在配置阶段强行解析路径,而是把生成器表达式本身存入列表,让CMake在生成阶段自动替换成实际路径。这种方式能完美适配跨平台、不同构建类型的路径差异。
示例代码:
set(EXAMPLE_EXECUTABLES_TARGETS "target_a" "target_b" "target_c" "target_d" "target_e") set(EXAMPLE_EXECUTABLES "") foreach(target ${EXAMPLE_EXECUTABLES_TARGETS}) # 把生成器表达式添加到列表,不做即时解析 list(APPEND EXAMPLE_EXECUTABLES "$<TARGET_FILE:${target}>") endforeach() # 举个例子:用自定义目标打印所有可执行文件路径(生成阶段会自动解析表达式) add_custom_target(print_all_executables COMMAND ${CMAKE_COMMAND} -E echo "All executable paths: ${EXAMPLE_EXECUTABLES}" VERBATIM )
当你构建print_all_executables目标时,就能看到每个目标的完整可执行文件路径了。这种方式也适用于add_custom_command等需要用到可执行文件路径的场景。
方法二:配置阶段获取路径(不推荐,仅特殊场景使用)
如果你确实需要在配置阶段(比如cmake ..时)看到路径,可以结合目标的输出目录和平台后缀来拼接,但要处理多配置生成器(比如VS)的情况:
set(EXAMPLE_EXECUTABLES_TARGETS "target_a" "target_b" "target_c" "target_d" "target_e") foreach(target ${EXAMPLE_EXECUTABLES_TARGETS}) # 获取目标的运行时输出目录(优先目标自定义的,其次全局默认) get_target_property(runtime_dir ${target} RUNTIME_OUTPUT_DIRECTORY) if(NOT runtime_dir) set(runtime_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) endif() # 处理多配置生成器(如VS)的不同构建类型目录 if(CMAKE_CONFIGURATION_TYPES) foreach(config ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${config} CONFIG_UPPER) # 拼接完整路径:目录 + 构建类型子目录 + 目标名 + 平台后缀 set(target_file "${runtime_dir}/${config}/${target}${CMAKE_EXECUTABLE_SUFFIX}") message(STATUS "Target ${target} (${config}): ${target_file}") endforeach() else() # 单配置生成器(如Makefile)直接拼接 set(target_file "${runtime_dir}/${target}${CMAKE_EXECUTABLE_SUFFIX}") message(STATUS "Target ${target}: ${target_file}") endif() endforeach()
这种方法的缺点是需要手动处理各种特殊情况(比如自定义输出文件名、不同配置的输出目录),不如生成器表达式灵活可靠。
总结
优先选择生成器表达式的方式,它是CMake设计用来处理这类跨阶段路径问题的最佳实践,能帮你避免很多平台和构建类型的坑。
内容的提问来源于stack exchange,提问作者CiaranWelsh
相关产品推荐
相关产品推荐

