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 dir 和 relative 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_2eproto
。 2f
和 2e
代表 /
和 .
,它们在符号名称中无效。
情况二:绝对路径
/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 相同的符号名称。
[更新] 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 pathimport "shmiw/metadata/metadata.proto";
发生这种情况的原因是什么?为什么protobuf编译器没有根据metadata.proto中定义的包生成元数据的“decriptor_tabele*”?
Protoc 对路径名的处理相当混乱,但这里是基础知识:
- 输入文件名被分隔为 include dir 和 relative 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_2eproto
。 2f
和 2e
代表 /
和 .
,它们在符号名称中无效。
情况二:绝对路径
/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 相同的符号名称。