Protobuf 不生成适当的声明

Protobuf does not generate appropriate declarations

[更新] protobuf_generate_cpp 似乎使用了绝对路径。 手动指定相对路径调用 protobuf 编译器似乎生成了有效源。

手动:

/usr/bin/protoc --cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build shmiw/metadata/metadata.proto

产生:(metadata.pb.h)

::DescriptorTable descriptor_table_shmiw_2fmetadata_2fmetadata_2eproto;

名称包含子目录

而当通过 protobuf_generate_cpp 从 cmake 进行编译时,它会使用以下命令调用 protobuf 编译器:

/usr/bin/protoc --cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build -I /home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata /home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata/metadata.proto

这会产生“无效”的名称,以后不能被其他软件包使用:(metadata.pb.h)

::DescriptorTable descriptor_table_metadata_2eproto;

我在使用 protobuf 时遇到了一些问题。我有 3 个原型文件。第一个是 proto 文件,其中包含所有其他 proto 文件使用的选项。所有 proto 文件都以相同的结构组织,并且每个文件都属于一个单独的包。我想生成所有 .h 和 .cc 文件,然后将它们放入一个静态库中。 项目结构如下:

/root-dir
-CMakeLists.txt (1)
-shm-iw/
  - CMakeLists.txt (2)
  - bci
    - CMakeLists.txt (3)
    - bci.proto
  - icon
    - CMakeLists.txt (4)
    - icon.proto
  - metadata
    - CMakeLists.txt (5)
    - metadata.proto

根目录 CMakeLists.txt (1)

cmake_minimum_required(VERSION 3.12)

project(shm-iw CXX)

set(SHM-IW_VERSION 0.1)

find_package(Protobuf REQUIRED)

include_directories(${CMAKE_BINARY_DIR})
set (Protobuf_IMPORT_DIRS ${CMAKE_SOURCE_DIR} )

add_subdirectory(shm-iw)

shm-iw CMakeLists.txt (2)

cmake_minimum_required(VERSION 3.12)

add_subdirectory(metadata)
add_subdirectory(bci)
add_subdirectory(icon)

bci CMakeLists.txt (3)

cmake_minimum_required(VERSION 3.12)


protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS
  bci.proto
)

add_library(bci_objlib OBJECT
  ${PROTO_SRCS}
  ${PROTO_HDRS}
)
target_link_libraries(bci_objlib metadata_objlib)

add_dependencies(bci_objlib metadata_objlib)

bci.proto

syntax = "proto3";

/* Board Control Interface */

import "shmiw/metadata/metadata.proto"; //Note the path to metadata.proto 

package shm.iw.bci;

enum IndicatorType {
  Status = 0;
  Warning = 1;
  Maintenance = 2;
  Fault = 3;
}
enum IndicatorState {
  SteadyOff = 0;
  SteadyOn = 1;
  Blink = 2;
};


message GetVisualIndicationReq
{
  option (shm.iw.metadata.MESSAGE_NUMBER) = 0x1000101;
  IndicatorType indicator = 1;
}

message GetVisualIndicationCfm
{
  option (shm.iw.metadata.MESSAGE_NUMBER) = 0x1000102;

  IndicatorType indicator = 1;
  IndicatorState state = 2;
}

元数据CMakeLists.txt (5)

cmake_minimum_required(VERSION 3.12)


protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS
  metadata.proto
)

add_library(metadata_objlib OBJECT
  ${PROTO_SRCS}
  ${PROTO_HDRS}
)

metadata.proto

syntax = "proto3";

import "google/protobuf/descriptor.proto";

package shm.iw.metadata;

extend google.protobuf.MessageOptions {
  uint32 MESSAGE_NUMBER = 50001;
}

我跳过了图标目录,因为它与 bci 目录几乎相同,它们只是消息不同,但现在不相关了。

编译时出现错误

shm-iw/build/shm-iw/bci/bci.pb.cc:183:6: error: ‘::descriptor_table_shm_2diw_2fmetadata_2fmetadata_2eproto’ has not been declared 183 | &::descriptor_table_shmiw_2fmetadata_2fmetadata_2eproto, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

看看 metadata.pb.h 我们有这样的东西:

extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_metadata_2eproto;

让我们比较缺少声明的名称和在metadata.pb.h

中生成的声明

metadata.pb.h: descriptor_table_metadata_2eproto

bci.pb.c: descriptor_table_shmiw_2fmetadata_2fmetadata_2eproto

他们看起来很像,但是第二个多了几个词:shm,iw,metadata,好像对应的是bci.proto

中定义的import path

import "shmiw/metadata/metadata.proto";

发生这种情况的原因是什么?为什么protobuf编译器没有根据metadata.proto中定义的包生成元数据的“decriptor_tabele*”?

Protoc 对路径名的处理相当混乱,但这里是基础知识:

  • 输入文件名被分隔为 include dirrelative path.
  • 相对路径 确定进入生成文件的符号的名称。
  • Include dir 必须匹配 -I.
  • 给出的目录
  • 如果没有给出 -I 个参数,总是有一个隐含的 -I .

基于此,我们可以弄清楚为什么它会以适合您的方式工作:

情况一:相对路径

/usr/bin/protoc
  --cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build
  shmiw/metadata/metadata.proto

没有给出-I,所以假定为-I .。相对路径为shmiw/metadata/metadata.proto,给出符号名称descriptor_table_shmiw_2fmetadata_2fmetadata_2eproto2f2e 代表 /.,它们在符号名称中无效。

情况二:绝对路径

/usr/bin/protoc
   --cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build
   -I /home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata 
   /home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata/metadata.proto

现在 -I 目录的相对路径是 metadata.proto。因此你得到 descriptor_table_metadata_2eproto 作为符号名称。

情况 3:绝对路径,但符号名称与情况 1 相同

/usr/bin/protoc
   --cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build
   -I /home/pp/Projects/SmartHomeManagement/shm-iw
   /home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata/metadata.proto

在对 -I 目录进行简单更改后,它将给出与案例 1 相同的符号名称。