与生成的protobufs的静态链接导致中止

Chr*_*her 8 c++ dll dynamic-linking protocol-buffers static-linking

我有一个项目,它将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)
Run Code Online (Sandbox Code Playgroud)

为了清楚起见,我有一个静态库A,它由程序P和共享库S链接.后来,P加载S,我得到上面的错误.

我在stackoverflow和google上看了类似的错误,但我很确定我只是链接到库,而不是重新编译源代码.据我所知,这应该意味着编译数据是相同的.

另请注意:此问题仅发生在Linux上.这适用于Windows和OS X.

任何解决此问题的建议都表示赞赏.

Ken*_*rda 7

问题是您的静态库包含一个文件mri.pb.cc,该文件在其全局初始化器中将类型描述符注册到由libprotobuf维护的全局描述符数据库中.因为您的静态库已加载到程序中两次,所以此初始化程序运行两次,但由于您的进程中只有一个libprotobuf副本,因此两个初始化程序都注册到同一个全局数据库中,并且它正在检测冲突.

要解决此问题,您需要将静态库更改为共享库,主程序和动态加载的库都依赖于该库.

我不确定为什么你在Windows或OSX上看到不同的行为.我最好的猜测是,在这些平台上,您实际上将两个独立的libprotobuf副本链接到您的程序中 - 一个在主可执行文件中,一个在动态加载的库中.因此,描述符数据库有两个副本,没有冲突.但是,您可能会在这里看到更多微妙的问题.如果您在主程序和动态加载的模块之间传输protobuf对象指针(没有序列化然后再次解析),那么最终可能会有一个由库的一个副本创建的protobuf对象,但是与另一个副本一起使用(因此描述符数据库的不同副本)会混淆库并导致奇怪的事情发生.

或者,如果您没有跨越边界传递protobuf对象,您可以通过静态链接libprotobuf来"修复"Linux上的问题,以便获得如上所述的两个副本.但这很危险; 我不推荐它.