Studying note of GCC-3.4.6 source (28)

4.1.1. Finish the setup of search path

GCC looks in several different places for headers. On a normal Unix system, if you do not instruct it otherwise, it will look for headers requested with `#include <FILE>' in:

     /usr/local/include

     LIBDIR/gcc/TARGET/VERSION/include

     /usr/TARGET/include

     /usr/include

For C++ programs, it will also look in `/usr/include/g++-v3', first. In the above, TARGET is the canonical name of the system GCC was configured to compile code for; often but not always the same as the canonical name of the system it runs on. VERSION is the version of GCC in use.

You can add to this list with the `-IDIR' command line option. All the directories named by `-I' are searched, in left-to-right order, before the default directories. The only exception is when `dir' is already searched by default. In this case, the option is ignored and the search order for system directories remains unchanged.

Duplicate directories are removed from the quote and bracket search chains before the two chains are merged to make the final search chain. Thus, it is possible for a directory to occur twice in the final search chain if it was specified in both the quote and bracket chains.

You can prevent GCC from searching any of the default directories with the `-nostdinc' option. This is useful when you are compiling an operating system kernel or some other program that does not use the standard C library facilities, or the standard C library itself. `-I' options are not ignored as described above when `-nostdinc' is in effect.

GCC looks for headers requested with `#include "FILE"' first in the directory containing the current file, then in the same places it would have looked for a header requested with angle brackets. For example, if `/usr/include/sys/stat.h' contains `#include "types.h"', GCC looks for `types.h' first in `/usr/include/sys', then in its usual search path.

`#line' does not change GCC's idea of the directory containing the current file.

You may put `-I-' at any point in your list of `-I' options. This has two effects. First, directories appearing before the `-I-' in the list are searched only for headers requested with quote marks. Directories after `-I-' are searched for all headers. Second, the directory containing the current file is not searched for anything, unless it happens to be one of the directories named by an `-I' switch.

`-I. -I-' is not the same as no `-I' options at all, and does not cause the same behavior for `<>' includes that `""' includes get with no special options. `-I.' searches the compiler's current working directory for header files. That may or may not be the same as the directory containing the current file.

If you need to look for headers in a directory named `-', write `-I./-'.

In previous section, we have seen the processing of “–I” options. Now the compiler will finish the setup of the search path. Here, parameter sysroot is the global variable sysroot which is set by option –isysroot to indicate the root of system searching directory. And parameter iprefix is the global variable iprefix which is set by option –iprefix to stand for the prefix of the searching directory.

 

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  }

 

Searching directories can also be added by environment variables, which include CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH and OBJC_INCLUDE_PATH.

Each variable's value is a list of directories separated by a special character, much like `PATH', in which to look for header files. The special character, `PATH_SEPARATOR', is target-dependent and determined at GCC build time. For Microsoft Windows-based targets it is a semicolon, and for almost all other targets it is a colon.

`CPATH' specifies a list of directories to be searched as if specified with `-I', but after any paths given with `-I' options on the command line. This environment variable is used regardless of which language is being preprocessed.

The remaining environment variables apply only when preprocessing the particular language indicated. Each specifies a list of directories to be searched as if specified with `-isystem', but after any paths given with `-isystem' options on the command line.

In all these variables, an empty element instructs the compiler to search its current working directory. Empty elements can appear at the beginning or end of a path. For instance, if the value of `CPATH' is `:/special/include', that has the same effect as `-I. -I/special/include'.

These pathes are added by 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  }

 

Note that stdinc at line 357 in register_include_chains comes from global variable std_inc which gets its value from option –nonstdinc (by default is 1), and cxx_stdinc comes from std_cxx_inc which is set by –nonstdinc++ (by default is 1). Then, if searching for header files in the standard system directories is not prohibited, appends the standard include chain into heads lists by add_standard_paths

 

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  }

 

Structure default_include holds the information of the default list of directories to search for include files. It may be overridden by the various -I and -ixxx options. All these directories are treated as `system' include directories (they are not subject to pedantic warnings in some cases).

 

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    };

 

On Linux platform, cpp_GCC_INCLUDE_DIR is empty, so cpp_GCC_INCLUDE_DIR_len is 0. For cpp_include_defaults at line 149 above, upon my machine (Linux), it just contains following content. These paths are considered as 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    };

 

After adding all header file searching paths, it needs merge the four include chains together in the order of quote, bracket, system, after into one chain, during which removes duplicate directories. It is done by 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    }

 

In remove_duplicates, for each duplicate path in chain head, keep just the first one. Remove each path in chain head that also exists in chain system. Set the next pointer of the last path in the resulting chain to join, unless it duplicates join in which case the last path is removed (for the case, the node next to the last becomes the last, and repeating the step till no duplicate node in join is found, so concatenates head and join). This shows that in head and join chain, duplicate path can present unless join is 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    }

 

In register_include_chains, after executing merge_include_chains, now searching sequence of header files is set as quote, bracket, system, then after. Notice that below, parameters quote refers to include path of quote header files, bracket refers to include path of bracket header files. Then cpp_set_include_chains sets parse_in – object of parser, accordingly.

 

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 }

 

See that only using –I- switch, can appear nonempty quote chain (refer to split_quote_chain, and description of -I-). Otherwise, in parser object, quote_include and bracket_include are same.

你可能感兴趣的:(struct,search,System,Path,include,Duplicates)