wgtdkp / wgtcc

A small C11 compiler

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

处理#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, 它们被找到的顺序是:

  1. /foo/math.h
  2. /bar/math.h
  3. /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;

难得你看的这么认真^_^