CMake为何忽略add_custom_command?问题排查求助
问题背景
在CMake 3.18.5项目中,为每个目标添加了自定义命令以生成包含目录文件,但约四分之一的目标对应的*_includes.txt规则未出现在build.ninja中,尽管配置阶段能看到每个目标的调试日志。相关代码如下:
set(TARGET_INCLUDES $<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>) set(INCL_FILE "project_includes/${target}_includes.txt") set( INC_WRITER_FLAGS --include-path ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES} ${TARGET_INCLUDES} --output ${CMAKE_BINARY_DIR}/${INCL_FILE} ) message("!!!!!!!!!!!!! generating rule for ${CMAKE_BINARY_DIR}/${INCL_FILE}") add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/${INCL_FILE} COMMAND ${Python3_EXECUTABLE} ${INCLUDE_WRITER_PATH} ${INC_WRITER_FLAGS} VERBATIM)
可能的原因及排查方向
自定义命令输出未被任何目标依赖
CMake仅会保留被构建目标直接或间接依赖的add_custom_command规则。如果生成的${CMAKE_BINARY_DIR}/${INCL_FILE}没有被其他目标(如可执行文件、库)通过add_dependencies引用,或未作为源文件关联到目标,CMake会判定该输出为“无意义”,不会加入构建系统。目标INCLUDE_DIRECTORIES属性未正确展开
使用的生成表达式$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>在CMake 3.18.5中,若目标的包含目录未完全配置完成,可能展开为空或无效值。建议在add_custom_command前添加message(STATUS "Target ${target} includes: ${TARGET_INCLUDES}"),检查属性是否正确获取。重复的输出文件路径
若不同目标生成的${INCL_FILE}重名(如目标名称冲突),CMake仅会保留第一个对应的add_custom_command,后续命令会被静默忽略。验证每个目标的输出文件路径是否唯一。目标类型为INTERFACE/ALIAS库
INTERFACE库无实际构建产物,ALIAS库仅为其他目标的别名,这类目标的INCLUDE_DIRECTORIES属性处理逻辑与普通库/可执行文件不同,可能导致关联的自定义命令不被生成。检查未生效的目标是否属于这两类。输出目录未预先创建
若${CMAKE_BINARY_DIR}/project_includes在配置阶段不存在,CMake可能无法正确识别输出路径的有效性。可在add_custom_command前添加file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/project_includes)确保目录存在。VERBATIM模式下的参数解析bug
CMake 3.18.5的VERBATIM模式对含空格的路径(如CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES中的路径)可能存在解析问题,导致命令无效。可临时移除VERBATIM测试,或手动为含空格的路径添加引号。目标被标记为EXCLUDE_FROM_ALL
若目标设置了EXCLUDE_FROM_ALL属性,且其关联的自定义命令未被非EXCLUDE_FROM_ALL的目标依赖,该命令会被排除在构建系统之外。检查未生效目标的属性配置。
内容的提问来源于stack exchange,提问作者Crazy Sage

