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

Cannot compile protoc-generated (C++) classes

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

CanInfo.pb.cc:107:5: error: ‘::protobuf_BusType_2eproto’ has not been declared 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 编译这些文件 "correctly"(没有错误)。 用于编译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。 将用于版本 8 或 9 的 G++ 版本更改不会改变此行为。

我已经多次尝试清理构建目录,并且尝试切换到不同的 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()

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

device_data/BusType.proto:15:5: Note that enum values use C++ scoping rules, meaning that enum values are siblings of their type, not children of it. Therefore, "ProprietaryBus" must be unique within "MyPackage", not just within "BusType".

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

To protocol compiler "bar.proto" and "x/bar.proto" are two proto files
although they are pointed at the same physical file.
Using 'import "x/bar.proto"' is the right fix.

解决方法(或修复)只是添加相对于 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}
)

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