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

4.1.3. 读入源代码

现在cpp_reader已经就绪,是时候读入源文件了。在下面,宏input_line访问全局变量input_locationline域。这个全局变量记录了当前文件名及当前处理行号。

 

c_common_post_option (continue)

 

1162   saved_lineno = input_line;

1163   input_line = 0;

1164

1165   /* If an error has occurred in cpplib, note it so we fail

1166     immediately.  */

1167   errorcount += cpp_errors (parse_in);

1168

1169   *pfilename = this_input_filename

1170     = cpp_read_main_file (parse_in, in_fnames[0]);

1171   /* Don't do any compilation or preprocessing if there is no input file.  */

1172   if (this_input_filename == NULL)

1173   {

1174     errorcount++;

1175     return false;

1176   }

1177

1178   if (flag_working_directory

1179       && flag_preprocess_only && ! flag_no_line_commands)

1180     pp_dir_change (parse_in, get_src_pwd ());

1181

1182   return flag_preprocess_only;

1183 }

 

注意到在上面in_fnames[0]持有命令行中第一个输入文件名(见handle_options453行)。它是源文件之一。

 

456    const char *

457    cpp_read_main_file (cpp_reader *pfile, const char *fname)                         in cppinit.c

458    {

459      if (CPP_OPTION (pfile, deps.style) != DEPS_NONE)

460      {

461        if (!pfile->deps)

462          pfile->deps = deps_init ();

463   

464        /* Set the default target (if there is none already).  */

465        deps_add_default_target (pfile->deps, fname);

466      }

 

首先,如果应用了-M(M)-M(M)D选项或环境变量DEPENDENCIES_OUTPUT,希望编译器为之生成适用于make的依赖规则,那么需要收集能用于makefile的目标。下面181行,如果目标是-,表示输出至stdout,而对于其他目标,则为文件名换上合适的后缀。

 

173    void

174    deps_add_default_target (struct deps *d, const char *tgt)                                    in mkdeps.c

175    {

176      /* Only if we have no targets.  */

177      if (d->ntargets)

178        return;

179   

180      if (tgt[0] == '/0')

181        deps_add_target (d, "-", 1);

182      else

183      {

184    #ifndef TARGET_OBJECT_SUFFIX

185    # define TARGET_OBJECT_SUFFIX ".o"

186    #endif

187        const char *start = lbasename (tgt);

188        char *o = alloca (strlen (start) + strlen (TARGET_OBJECT_SUFFIX) + 1);

189        char *suffix;

190   

191        strcpy (o, start);

192   

193        suffix = strrchr (o, '.');

194        if (!suffix)

195          suffix = o + strlen (o);

196        strcpy (suffix, TARGET_OBJECT_SUFFIX);

197   

198        deps_add_target (d, o, 1);

199      }

200    }

 

2个会产生make依赖规则的选项是-MT-MQ,其由handle_deferred_opts处理,其中所调用的cpp_add_dependency_target,及而后的deps_add_target,的参数quote1如果是-MQ,否则为0。而在这里,quote一概为1

 

152    void

153    deps_add_target (struct deps *d, const char *t, int quote)                                    in mkdeps.c

154    {

155      if (d->ntargets == d->targets_size)

156      {

157        d->targets_size = d->targets_size * 2 + 4;

158        d->targetv = xrealloc (d->targetv,

159                            d->targets_size * sizeof (const char *));

160      }

161   

162      if (quote)

163        t = munge (t);  /* Also makes permanent copy.  */

164      else

165        t = xstrdup (t);

166   

167      d->targetv[d->ntargets++] = t;

168    }

 

函数mungeGCC期望的形式 expected form. The major issue is replacing every single ‘/’ with ‘//’, and single ‘$’ with ‘$$’.

 

49      static const char *

50      munge (const char *filename)                                                                   in mkdeps.c

51      {

52        int len;

53        const char *p, *q;

54        char *dst, *buffer;

55     

56        for (p = filename, len = 0; *p; p++, len++)

57        {

58          switch (*p)

59          {

60            case ' ':

61            case '/t':

62              /* GNU make uses a weird quoting scheme for white space.

63                A space or tab preceded by 2N+1 backslashes represents

64                N backslashes followed by space; a space or tab

65                preceded by 2N backslashes represents N backslashes at

66                the end of a file name; and backslashes in other

67                contexts should not be doubled.  */

68              for (q = p - 1; filename <= q && *q == '//';  q--)

69                len++;

70              len++;

71              break;

72     

73            case '$':

74              /* '$' is quoted by doubling it.  */

75              len++;

76              break;

77          }

78        }

79     

80        /* Now we know how big to make the buffer.  */

81        buffer = xmalloc (len + 1);

82     

83        for (p = filename, dst = buffer; *p; p++, dst++)

84        {

85          switch (*p)

86          {

87            case ' ':

88            case '/t':

89              for (q = p - 1; filename <= q && *q == '//';  q--)

90                *dst++ = '//';

91              *dst++ = '//';

92              break;

93     

94            case '$':

95              *dst++ = '$';

96              break;

97     

98            default:

99              /* nothing */;

100        }

101        *dst = *p;

102      }

103   

104      *dst = '/0';

105      return buffer;

106    }

 

千万注意,能在产生make依赖规则的选项中,除了-M(M)D外,其余均由GCCshell默认加入-E选项。

4.1.3.1.    查找并读入文件

 

cpp_read_main_file (continue)

 

468    pfile->main_file

469      = _cpp_find_file (pfile, fname, &pfile->no_search_path, false, 0);

470    if (_cpp_find_failed (pfile->main_file))

471      return NULL;

 

cpp_reader结构中,具有3个查找路径,其中bracket_include用于尖括号包含的头文件(<>),quote_include用于引号包含的头文件(””),而no_search_path用于绝对路径。在完成查找路径设置部分,已经看到bracket_includequote_include都已被设置并连接起来。现在我们不是处理头文件,因此在此使用no_search_path来作为文件查找路径(其为””)。

 

362  _cpp_file *

363  _cpp_find_file (cpp_reader *pfile, const char *fname,                                   in cppfiles.c

364               cpp_dir *start_dir, bool fake, int angle_brackets)

365  {

366    struct file_hash_entry *entry, **hash_slot;

367    _cpp_file*file;

368    bool invalid_pch = false;

369 

370    /* Ensure we get no confusion between cached files and directories.  */

371    if (start_dir == NULL)

372      cpp_error (pfile, CPP_DL_ICE, "NULL directory in find_file");

373 

374    hash_slot = (struct file_hash_entry **)

375      htab_find_slot_with_hash (pfile->file_hash, fname,

376                           htab_hash_string (fname),

377                            INSERT);

378 

379    /* First check the cache before we resort to memory allocation.  */

380    entry = search_cache (*hash_slot, start_dir);

381    if (entry)

382      return entry->u.file;

383 

384    file = make_cpp_file (pfile, start_dir, fname);

 

所有已被找到的文件都由一个哈希表记录(cpp_readerfile_hash域)以使得而后对其访问能尽可能快。这个哈希表的元素具有如下file_hash_entry类型。

 

145  struct file_hash_entry                                                                                  in cppfiles.c

146  {

147    struct file_hash_entry *next;

148    cpp_dir *start_dir;

149    union

150    {

151      _cpp_file *file;

152      cpp_dir *dir;

153    } u;

154  };

 

打开的源文件,被保存在结构体_cpp_file中。

 

57    struct _cpp_file                                                                                          in cppfiles.c

58    {

59      /* Filename as given to #include or command line switch.  */

60      const char *name;

61   

62      /* The full path used to find the file.  */

63      const char *path;

64   

65      /* The full path of the pch file.  */

66      const char *pchname;

67   

68      /* The file's path with the basename stripped. NULL if it hasn't

69        been calculated yet.  */

70      const char *dir_name;

71   

72      /* Chain through all files.  */

73      struct _cpp_file *next_file;

74   

75     /* The contents of NAME after calling read_file().  */

76      const uchar *buffer;

77   

78      /* The macro, if any, preventing re-inclusion.  */

79      const cpp_hashnode *cmacro;

80   

81      /* The directory in the search path where FILE was found. Used for

82        #include_next and determining whether a header is a system

83        header.  */

84      cpp_dir *dir;

85   

86     /* As filled in by stat(2) for the file.  */

87      struct stat st;

88   

89      /* File descriptor. Invalid if -1, otherwise open.  */

90      int fd;

91   

92      /* Zero if this file was successfully opened and stat()-ed,

93        otherwise errno obtained from failure.  */

94      int err_no;

95   

96      /* Number of times the file has been stacked for preprocessing.  */

97      unsigned short stack_count;

98   

99      /* If opened with #import or contains #pragma once.  */

100    bool once_only;

101 

102   /* If read() failed before.  */

103    bool dont_read;

104 

105   /* If this file is the main file.  */

106    bool main_file;

107 

108    /* If BUFFER above contains the true contents of the file.  */

109    bool buffer_valid;

110 

111    /* 0: file not known to be a PCH.

112      1: file is a PCH (on return from find_include_file).

113      2: file is not and never will be a valid precompiled header.

114      3: file is always a valid precompiled header.  */

115    uchar pch;

116  };

 

这里如果start_dirno_search_path(其内容为””),表明所缓存的文件是源文件。若是头文件,start_dir应为其所在目录。此处head是由在不同目录中的同名文件构成的链表,其已是所希求的文件名。

 

788  static struct file_hash_entry *

789  search_cache (struct file_hash_entry *head, const cpp_dir *start_dir)              in cppfiles.c

790  {

791    while (head && head->start_dir != start_dir)

792      head = head->next;

793 

794    return head;

795  }

 

如果文件未被哈希表所缓存,需要通过make_cpp_file为其创建一个_cpp_file对象,因为我们将要查找、打开及缓存这个文件。

 

798  static _cpp_file *

799  make_cpp_file (cpp_reader *pfile, cpp_dir *dir, const char *fname)                      in cppfiles.c

800  {

801    _cpp_file *file;

802 

803    file = xcalloc (1, sizeof (_cpp_file));

804    file->main_file = !pfile->buffer;

805    file->fd = -1;

806    file->dir = dir;

807    file->name = xstrdup (fname);

808 

809    return file;

810  }

 

完成这个_cpp_file对象的创建后,将检查在指定的路径下是否存在该文件。如果该文件不存在,则依次在相关的查找路径中查找,直至找到该文件或穷尽所有目录。注意,对于使用no_search_path作为查找目录的文件,一旦在指定的目录下找不到文件,即报错。而其他bracket_includequote_include,则依据系统及命令行或环境变量的设置,将有有序的多个目录项。

 

_cpp_find_file (continue)

 

386   /* Try each path in the include chain.  */

387    for (; !fake ;)

388    {

389      if (find_file_in_dir (pfile, file, &invalid_pch))

390        break;

391 

392      file->dir = file->dir->next;

393      if (file->dir == NULL)

394      {

395        open_file_failed (pfile, file, angle_brackets);

396        if (invalid_pch)

397        {

398          cpp_error (pfile, CPP_DL_ERROR,

399                  "one or more PCH files were found, but they were invalid");

400          if (!cpp_get_options (pfile)->warn_invalid_pch)

401            cpp_error (pfile, CPP_DL_ERROR,

402                   "use -Winvalid-pch for more information");

403        }

404        break;

405      }

406 

407      /* Only check the cache for the starting location (done above)

408        and the quote and bracket chain heads because there are no

409        other possible starting points for searches.  */

410      if (file->dir != pfile->bracket_include

411         && file->dir != pfile->quote_include)

412        continue;

413 

414      entry = search_cache (*hash_slot, file->dir);

415      if (entry)

416        break;

417    }

 

下面319行的remapdos之类的只支持短文件名的系统所设置,它需要remap_filename进行文件名映射。否则在322行,append_file_to_dir通过嫁接文件名及目录路径构建出绝对路径。

 

314  static bool

315  find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)          in cppfiles.c

316  {

317    char *path;

318 

319    if (CPP_OPTION (pfile, remap) && (path = remap_filename (pfile, file)))

320      ;

321    else

322      path = append_file_to_dir (file->name, file->dir);

323 

324    file->path = path;

325    if (pch_open_file (pfile, file, invalid_pch))

326      return true;

327 

328    if (open_file (file))

329      return true;

330 

331    if (file->err_no != ENOENT)

332    {

333      open_file_failed (pfile, file, 0);

334      return true;

335    }

336 

337    free (path);

338    file->path = file->name;

339    return false;

340  }

 

你可能感兴趣的:(struct,File,search,buffer,Path,include)