如何在CMakeLists.txt中定义通用文件转换规则(替代Makefile模式规则)?
如何在CMakeLists.txt中定义通用文件转换规则(替代Makefile模式规则)?
嗨,我明白你想要用CMake实现Makefile里那种模式规则的效果——不用逐个指定文件,只要是.sql文件就自动转换成对应的目标文件对吧?其实CMake没有直接和Makefile模式规则完全等价的语法,但我们可以通过循环配合add_custom_command来实现同样的通用转换效果,下面就一步步来教你怎么做:
核心思路
我们会先收集所有需要处理的.sql文件,然后对每个文件单独定义转换规则,最后把生成的文件加入到主程序的构建目标中。这样只要新增.sql文件,CMake就能自动识别并处理它们(如果用GLOB收集的话,注意新增文件后需要重新运行CMake)。
具体实现代码
下面是对应你需求的CMake配置示例,我们会把.sql文件处理成C风格字符串的.c文件,再由CMake自动编译成目标文件链接到主程序:
# 1. 收集当前目录下所有的.sql文件(如果需要子目录可以用GLOB_RECURSE,或者更严谨地手动列出文件) file(GLOB SQL_SOURCES *.sql) # 2. 初始化一个变量,用来存储所有生成的C文件 set(GENERATED_C_SOURCES "") # 3. 遍历每个.sql文件,定义转换规则 foreach(sql_file ${SQL_SOURCES}) # 获取文件名(不含路径和后缀),用来作为生成的C字符串变量名 get_filename_component(sql_name ${sql_file} NAME_WE) # 定义输出的C文件路径(放在构建目录下,避免污染源码目录) set(output_c ${CMAKE_CURRENT_BINARY_DIR}/${sql_name}_sql.c) # 添加自定义命令:将sql文件处理成C风格字符串的.c文件 add_custom_command( OUTPUT ${output_c} # 生成的输出文件 COMMAND sed -e 's/--.*$$//' -e '/^$$/d' ${sql_file} | xxd -i -n ${sql_name} > ${output_c} DEPENDS ${sql_file} # 依赖的源文件,sql文件修改时会重新生成 COMMENT "Generating C string from ${sql_file}" # 构建时显示的提示信息 ) # 把生成的C文件加入到全局列表中 list(APPEND GENERATED_C_SOURCES ${output_c}) endforeach() # 4. 定义主程序目标,包含源码和所有生成的C文件 add_executable(your_main_app main.c ${GENERATED_C_SOURCES})
如果你想直接生成目标文件(.o)
如果你想跳过生成.c文件的步骤,直接生成.o文件,可以把上面的转换命令改成这样:
foreach(sql_file ${SQL_SOURCES}) get_filename_component(sql_name ${sql_file} NAME_WE) set(output_o ${CMAKE_CURRENT_BINARY_DIR}/${sql_name}_sql.o) add_custom_command( OUTPUT ${output_o} # 用CMake自带的C编译器变量替代硬编码的gcc,提升跨平台性 COMMAND sed -e 's/--.*$$//' -e '/^$$/d' ${sql_file} | xxd -i -n ${sql_name} | ${CMAKE_C_COMPILER} -c -x c -o ${output_o} - DEPENDS ${sql_file} COMMENT "Compiling object file from ${sql_file}" ) list(APPEND GENERATED_OBJECTS ${output_o}) endforeach() # 直接把生成的目标文件加入到可执行目标中 add_executable(your_main_app main.c ${GENERATED_OBJECTS})
关键说明
- CMake是基于目标的构建系统,它的
add_custom_command是绑定到具体输出文件的,不像Makefile的模式规则那样是全局的,但通过循环遍历文件,我们能实现几乎一样的通用效果。 - 把生成的文件放在
CMAKE_CURRENT_BINARY_DIR(构建目录)下,能避免修改源码目录,保持源码干净。 - 如果不想用
file(GLOB)(因为新增文件后需要重新运行CMake),可以手动列出所有.sql文件,比如set(SQL_SOURCES file1.sql file2.sql),这样更严谨。
备注:内容来源于stack exchange,提问作者White Owl
相关产品推荐
相关产品推荐

