0x00. 前言
在网上看别人做一些手工教程视频,经常能看到这样的评论:
脑子:我感觉我会了。
手:你行你来。
之前一直通过编译脚本去寻找代码入口,感觉我已经懂得CMake的语法了,直到今天寄己要写一个脚本去编译一个工程才发现,事情并不简单:脚本并没有按照我期望的去执行。
此工程需要用到Protocol Buffer,因此当代码构建的时候需要使用使用Protocol Buffer编译器去编译.proto
文件获得对应的生成文件。理论上,想要达到这个目的,我们只需要在CMakeLists.txt中使用add_custom_command
命令就可以可以生成对应的构建规则。但出人意料的是,这条命令并没有被执行,也就是说,并没有编译.proto
文件的规则生成,因此当最终使用Make去构建工程的时候,没能通过.proto
文件得到对应的源代码。
0x01. 踩雷
整个命令的使用如下面的代码所示,作用就是将位${REPO_ROOT}/protobuf/onnx-operators-ml.proto
以及${REPO_ROOT}/protobuf/onnx-ml.proto
这两个文件编译成C++头文件以及源文件,并存放到{REPO_ROOT}/src
目录下,其中${REPO_ROOT}
是项目的根目录,例如在我的例子中为/home/sunny/workspace/model-tool/
:
set(PROTOBUF_PROTOC_EXECUTABLE ${REPO_ROOT}/build/third_party/protobuf/cmake/protoc)
list(APPEND PROTO_FILES
"${REPO_ROOT}/protobuf/onnx-operators-ml.proto"
"${REPO_ROOT}/protobuf/onnx-ml.proto")
set(output_dir ${REPO_ROOT}/include)
set(protoc_include ${REPO_ROOT}/protobuf)
foreach(fil ${PROTO_FILES})
get_filename_component(abs_fil ${fil} ABSOLUTE)
get_filename_component(fil_we ${fil} NAME_WE)
list(APPEND ${srcs_var} "${output_dir}/${fil_we}.pb.cc")
list(APPEND ${hdrs_var} "${output_dir}/${fil_we}.pb.h")
add_custom_command(
OUTPUT "${output_dir}/${fil_we}.pb.cc"
"${output_dir}/${fil_we}.pb.h"
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --cpp_out ${output_dir} -I${protoc_include} ${abs_fil}
DEPENDS ${abs_file}
COMMENT "Running C++ protocol buffer compiler on ${fil}" VERBATIM )
endforeach()
官方文档中该命令的签名有两个形式,在开源的项目中经常看到的是下面这个形式:
add_custom_command(OUTPUT output1 [output2 ...]
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args