无法编译 protoc 生成的 (C++) 类

Posted

技术标签:

【中文标题】无法编译 protoc 生成的 (C++) 类【英文标题】:Cannot compile protoc-generated (C++) classes 【发布时间】:2020-01-09 10:07:54 【问题描述】:

我目前在编译 protobuf 生成的 C++ 代码时遇到了一些麻烦。 protoc 运行正常并且没有显示任何警告,但是当我尝试编译生成的 C++ 代码以便构建静态库时,g++ 向我显示以下消息:

CanInfo.pb.cc:107:5:错误:'::protobuf_BusType_2eproto' 尚未声明 107 | ::protobuf_BusType_2eproto::AddDescriptors();

到目前为止,我已经能够收集到,这是我的 BusType 枚举的一些问题,看起来像这样:

syntax = "proto3";

package MyPackage;

enum BusType 

    ProprietaryBus = 0;
    OpenBus = 1;
    UnknownBus = 2;


这个枚举包含在一条名为 CanInfo 的消息中,看起来像这样:

syntax = "proto3";

package MyPackage;

import "BusType.proto";

message CanInfo 

    int32 interfaceId = 10;
    bool isConnected = 20;
    BusType busType = 30;


正如我之前提到的,protoc“正确”编译这些文件(没有错误)。 用于编译 protos 的版本是 protoc 3.6.0。 这是protoc生成的C++代码部分:

::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
      descriptor, 248);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
    "data_containers/device_data/CanInfo.proto", &protobuf_RegisterTypes);
::protobuf_BusType_2eproto::AddDescriptors();
//           ^ error occurs here

通过代码搜索,protobuf_BusType_2eproto 命名空间的唯一提及是上面的行。 用于编译 C++ 代码的编译器版本是powerpc-linux-gnu-g++-6 (Ubuntu 6.4.0-17ubuntu1) 6.4.0 20180424。 将使用的 G++ 版本更改为版本 8 或 9不会改变此行为。

我多次尝试清理构建目录,并尝试切换到不同的 protobuf 版本(3.4.0),但这也导致了许多编译器错误,主要是因为 protoc 版本太旧.

单独构建每个文件也不会改变行为。

是什么导致了这种行为?到目前为止,我在使用 Protobuf 时还没有遇到过问题。 有没有人经历过这个并且知道一个方便的技巧?


编辑 这可能是我打电话给protoc 的方式造成的吗?

###
# Re-compile protos
###
set(BUILD_PROTOS True)
set(PROTOBUF_COMPILER protoc)
if (BUILD_PROTOS)
    function(BUILD_PROTOS)
        foreach(PROTO $PROTOS)
            message("Compiling $PROTO...")
            execute_process(
                COMMAND $PROTOBUF_COMPILER $PROTO_DIRS "--cpp_out=$CMAKE_CURRENT_BINARY_DIR" $PROTO
                WORKING_DIRECTORY $CMAKE_CURRENT_SOURCE_DIR
            )
        endforeach()
    endfunction()

    ###
    # Compile all protos
    ###
    BUILD_PROTOS()
endif()

【问题讨论】:

我认为protobuf_BusType_2eproto命名空间应该用在BusType.pb.h中,应该包含在CanInfo.pb.h中。你确定没有关于缺少包含的编译错误吗? 除了上面发布的错误之外,没有其他错误。 BusType.pb.h 中使用的命名空间是protobuf_data_5fcontainers_2fdevice_5fdata_2fBusType_2eproto 【参考方案1】:

好像我已经解决了这个问题。 protoc 编译器中显然存在一个错误,在每次编译单个文件时,在同一目录中导入文件都会导致这种奇怪的行为。 一次编译多个文件时,protoc 会产生一个错误,指出枚举值已在另一个文件中定义,并发出以下注释:

device_data/BusType.proto:15:5:请注意,枚举值使用 C++ 范围规则,这意味着枚举值是其类型的兄弟,而不是其子类型。因此,“ProprietaryBus”在“MyPackage”中必须是唯一的,而不仅仅是在“BusType”中。

谷歌搜索愈演愈烈,我发现了这个 2012 年的旧 Google Code post:

到协议编译器“bar.proto”和“x/bar.proto”是两个proto文件 尽管它们指向同一个物理文件。 使用 'import "x/bar.proto"' 是正确的解决方法。

解决方法(或修复)只是添加相对于protoc 工作目录的整个路径。

import "data_containers/device_data/BusType.proto";

在 CMake 中,现在如下所示。

message("Compiling protos...")
execute_process(
  COMMAND $PROTOBUF_COMPILER
  $PROTO_DIRS "--cpp_out=$CMAKE_CURRENT_BINARY_DIR" $PROTOS
  WORKING_DIRECTORY $CMAKE_CURRENT_SOURCE_DIR
)

到目前为止,这已经解决了我的问题,如果出现任何新信息,我将编辑我的答案。 也许这对其他人有用。

【讨论】:

以上是关于无法编译 protoc 生成的 (C++) 类的主要内容,如果未能解决你的问题,请参考以下文章

无法为 c++ python 扩展编译 swig 生成的包装器

Go

如何继承protobuf生成的C++类

当类成员是引用时无法生成默认赋值运算符?(在 C++ 中)

mapstruct无法生成实现类

通用protoc Makefile