GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.

【GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.】gcc在寻找头文件时, 会按照一定的顺序在很多个目录挨个寻找, 一旦找到一个即停止寻找. 如果项目中存在多个同名的头文件, 则以第一个为准, 后面的直接忽略. 这个特性会导致很多编译不通过的问题!

GCC的寻找依赖的头文件顺序为: (这里已a.h为例)
1) 优先在使用了#include ”a.h” 的文件所在的目录寻找a.h
2) 在GCC通过 –I 指定的包含路径中从左到右找.

测试代码:
a.h
GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.
文章图片

b.h
GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.
文章图片


把a.h 分别往a1, a2两个目录放置一份.
把b.h 分别往当前目录和b1目录放置一份.
目录结构如下:
GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.
文章图片


主文件 gcc_include.cpp
GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.
文章图片


======================================
下面我们gcc找到同名文件的不同版本的效果.

1) 优先找到a1/a.h.
GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.
文章图片


2) 优先找到a2/a.h
GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.
文章图片


可以看到, 当指定不同的包含路径顺序时, gcc引用了不同a.h, 导致输出的结果不一样.

3) 优先找到当前目录下的b.h
GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.
文章图片

PS: 虽然-I./b1指定了目录, 但这里为什么没有找到 ./b1/b.h, 是因为 gcc_include.cpp文件中包含了 #include “b.h”, 所以, 优先在gcc_include.cpp所在的文件寻找.

4) 优先找到b/b.h (先把当前目录的b.h删除)GCC/LD编译链接潜规则 (第三弹) : 当项目库中包含多个同名的头文件时.
文章图片

此时终于输出了 ./b1/b.h
真实案例:
代码中用到了md5库, md5库有两个头文件, md5c.h 和 MD5Int.h, 其中MD5Int.h内部包含了md5c.h.

正常情况下, 需要md5库的代码, 只需要包含 MD5Int.h 即可. 但是. 实际中却编译报错.
经查, 发现
1)代码库中包含有多个md5的库:
1:./md5
2:./md5/inc/MD5Int.h
3:./md5/inc/md5_global.h
4:./md5/inc/md5c.h
5:./plib/base_class/extern_libs/tdev/include/md5.h
6:./plib/base_class/extern_libs/tdev/include/md5c.h
7:./plib/base_class/extern_libs/tbase/include/tbase_md5.h
8:./plib/application/qzdata/src/profile/md5c.c
9:./plib/application/app_manage/shortmsg_mail/share/include/md5c_new.h
10:./plib/application/path/group/include/md5_simple.h
11:./tdev/tlib/md5.c
12:./tdev/tlib/md5.h
13:./tdev/tlib/md5c.c
14:./tdev/tlib/md5c.h
2) 在没有加入编译依赖中没有明确的加入MD5库依赖时,查看编译时的引入库路径,居然已经有了上面的tdev (是被PLIB_BASE引入的)
g++ -o obj/open_tfs_bus.o -MF dep/open_tfs_bus.d -c -O -ggdb3 -pipe -Wall -MMD -MP -D_REENTRANT -D_GNU_SOURCE -pthread -DQZONE_PROJECT_ROOT="/usr/local/qzone_v3.0/" src/open_tfs_bus.cpp -Iinc -
.....
I/home/nemo/code/isd_qzoneappbase_proj/outerlib/store_cloud/32/include -I/home/nemo/code/isd_qzoneappbase_proj/outerlib/plib/outerlib/logapi//include/ -I/home/nemo/code/isd_qzoneappbase_proj/outerlib/plib/base_class/extern_libs/tdev/include
......
这个玩意给后面的编译失败留下了隐患.
3) 经查,tdev/include下的md5c.h 和 md5/inc/md5c.h 文件不一样!!!
更垃圾的是, md5/inc/MD5Inc.h 真正需要的md5c.h是tdev/include目录下的那个!!! 自己目录下的有很多符号都没有定义!!!
这里不得不吐槽下plib的维护者们, 这是在搞毛啊.
4) 所以, 如果想要编译过去, 必须引入md5/inc/MD5Int.h, 同时让其引入tdev/include目录下md5c.h, 而不是md5/inc/md5c.h
5) 偷鸡取巧的解决方法是:
a)
引入md5库的顺序如下: (让MD5放在后面)
PLIB_BASE
MD5
b)
代码中引入头文件的方式如下: (将md5c.h单独提出来,并且放在MD5Inc.h的前面)
#include "md5c.h" // 必须放在MD5Int.h前面, 否则编译报错. 因为MD5Int.h会引用一个错误的版本.
#include "MD5Int.h"
这样就可以编译过去了! 这样可以gcc引用的md5c.h是位于tdev/include目录下的, 而MD5Inc.h是位于md5/inc目录下的

PS:为什么会这样呢? 根据上面的潜规则自己推倒下吧~

    推荐阅读