【bug】error: multiple types in one declaration

时间:2021-08-28 16:13:36

背景

我的项目采用CMake构建,项目中使用了Thrift库,在构建代码的时候就遇到了一次这个问题,见下图

【bug】error: multiple types in one declaration

我通过修改项目主目录下的CMakefilelist.txt规避了这个问题,显式为libevent指定一个版本号

ADD_DEFINITIONS(-DLIBEVENT_VERSION_NUMBER=0x02010800)

  清理构建过程中间数据,重新构建编译,一切顺利。

bug原因分析

*上有人对这种一个符号多次定义的问题做了分析,参考:C++ “multiple types in one declaration” error

不过这是从个人开发角度来说的,答者的观点是:产生这种bug的原因主要还是因为个人写代码时的不小心,比如少写个;等等。

不过作为开源库,这种因为少些符号或者笔误导致的问题基本上不会出现的,那么就很有必要分析这个问题产生的根本原因了。

根据报错位置,逐步跟踪代码

【bug】error: multiple types in one declaration

【bug】error: multiple types in one declaration

到这一步问题基本上就很清楚了,THRIFT_SOCKET这个符号分别在/usr/local/include/thrift/server/TNonblockingServer.h 和 /usr/local/include/thrift/transport/PlatformSocket.h中进行了定义。PlatformSocket.h有两处定义,这两处是根据g++ 预定义宏(predefined macros)来区分是否是_Win32架构。

OK,现在问题找到了。能否对这个问题更进一步思考呢? 我的项目中很显然是引用了PlatformSocket.h,那么我能在项目中找到这个头文件呢?当然是找不到,不仅PlatformSocket.h找不到,连PlatformSocket.h也找不到。因为他们都没有添加到我的当前项目,之所以我的项目现在可以解析这些符号,完全是因为我单独添加外部符号到当前项目的缘故。现在对这个问题再一次抽象

【bug】error: multiple types in one declaration

如上图所示,在使用开源库的时候,或者处理大型项目的时候,符号冲突在所难免。假设我的项目直接使用头文件A.h和D.h,间接实用C.h中的THRIFT_SOCKET。上图为了简化,A.h直接使用B.h,现实问题中情况可能比这个还复杂,中间会经历更多的头文件。在构建项目的时候,就会出现THRIFT_SOCKET符号多次定义的问题。由于C.h时系统标准路径下的代码,你一般不太敢改动,而D.h中的代码是你自己写的,于是这个时候为了顺利构建以及照顾系统代码你可能就会更改自己的代码。如果你的代码中针对THRIFT_SOCKET符号有者复杂的处理逻辑,恐怕你改起自己的代码来也会很不爽(以我遇到的问题为例,你可以把typedef THRIFT_SOCKET evutil_socket_t;注释掉)。

【bug】error: multiple types in one declaration

进一步讲,假如THRIFT_SOCKET多次定义的位置都是位于系统文件的地方,如果不改变代码那似乎就是死路一条了。我们真的没有办法了吗?并不是,可以在项目构建起始阶段来解决这个问题,就像我最开始那样,在CMakefilelist.txt中规避问题。