Protobuf 使用过程遇到的一个问题
问题描述
运行时崩溃,断点处 log
报错 File already exists in database
和 File is already registered
类似问题 static linking with generated protobufs causes abort
出现的原因
工程结构如下,首先项目里使用的 protobuf
库是动态编译的 libprotobuf.dll
,然后有两个其他的库分别为 A.dll
和 B.dll
,这个两个 dll
都有 proto
协议处理的部分,并且有一个协议是一样的都是 Common.proto
,所以这两个 dll
工程里都编译了 Common.pb.h/Common.pb.cc
文件
每个 pb.cc
文件中,都有一个函数 AddDescriptorsImpl
,里面调用了 InternalAddGeneratedFile
和 InternalRegisterGeneratedFile
去注册自己的协议类型,这些函数会在程序一启动的时候调用,所以在加载 A.dll
和 B.dll
的时候,这个两个 dll
中的 Common.pb.cc
中的这些函数就会被调用两次,而 InternalAddGeneratedFile
和 InternalRegisterGeneratedFile
这两个函数最终是调到了 libprotobuf.dll
里去,libprotobuf.dll
会有全局变量 generated_database_
和 GeneratedMessageFactory::singleton
来做相应的注册,因为 libprotobuf.dll
是同一份,所以就注册到了同一个全局对象中,所以就冲突了
解决方法
方法一
不使用动态库 libprotobuf.dll
,而改用静态库,A.dll
和 B.dll
各自链接,这样就不会冲突了
方法二
如果一定要使用动态库,那么可以修改 protobuf
代码,把 InternalAddGeneratedFile
和 InternalRegisterGeneratedFile
因为冲突报错的地方忽略掉,原来 return false
改成 return true
,这样也可以解决问题,不过这样之后最好要保证 A.dll
和 B.dll
中各自用的 Common.pb.h/.cc
是同一版本的 Common.proto
生成出来的,否则可能有其他问题