处理#include_next的方法不对?
mhowto opened this issue · comments
cpp.cc中SearchFile函数对next的处理有这么一段:
if (next) {
assert(curPath);
if (path != *curPath)
continue;
else
next = false;
}
...
}
意思是要从当前file的下一个路径开始找。
但是我看https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html 中的介绍:
Suppose you specify -I /usr/local/include, and the list of directories to search also includes /usr/include;
and suppose both directories contain signal.h. Ordinary #include <signal.h> finds the file under
/usr/local/include. If that file contains #include_next <signal.h>, it starts searching after that directory, and finds the file in /usr/include.
指的是从找到的第一个包含的路径开始的下一个路径。
https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html
This directive works like ‘#include’ except in searching for the specified file: it starts searching the list of header file directories after the directory in which the current file was found.
假设现在有3个同名的头文件math.h, 它们被找到的顺序是:
- /foo/math.h
- /bar/math.h
- /hello/math.h
现在/bar/math.h这个文件,如果想包含/hello/math.h,那么他只要写:
#include_next "math.h"
按照你的理解, 这会导致这个预处理器找到/bar/math.h(第一个找到的是/foo/math.h), 于是无限循环。
题外话, 这三个头文件被搜索到的顺序,隐含的意义是:/foo/math.h 应当是/bar/math.h 的某种扩充或修正, /bar/math.h 则是/hello/math.h的扩充。这种情况下,应该总是/foo/math.h include_next "math.h" 去把/bar/math.h 包含进来,而/bar/math.h 同样用include_next 去把/hello/math.h 包含进来。这样.c文件就只需要简单的include "math.h" 了。
cpp.cc代码中的continue,就是为了跳过/foo/math.h,直到找到/bar/math.h(也就是自身) :)
希望你理解了~~
当然,SearchFile()这样简单的reverse头文件目录的搜索顺序是不对的。应该仅仅是调整库头文件目录和用户头文件目录之间的顺序。。。
如果你在foo.c 里面写:
#include_next "math.h"
用gcc编译,它会给你warning:
gcc -std=c11 -Wall -I./foo -I./bar foo.c
warning: #include_next in primary source file
#include_next "math.h"
而事实上,如果gcc此时干的事情是将foo.c中的include_next, 直接换成了include,你可以加一个 -E 看一下预处理后的结果。可能写foo.c 的人想要包含的是/bar/math.h 结果gcc给了他/foo/math.h。gcc尽最大能力让程序编译通过了,但是结果"出人意料"。wgtcc干脆就不给warning了,强制只能在math.h 里面include_next math.h(这也是include_next设计的初衷)。
理解了。
原来 https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html
This directive works like ‘#include’ except in searching for the specified file: it starts searching the list of
header file directories after the directory in which the current file was found.
这一段讲的就是gcc中对include_next的实现方法。
我追踪了gcc的源码,发现最终在 https://github.com/gcc-mirror/gcc/blob/4d2a90e08fd5a0ee89a0177c9179df2fa984ff28/libcpp/files.c 中的search_path_head函数中就是这样处理的:
if (type == IT_INCLUDE_NEXT && file->dir && file->dir != &pfile->no_search_path)
dir = file->dir->next;
难得你看的这么认真^_^