Protobuf 使用过程遇到的一个问题

问题描述

运行时崩溃,断点处 log 报错 File already exists in databaseFile is already registered

类似问题 static linking with generated protobufs causes abort

出现的原因

工程结构如下,首先项目里使用的 protobuf 库是动态编译的 libprotobuf.dll,然后有两个其他的库分别为 A.dllB.dll,这个两个 dll 都有 proto 协议处理的部分,并且有一个协议是一样的都是 Common.proto,所以这两个 dll 工程里都编译了 Common.pb.h/Common.pb.cc 文件

每个 pb.cc 文件中,都有一个函数 AddDescriptorsImpl ,里面调用了 InternalAddGeneratedFileInternalRegisterGeneratedFile 去注册自己的协议类型,这些函数会在程序一启动的时候调用,所以在加载 A.dllB.dll 的时候,这个两个 dll 中的 Common.pb.cc 中的这些函数就会被调用两次,而 InternalAddGeneratedFileInternalRegisterGeneratedFile 这两个函数最终是调到了 libprotobuf.dll 里去,libprotobuf.dll 会有全局变量 generated_database_GeneratedMessageFactory::singleton 来做相应的注册,因为 libprotobuf.dll 是同一份,所以就注册到了同一个全局对象中,所以就冲突了

解决方法

方法一

不使用动态库 libprotobuf.dll,而改用静态库,A.dllB.dll 各自链接,这样就不会冲突了

方法二

如果一定要使用动态库,那么可以修改 protobuf 代码,把 InternalAddGeneratedFileInternalRegisterGeneratedFile 因为冲突报错的地方忽略掉,原来 return false 改成 return true,这样也可以解决问题,不过这样之后最好要保证 A.dllB.dll 中各自用的 Common.pb.h/.cc 是同一版本的 Common.proto 生成出来的,否则可能有其他问题