Protobuf在Cmake中的正确使⽤⽅法详解
是google开发的⼀个序列化和反序列化的协议库,我们可以⾃⼰设计传递数据的格式,通过.proto⽂件定义我们的要传递的数据格式。例如,在深度学习中常⽤的交换模型就是使⽤.proto编写的。我们可以通过多种前端(MNN、NCNN、TVM的前端)去读取这个.onnx这个模型,但是⾸先你要安装protobuf。
在之前的博⽂中已经简单介绍了,其中就代表了onnx模型的基本数据结构。⼀般来说,protobuf经常搭配Cmake使
⽤,Cmake有官⽅的modules,可以通过简单的⼏个命令protobuf_generate_cpp来⽣成对应的.pb.cc和.pb.h。
简单的例⼦:
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS EXPORT_MACRO DLL_EXPORT foo.proto)
protobuf_generate_python(PROTO_PY foo.proto)
add_executable( ${PROTO_SRCS} ${PROTO_HDRS})
target_link_libraries(bar ${Protobuf_LIBRARIES})
但是这个例⼦太简单了,如果我们的.proto⽂件只有⼀个或者说都只在⼀个⽬录⾥,那⽤这个命令没什么⽑病...
但如果是这种情况,我们的⽂件⽬录如下:
├──
├── README.md
├── meta
│└── proto
│├──
│└── common
│├── bar
││├──
││└── bar.proto
│└── foo
│├──
│└── foo.proto
└── src
├──
├──
└── c_proto.hh
其中foo.proto⽂件如下:
message foo_msg
{
optional string name = 1;
}
bar.proto的⽂件如下:
import "common/foo/foo.proto";
message bar_msg
{
optional foo_msg foo = 1;
optional string name = 2;
}
如上,bar⽂件引⽤foo,⽽且这两个不在⼀个⽬录,如果直接使⽤protobuf_generate_cpp来⽣成,直接会报错。(这个例⼦取⾃Yu的⼀篇)
也想过把他俩放到同⼀个⽬录...然后bar.proto中import的代码就要修改,虽然这样可以,但显然是不适合⼤型的项⽬。
⽽这个⼤型项⽬显然就是...折磨了我好久。
关于mediapipe的详细介绍在另⼀篇⽂章。mediapipe中使⽤了⼤量的ProtoBuf技术来表⽰图结构,⽽且mediapipe原⽣并不是采⽤cmake来构建项⽬,⽽是使⽤google⾃家研发的,这个项⽬构建系统我就不评价了,⽽现在我需要使⽤Cmake来对其进⾏构建。
这也是噩梦的开始,mediapipe的.proto⽂件很多,核⼼的framework的⽬录下存在很多的.proto⽂件,根⽬录和⼦⽬录都
有.proto⽂件:
⽽且每个proto⽂件之间存在引⽤的顺序,framework根⽬录下的calculator.proto⽂件:
// mediapipe/framework/calculator.proto
syntax = "proto3";
package mediapipe;
import public "mediapipe/framework/calculator_options.proto";
import "google/protobuf/any.proto";
import "mediapipe/framework/mediapipe_options.proto";
import "mediapipe/framework/packet_factory.proto";
import "mediapipe/framework/packet_generator.proto";
import "mediapipe/framework/status_handler.proto";
import "mediapipe/framework/stream_handler.proto";
为什么现在都用cmake
每个.proto⽂件都import了其他⽬录下的⽂件,这⾥的import类似于C++中的include,但是这⾥的import⼜可以相互引⽤,例如上述的status_handler.proto也引⽤了mediapipe_options.proto。
如果直接对上述所有的.proto⽂件直接使⽤protobuf_generate_cpp命令,会直接报错,因为这些⽂件不在⼀个⽬录,⽽且import的
相对⽬录也⽆法分析。另外,不同⽬录内的.cc⽂件会引⽤相应⽬录⽣成的.pb.h⽂件,我们需要⽣成的.pb.cc和.pb.h在原始的⽬录中,这样才可以正常引⽤,要不然需要修改其他源代码的include地址,⽐较⿇烦。
CLion中Cmake来编译proto⽣成的.pb.cc和.pb.h不在原始⽬录,⽽是集中在cmake-build-debug(release)中,我们额外需要将其中⽣成的.pb.cc和.pb.h⽂件移动到原始地址(Clion的情况是这样)。
正确修改cmake
对于这种情况,⽐较合适的做法是直接使⽤命令进⾏⽣成。
⾸先到所有需要编译的.proto⽂件:
file(GLOB protobuf_files
mediapipe/framework/*.proto
mediapipe/framework/tool/*.proto
mediapipe/framework/deps/*.proto
mediapipe/framework/testdata/*.proto
mediapipe/framework/formats/*.proto
mediapipe/framework/formats/annotation/*.proto
mediapipe/framework/formats/motion/*.proto
mediapipe/framework/formats/object_detection/*.proto
mediapipe/framework/stream_handler/*.proto
mediapipe/util/*.proto
mediapipe/calculators/internal/*.proto
)
接下来,定义相关的⽬录地址,PROTO_META_BASE_DIR为编译之后⽣成⽂件的⽬录。PROTO_FLAGS很重要,指定编译.proto⽂件时的总的寻路径,.proto中的import命令根据根据这个地址去连接其他的.proto⽂件:
SET(PROTO_META_BASE_DIR ${CMAKE_CURRENT_BINARY_DIR})
LIST(APPEND PROTO_FLAGS -I${CMAKE_CURRENT_SOURCE_DIR})
设置好之后,通过FOREACH去循环之前的.proto⽂件,依次编译每个⽂件,然后将⽣成的.pb.cc和.pb.h移动回原始的⽬录,⾄此就可以正常⼯作了。
FOREACH(FIL ${protobuf_files})
GET_FILENAME_COMPONENT(FIL_WE ${FIL} NAME_WE)
string(REGEX REPLACE ".+/(.+)\\..*" "\\1" FILE_NAME ${FIL})
string(REGEX REPLACE "(.+)\\${FILE_NAME}.*" "\\1" FILE_PATH ${FIL})
string(REGEX MATCH "(/mediapipe/framework.*|/mediapipe/util.*|/mediapipe/calculators/internal/)" OU
T_PATH ${FILE_PATH})
set(PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}${OUT_PATH}${FIL_WE}.pb.cc")
set(PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}${OUT_PATH}${FIL_WE}.pb.h")
EXECUTE_PROCESS(
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} ${PROTO_FLAGS} --cpp_out=${PROTO_META_BASE_DIR} ${FIL}
)
message("Copying " ${PROTO_SRCS} " to " ${FILE_PATH})
file(COPY ${PROTO_SRCS} DESTINATION ${FILE_PATH})
file(COPY ${PROTO_HDRS} DESTINATION ${FILE_PATH})
ENDFOREACH()
参考链接
到此这篇关于Protobuf在Cmake中的正确使⽤⽅法的⽂章就介绍到这了,更多相关Protobuf使⽤Cmake内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论