Protobuf 가 Cmake 에서 의 정확 한 사용 방법 에 대한 상세 한 설명

7900 단어 Protobuf쓰다Cmake
Protobuf구 글 이 개발 한 직렬 화 와 반 직렬 화 된 프로 토 콜 라 이브 러 리 입 니 다.저 희 는 데 이 터 를 전달 하 는 형식 을 스스로 설계 하고.proto 을 통 해 전달 할 데이터 형식 을 정의 할 수 있 습 니 다.예 를 들 어 심도 있 는 학습 에서 자주 사용 하 는ONNX교환 모델 은.proto로 작 성 된 것 이다.우 리 는 다양한 전단(MNN,NCNN,TVM 의 전단)을 통 해 이.onx 모델 을 읽 을 수 있 지만,우선 protobuf 를 설치 해 야 합 니 다.
이전의 블 로그 에서 간단하게 소개onnx했 는데 그 중에서onnx.proto는 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(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
target_link_libraries(bar ${Protobuf_LIBRARIES})
그러나 이 예 는 너무 간단 합 니 다.만약 에 우리 의'proto 파일 이 하나 밖 에 없 거나 한 디 렉 터 리 에 만 있다 면 이 명령 을 사용 하 는 것 은 문제 가 없습니다.
그러나 이 경우 파일 디 렉 터 리 는 다음 과 같 습 니 다.

├── CMakeLists.txt
├── README.md
├── meta
│  └── proto
│    ├── CMakeLists.txt
│    └── common
│      ├── bar
│      │  ├── CMakeLists.txt
│      │  └── bar.proto
│      └── foo
│        ├── CMakeLists.txt
│        └── foo.proto
└── src
  ├── CMakeLists.txt
  ├── c_proto.cc
  └── 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나 를 오랫동안 괴 롭 혔 다.
미디어 파이프 에 대한 상세 한 소 개 는 다른 글 에 있 습 니 다.미디어 파이프 에서 대량의 ProtoBuf 기술 을 사용 하여 그림 구 조 를 표 시 했 습 니 다.그리고 미디어 파이프 의 원생 은 cmake 로 프로젝트 를 구축 하 는 것 이 아니 라 구 글 이 자체 개발 한bazel을 사 용 했 습 니 다.이 프로젝트 의 구축 시스템 은 평가 하지 않 겠 습 니 다.지금 은 Cmake 를 사용 하여 구축 해 야 합 니 다.

이것 도 악몽 의 시작 입 니 다.미디어 파이프 의.proto 파일 이 많 습 니 다.핵심 프레임 워 크 의 디 렉 터 리 에는.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";
모든.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/)" OUT_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()
참조 링크
http://blog.argcv.com/articles/3884.c
https://www.v2ex.com/t/602363
https://stackoverflow.com/questions/29720410/no-member-found-when-use-cmake-construct-proto/29817843
여기 서 Protobuf 가 Cmake 에서 의 올 바른 사용 방법 에 관 한 글 을 소개 합 니 다.더 많은 Protobuf 가 Cmake 를 사용 하 는 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기