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 生成出来的,否则可能有其他问题