我有一个项目将 C++ 生成的 protobuf 序列化程序编译成静态库。一个可执行文件链接到这个库,一个 .so (.dll) 也是如此。可执行文件稍后加载 .so 文件。发生这种情况时,我得到:
[libprotobuf ERROR /mf-toolchain/src/protobuf-3.0.0-beta-1/src/google/protobuf/descriptor_database.cc:57] File already exists in database: mri.proto
[libprotobuf FATAL /mf-toolchain/src/protobuf-3.0.0-beta-1/src/google/protobuf/descriptor.cc:1128] CHECK failed: generated_database_->Add(encoded_file_descriptor, size):
terminate called after throwing an instance of 'google::protobuf::FatalException'
what(): CHECK failed: generated_database_->Add(encoded_file_descriptor, size):
Aborted (core dumped)
说清楚一点,我有一个静态库A,它链接到程序P和共享库S。后来P加载S,我得到上面的错误。
我在 Stack Overflow 和谷歌上查看了类似的错误,但我很确定我只是链接库,而不是重新编译源代码。据我所知,这应该意味着编译的数据是相同的。
另请注意:此问题仅发生在 Linux 上。这在 Windows 和 OS X 上运行良好。
最佳答案
问题是您的静态库包含一个文件 mri.pb.cc
,该文件在其全局初始化程序中将类型描述符注册到由 libprotobuf 维护的全局描述符数据库中。因为你的静态库被加载到你的程序中两次,这个初始化程序运行了两次,但是因为你的进程中只有一个 libprotobuf 拷贝,所以两个初始化程序都注册到同一个全局数据库中,并且它正在检测冲突。
要解决这个问题,您需要将静态库更改为共享库,主程序和动态加载库都依赖它。
我不确定为什么您会在 Windows 或 OSX 上看到不同的行为。我最好的猜测是,在这些平台上,您实际上将两个独立的 libprotobuf 拷贝链接到您的程序中——一个在主可执行文件中,一个在动态加载的库中。因此描述符数据库有两个拷贝并且没有冲突。但是,您可能会在这里看到更微妙的问题。如果你曾经在主程序和动态加载的模块之间传输 protobuf 对象指针(没有序列化然后再次解析)那么你最终可能会得到一个由库的一个拷贝创建但被另一个拷贝使用的 protobuf 对象(因此描述符数据库的不同拷贝),这会混淆库并导致奇怪的事情发生。
或者,如果您不曾经跨越边界传递 protobuf 对象,您可以通过静态链接 libprotobuf 来“修复”Linux 上的问题,以获得所描述的两个拷贝以上。但这是非常危险的;我不推荐它。
关于c++ - 与生成的 protobufs 的静态链接导致中止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33017985/