这个问题是我之前的一个后续问题:如何将这种源生成器集成到CMake构建链中?
目前,C源文件是这样从XS生成的:
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${file_src_by_xs} PROPERTIES GENERATED 1)
add_custom_target(${file_src_by_xs}
COMMAND ${XSUBPP_EXECUTABLE} ${XSUBPP_EXTRA_OPTIONS} ${lang_args} ${typemap_args} ${file_xs} >${CMAKE_CURRENT_BINARY_DIR}/${file_src_by_xs}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${file_xs} ${files_xsh} ${_XSUBPP_TYPEMAP_FILES}
COMMENT "generating source from XS file ${file_xs}"
)
GENERATED
属性让cmake在配置时不检查这个源文件的存在,add_custom_target
让xsubpp
总是在每次编译时重新运行。总是重新运行的原因是因为xsubpp
即使失败也会生成一个不完整的源文件,所以有可能整个编译继续使用一个不完整的源文件。
我发现总是重新运行源生成器并重新编译它是费时的。所以我想让它只在依赖的XS文件被修改时才重新运行。但是,如果这样做,则必须删除生成的不完整源文件。
所以我的问题是:有没有办法删除生成的文件,只有当程序在编译时异常退出?
或更通用:是否有任何方法运行一个命令取决于另一个命令的退出状态在编译时?
你总是可以用你最喜欢的语言(例如Perl或Ruby)编写一个包装器脚本,它运行xsubpp并在命令失败时删除输出文件。这样你就可以确定如果它存在,它是正确的。
此外,我建议您使用add_custom_command
的OUTPUT
关键字来告诉CMake该文件是执行命令的结果。(而且,如果你这样做,你不需要手动设置GENERATED
属性)
受@Lindydancer回答的启发,我通过在一个目标中使用多个命令来达到目的,并且不需要编写外部包装器脚本。
set(source_file_ok ${source_file}.ok)
add_custom_command(
OUTPUT ${source_file} ${source_file_ok}
DEPENDS ${xs_file} ${xsh_files}
COMMAND rm -f ${source_file_ok}
COMMAND xsubpp ...... >${source_file}
COMMAND touch ${source_file_ok}
)
add_library(${xs_lib} ${source_file})
add_dependencies(${xs_lib} ${source_file} ${source_file_ok})
自定义目标器有3个命令。OK文件仅在xsubpp成功时存在,并且该文件作为库的依赖项添加。当xsubpp不成功时,对OK文件的依赖将强制重新运行自定义命令。
唯一的缺点是跨平台:不是所有的操作系统都有touch
和rm
,所以这两个命令的名称应该根据操作系统类型来决定。