GCC-3.4.6源代码学习笔记(28)

4.1.1. 完成查找路径设置

GCC在多个不同的地方查找头文件。在一个普通的Unix系统上,如果不另外指示,由`#include <FILE>'请求的文件将在以下目录中查找:

     /usr/local/include

     LIBDIR/gcc/TARGET/VERSION/include

     /usr/TARGET/include

     /usr/include

对于C++程序,它还首先会在/usr/include/g++-v3中查找。在上面,TARGETGCC为之编译代码的系统的规范名(canonical name);通常但不总是运行编译器的系统的规范名。VERSION则是GCC的版本。

通过-IDIR命令行选项可以向此列表添加查找目录DIR。所有为-I所指定的目录,以从左到右的次序,在默认目录前,被查找。唯一的例外是当dir已由默认查找所覆盖。在这种情况下,该选项被忽略且系统目录的查找次序不变。

在引号包含查找链及尖括号包含查找链合并为最终的查找链之前,重复的目录被从中移出。然而,一个目录可能在最终查找链中出现2次,如果它在引号包含查找链及尖括号包含查找链中均被指定。

当编译操作系统内核或其它不使用标准C库的程序或C标准库本身时,可以通过-nostdinc选项来阻止GCC在任一默认目录中查找。当-nonstdinc起用时,选项-I不会像上面所说的那样被忽略。

GCC首先在包含当前文件的目录中查找由#include "FILE"所请求的头文件,然后在那些它查找尖括号引用的头文件的目录中查找。例如,如果/usr/include/sys/stat.h中包含#include "types.h"GCC首先在/usr/include/sys中查找types.h,然后才在它的通常查找路径中查找。

#line不会改变GCC中包含当前文件的目录。

可以在-I选项列表中任意处插入-I-。这将有2个作用。首先,在-I-之前出现的目录仅用于查找由引号引用之头文件。在-I-之后的目录则用于查找所有头文件。其次,包含当前文件的目录不用于查找,除非它正好由-I选项指定。

-I. -I-不同于不使用-I选项,它不能导致<>包含具有,””包含在没有特别选项时,同样的行为。-I.查找编译器的当前工作目录。它可能是包含当前文件的目录,也可能不是。

如果需要在名为“-”的目录中查找头文件,应写作-I./-

在前面的章节中,我们已经看过了-I选项的处理。现在编译器应该完成查找路径的设置了。这里,参数sysroot是全局变量sysroot,由-isysroot选项设置,表示系统头文件的查找根目录。而参数iprefix是全局变量iprefix,由-iprefix选项设置,表示查找目录的前缀。

 

335  void

336  register_include_chains (cpp_reader *pfile, const char *sysroot,                     in c-incpath.c

337                       const char *iprefix, int stdinc, int cxx_stdinc,

338                       int verbose)

339  {

340    static const char *const lang_env_vars[] =

341      { "C_INCLUDE_PATH", "CPLUS_INCLUDE_PATH",

342        "OBJC_INCLUDE_PATH", "OBJCPLUS_INCLUDE_PATH" };

343    cpp_options *cpp_opts = cpp_get_options (pfile);

344    size_t idx = (cpp_opts->objc ? 2: 0);

345 

346    if (cpp_opts->cplusplus)

347      idx++;

348    else

349      cxx_stdinc = false;

350 

351    /* CPATH and language-dependent environment variables may add to the

352      include chain.  */

353    add_env_var_paths ("CPATH", BRACKET);

354    add_env_var_paths (lang_env_vars[idx], SYSTEM);

355 

356    /* Finally chain on the standard directories.  */

357    if (stdinc)

358      add_standard_paths (sysroot, iprefix, cxx_stdinc);

359 

360    merge_include_chains (pfile, verbose);

361 

362    cpp_set_include_chains (pfile, heads[QUOTE], heads[BRACKET],

363                         quote_ignores_source_dir);

364  }

 

查找目录亦可通过环境变量来添加,这些环境变量包括CPATHC_INCLUDE_PATHCPLUS_INCLUDE_PATHOBJC_INCLUDE_PATH

每个环境变量的值是由特殊字符分割的目录列表,与PATH非常相似,在其中查找头文件。这个特殊字符,PATH_SEPARATOR,是依赖于目标平台并且在编译GCC的时候确定的。对于Microsoft 基于Windows的平台,它是分号,而对于几乎所有其他目标平台是冒号。

CPATH指定了一组用于查找的目录,如同-I所指定那样,但它们排在命令行中-I选项给出的路径后。这个环境变量不管被预处理的是何种语言,都得到使用。

剩下的环境变量只应用于预处理特定的语言。每个指定了一组用于查找的目录,如同-isystem所指定那样,但它们排在命令行中-isystem选项给出的路径后。

在所有这些环境变量中,一个空的元素指示编译器在当前工作目录查找。空元素可以出现在路径的开头或结尾。例如,如果CPATH的值是::/special/include,这与“-I. -I/special/include”效果相同。

这些路径由add_env_var_paths执行添加。

 

90    static void

91    add_env_var_paths (const char *env_var, int chain)                                       in c-incpath.c

92    {

93      char *p, *q, *path;

94   

95      GET_ENVIRONMENT (q, env_var);

96   

97      if (!q)

98        return;

99   

100    for (p = q; *q; p = q + 1)

101    {

102      q = p;

103      while (*q != 0 && *q != PATH_SEPARATOR)

104        q++;

105 

106      if (p == q)

107        path = xstrdup (".");

108      else

109      {

110        path = xmalloc (q - p + 1);

111        memcpy (path, p, q - p);

112        path[q - p] = '/0';

113      }

114 

115      add_path (path, chain, chain == SYSTEM);

116    }

117  }

 

注意到在register_include_chains357行的stdinc来自全局变量std_inc,其内容来自选项–nonstdinc(默认值为1),而cxx_stdinc来自std_cxx_inc,其内容由–nonstdinc++设定(默认值为1)。因此,如果在标准系统目录下查找头文件是被允许的,通过add_standard_paths把标准包含链加入heads链。

 

120  static void

121  add_standard_paths (const char *sysroot, const char *iprefix, int cxx_stdinc)   in c-incpath.c

122  {

123    const struct default_include *p;

124    size_t len;

125 

126    if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0)

127    {

128      /* Look for directories that start with the standard prefix.

129       "Translate" them, ie. replace /usr/local/lib/gcc... with

130       IPREFIX and search them first.  */

131      for (p = cpp_include_defaults; p->fname; p++)

132      {

133        if (!p->cplusplus || cxx_stdinc)

134        {

135          /* Should we be translating sysrooted dirs too? Assume

136            that iprefix and sysroot are mutually exclusive, for

137            now.  */

138          if (sysroot && p->add_sysroot)

139            continue;

140          if (!strncmp (p->fname, cpp_GCC_INCLUDE_DIR, len))

141          {

142            char *str = concat (iprefix, p->fname + len, NULL);

143            add_path (str, SYSTEM, p->cxx_aware);

144          }

145        }

146      }

147    }

148 

149    for (p = cpp_include_defaults; p->fname; p++)

150    {

151      if (!p->cplusplus || cxx_stdinc)

152      {

153        char *str;

154 

155        /* Should this directory start with the sysroot?  */

156        if (sysroot && p->add_sysroot)

157          str = concat (sysroot, p->fname, NULL);

158        else

159          str = update_path (p->fname, p->component);

160 

161        add_path (str, SYSTEM, p->cxx_aware);

162      }

163    }

164  }

 

结构体default_include持有查找包含文件的默认目录列表的信息。它可以被不同的-I-ixxx选项改写。所有这些目录都被处理为系统包含目录(在某些情况下它们不受pedantic警告的影响)。

 

35    struct default_include                                                                           in cppdefault.h

36    {

37      const char *const fname;           /* The name of the directory.  */

38      const char *const component;    /* The component containing the directory

39                                        (see update_path in prefix.c) */

40      const char cplusplus;         /* Only look here if we're compiling C++.  */

41      const char cxx_aware;              /* Includes in this directory don't need to

42                              be wrapped in extern "C" when compiling

43                              C++.  */

44      const char add_sysroot;             /* FNAME should be prefixed by

45                                    cpp_SYSROOT.  */ 

46    };

 

Linux平台上,cpp_GCC_INCLUDE_DIR是空的,因此cpp_GCC_INCLUDE_DIR_len0。对于149行的cpp_include_defaults,在我的机器上(Linux),它包含以下内容。这些路径都被认为是SYSTEM

 

44    const struct default_include cpp_include_defaults[]                                 in cppdefault.c

48      = {

66       { "/localdisk/data/gcc346/include", 0, 0, 1, 0 },

86         { "/include", 0, 0, 0, 1 },

88         { 0, 0, 0, 0, 0 }

89    };

 

在加入了所有的头文件查找路径后,需要把这四个包含链以quotebracketsystemafter的次序合并一起,期间去除重复的目录。这由merge_include_chains完成。

 

247    static void

248    merge_include_chains (cpp_reader *pfile, int verbose)                                 in c-incpath.c

249    {

250      /* Join the SYSTEM and AFTER chains. Remove duplicates in the

251        resulting SYSTEM chain.  */

252      if (heads[SYSTEM])

253        tails[SYSTEM]->next = heads[AFTER];

254      else

255        heads[SYSTEM] = heads[AFTER];

256      heads[SYSTEM] = remove_duplicates (pfile, heads[SYSTEM], 0, 0, verbose);

257   

258      /* Remove duplicates from BRACKET that are in itself or SYSTEM, and

259        join it to SYSTEM.  */

260      heads[BRACKET] = remove_duplicates (pfile, heads[BRACKET], heads[SYSTEM],

261                                    heads[SYSTEM], verbose);

262   

263     /* Remove duplicates from QUOTE that are in itself or SYSTEM, and

264        join it to BRACKET.  */

265      heads[QUOTE] = remove_duplicates (pfile, heads[QUOTE], heads[SYSTEM],

266                                  heads[BRACKET], verbose);

267   

268      /* If verbose, print the list of dirs to search.  */

269      if (verbose)

270      {

271        struct cpp_dir *p;

272   

273        fprintf (stderr, _("#include /".../" search starts here:/n"));

274        for (p = heads[QUOTE];; p = p->next)

275       {

276          if (p == heads[BRACKET])

277            fprintf (stderr, _("#include <...> search starts here:/n"));

278          if (!p)

279            break;

280          fprintf (stderr, " %s/n", p->name);

281        }

282        fprintf (stderr, _("End of search list./n"));

283      }

284    }

 

remove_duplicates中,对于链head中每个重复路径,保留第一个出现的。而在system链中亦出现的路径,则将其从head链移除。把移除重复路径(注意只是移除与system重复的部分)后所得的链中最后路径节点中的next指针设置为指向join,除非它也出现在join中。在这种情况下它则被从head链中移除(现次结尾的节点为结尾节点,重复上步骤,直至发现join所无之节点,从而将headjoin相接)。由此可见,在headjoin链中,实可出现重复路径,除非join就是system

 

172    static struct cpp_dir *

173    remove_duplicates (cpp_reader *pfile, struct cpp_dir *head,                        in c-incpath.c

174                   struct cpp_dir *system, struct cpp_dir *join,

175                   int verbose)

176    {

177      struct cpp_dir **pcur, *tmp, *cur;

178      struct stat st;

179   

180      for (pcur = &head; *pcur; )

181      {

182        int reason = REASON_QUIET;

183   

184        cur = *pcur;

185   

186        if (stat (cur->name, &st))

187        {

188          /* Dirs that don't exist are silently ignored, unless verbose.  */

189          if (errno != ENOENT)

190            cpp_errno (pfile, CPP_DL_ERROR, cur->name);

191          else

192            reason = REASON_NOENT;

193        }

194        else if (!S_ISDIR (st.st_mode))

195          cpp_error_with_line (pfile, CPP_DL_ERROR, 0, 0,

196                           "%s: not a directory", cur->name);

197        else

198        {

199          INO_T_COPY (cur->ino, st.st_ino);

200          cur->dev = st.st_dev;

201   

202          /* Remove this one if it is in the system chain.  */

203          reason = REASON_DUP_SYS;

204          for (tmp = system; tmp; tmp = tmp->next)

205            if (INO_T_EQ (tmp->ino, cur->ino) && tmp->dev == cur->dev)

206              break;

207   

208          if (!tmp)

209          {

210            /* Duplicate of something earlier in the same chain?  */

211             reason = REASON_DUP;

212            for (tmp = head; tmp != cur; tmp = tmp->next)

213              if (INO_T_EQ (cur->ino, tmp->ino) && cur->dev == tmp->dev)

214                break;

215   

216              if (tmp == cur

217               /* Last in the chain and duplicate of JOIN?  */

218               && !(cur->next == NULL && join

219                    && INO_T_EQ (cur->ino, join->ino)

220                    && cur->dev == join->dev))

221            {

222              /* Unique, so keep this directory.  */

223              pcur = &cur->next;

224              continue;

225            }

226          }

227        }

228   

229        /* Remove this entry from the chain.  */

230        *pcur = cur->next;

231        free_path (cur, verbose ? reason: REASON_QUIET);

232      }

233   

234      *pcur = join;

235      return head;

236    }

 

register_include_chains中,执行完merge_include_chains后,现在头文件的查找次序被设置为引号(quote),尖括号(bracket),系统(system),而后后续(after)。注意到下面参数quote引用括号引用头文件的包含路径,bracket引用尖括号引用头文件的包含路径。据此cpp_set_include_chains设置parse_in——解析器对象。

 

1083 void

1084 cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote,                   in cppfiles.c

1085              cpp_dir *bracket, int quote_ignores_source_dir)

1086 {

1087   pfile->quote_include = quote;

1088   pfile->bracket_include = quote;

1089   pfile->quote_ignores_source_dir = quote_ignores_source_dir;

1090

1091   for (; quote; quote = quote->next)

1092   {

1093     quote->name_map = NULL;

1094     quote->len = strlen (quote->name);

1095     if (quote == bracket)

1096       pfile->bracket_include = bracket;

1097   }

1098 }

 

注意,只有使用了-I-选项,才会出现非空的quote(参见split_quote_chain,及-I-的解释)。否则解析器对象中的quote_includebracket_include是相同的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值