我有一个项目,它将c++生成的protobuf序列化程序编译到静态库中。可执行文件与此库链接,而.so(.dll)也是如此。可执行文件稍后会加载.so文件。发生这种情况时,我得到:
[libprotobuf ERROR ../google/protobuf/descriptor_database.cc:668] Symbol name "google.protobuf.Struct" conflicts with the existing symbol "google.protobuf.Struct".
[libprotobuf FATAL ../google/protobuf/descriptor.cc:1357] CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size):
terminate called after throwing an instance of 'google::protobuf::FatalException'
what(): CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size):
十分清楚,我有一个静态库A,它链接到程序P和共享库S。后来,P加载了S,并且我得到了上面的错误。
我通常在Stack Overflow和google上看过类似的错误,但是我很确定我只是针对库进行链接,而不是重新编译源代码。据我所知,这应该意味着编译后的数据是相同的。
另请注意:此问题仅在Linux上发生。在Windows和OS X上运行良好。
最佳答案
问题是您的静态库包含一个文件mri.pb.cc,该文件在其全局初始化程序中正在将类型描述符注册到libprotobuf维护的全局描述符数据库中。因为您的静态库两次加载到程序中,所以此初始化程序运行两次,但是由于您的进程中只有一个libprotobuf拷贝,因此两个初始化程序都注册到相同的全局数据库中,并且正在检测到冲突。
若要解决此问题,您需要将您的静态库更改为共享库(-shared),主程序和动态加载的库都依赖该共享库。
我不确定为什么您会在Windows或OSX上看到不同的行为。我最好的猜测是,在这些平台上,实际上是将libprotobuf的两个单独拷贝链接到程序中-一个在主可执行文件中,一个在动态加载的库中。因此,描述符数据库有两个拷贝,并且没有冲突。但是,您可能会在这里看到更多细微的问题。如果您曾经在主程序和动态加载的模块之间传输protobuf对象指针(而无需序列化然后再次解析),那么最终可能会由该库的一个拷贝创建一个protobuf对象,但又将其与另一个拷贝一起使用(因此描述符数据库的另一个拷贝),这会混淆该库并导致发生奇怪的事情。
另外,如果您从未跨越边界传递protobuf对象,则可以通过静态链接libprotobuf来“修复” Linux上的问题,以便如上所述获得两个拷贝。但这是非常危险的。我不推荐它。
Google翻译自:https://stackoverflow.com/questions/33017985/static-linking-with-generated-protobufs-causes-abort