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

4.1.3.1.1.1.      验证PCH文件

如果PCH文件找到了,需确保它是有效的。

 

1257 static bool

1258 validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname)          in cppfiles.c

1259 {

1260   const char *saved_path = file->path;

1261   bool valid = false;

1262

1263   file->path = pchname;

1264   if (open_file (file))

1265   {

1266     valid = 1 & pfile->cb.valid_pch (pfile, pchname, file->fd);

1267

1268     if (!valid)

1269     {

1270       close (file->fd);

1271       file->fd = -1;

1272     }

1273

1274     if (CPP_OPTION (pfile, print_include_names))

1275     {

1276       unsigned int i;

1277       for (i = 1; i < pfile->line_maps.depth; i++)

1278         putc ('.', stderr);

1279       fprintf (stderr, "%c %s/n",

1280             valid ? '!' : 'x', pchname);

1281     }

1282   }

1283

1284   file->path = saved_path;

1285   return valid;

1286 }

 

预编译头文件的格式尚未统一,GCC以后可能会引入其他预编译头文件的格式,因此cpp_reader提供钩子cb绑定指定的预编译头文件的各种操作函数。对于C++/Cinit_c_lex完成了这个绑定。钩子cb的定义如下,只有最后2个域是用于预编译头文件的,其他域则也为其他相应的操作提供了灵活的架构。

 

379  struct cpp_callbacks                                                                                    in cpplib.h

380  {

381    /* Called when a new line of preprocessed output is started.  */

382    void (*line_change) (cpp_reader *, const cpp_token *, int);

383 

384    /* Called when switching to/from a new file.

385      The line_map is for the new file. It is NULL if there is no new file.

386      (In C this happens when done with <built-in>+<command line> and also

387      when done with a main file.)  This can be used for resource cleanup.  */

388    void (*file_change) (cpp_reader *, const struct line_map *);

389 

390    void (*dir_change) (cpp_reader *, const char *);

391    void (*include) (cpp_reader *, unsigned int, const unsigned char *,

392                   const char *, int);

393    void (*define) (cpp_reader *, unsigned int, cpp_hashnode *);

394    void (*undef) (cpp_reader *, unsigned int, cpp_hashnode *);

395    void (*ident) (cpp_reader *, unsigned int, const cpp_string *);

396    void (*def_pragma) (cpp_reader *, unsigned int);

397    int (*valid_pch) (cpp_reader *, const char *, int);

398    void (*read_pch) (cpp_reader *, const char *, int, const char *);

399  };

 

当前的valid_pch,对于C/C++c_common_valid_pch。对于PCH文件,文件的最开头包含8字节的识别码,后跟一个如下定义的c_pch_validity结构。

 

53    struct c_pch_validity                                                                                   in c-pch.c

54    {

55      unsigned char host_machine_length;

56      unsigned char target_machine_length;

57      unsigned char version_length;

58      unsigned char debug_info_type;

59      unsigned int flags_info;

60      void (*pch_init) (void);

61      size_t target_data_length;

62    };

 

c_common_valid_pch中,很容易就知道通常一个PCH文件,在开头有如下内容:

 

9PCH文件的布局

 

debug_info_type表明了要产生的调试信息的类型,而flags_info被设置为1,如果在生成PCH文件时使用了选项-funit-at-a-time

 

219  int

220  c_common_valid_pch (cpp_reader *pfile, const char *name, int fd)                in c-pch.c

221  {

222    int sizeread;

223    int result;

224    char ident[IDENT_LENGTH];

225    char short_strings[256 * 3];

226    int strings_length;

227    const char *pch_ident;

228    struct c_pch_validity v;

229    unsigned int current_flags_info = 0;

230 

231    if (flag_unit_at_a_time)

232      current_flags_info |= FLAG_UNIT_AT_A_TIME_SET;

233 

234    /* Perform a quick test of whether this is a valid

235      precompiled header for the current language

236      and with the current flag settings.  */

237 

238    sizeread = read (fd, ident, IDENT_LENGTH);

239    if (sizeread == -1)

240      fatal_error ("can't read %s: %m", name);

241    else if (sizeread != IDENT_LENGTH)

242      return 2;

243   

244    pch_ident = get_ident();

245    if (memcmp (ident, pch_ident, IDENT_LENGTH) != 0)

246    {

247      if (cpp_get_options (pfile)->warn_invalid_pch)

248      {

249        if (memcmp (ident, pch_ident, 5) == 0)

250          /* It's a PCH, for the right language, but has the wrong version.

251           */

252          cpp_error (pfile, CPP_DL_WARNING,

253                   "%s: not compatible with this GCC version", name);

254        else if (memcmp (ident, pch_ident, 4) == 0)

255          /* It's a PCH for the wrong language.  */

256          cpp_error (pfile, CPP_DL_WARNING, "%s: not for %s", name,

257                   lang_hooks.name);

258        else

259           /* Not any kind of PCH.  */

260           cpp_error (pfile, CPP_DL_WARNING, "%s: not a PCH file", name);

261      }

262      return 2;

263    }

264 

265    /* At this point, we know it's a PCH file, so it ought to be long enough

266      that we can read a c_pch_validity structure.  */

267    if (read (fd, &v, sizeof (v)) != sizeof (v))

268      fatal_error ("can't read %s: %m", name);

269 

270    strings_length = (v.host_machine_length + v.target_machine_length

271                    + v.version_length);

272    if (read (fd, short_strings, strings_length) != strings_length)

273      fatal_error ("can't read %s: %m", name);

274    if (v.host_machine_length != strlen (host_machine)

275        || memcmp (host_machine, short_strings, strlen (host_machine)) != 0)

276    {

277      if (cpp_get_options (pfile)->warn_invalid_pch)

278        cpp_error (pfile, CPP_DL_WARNING,

279                   "%s: created on host `%.*s', but used on host `%s'", name,

280                   v.host_machine_length, short_strings, host_machine);

281        return 2;

282    }

283    if (v.target_machine_length != strlen (target_machine)

284        || memcmp (target_machine, short_strings + v.host_machine_length,

285                strlen (target_machine)) != 0)

286   {

287      if (cpp_get_options (pfile)->warn_invalid_pch)

288        cpp_error (pfile, CPP_DL_WARNING,

289                    "%s: created for target `%.*s', but used for target `%s'",

290                    name, v.target_machine_length,

291                    short_strings + v.host_machine_length, target_machine);

292        return 2;

293    }

294    if (v.version_length != strlen (version_string)

295        || memcmp (version_string,

296                  (short_strings + v.host_machine_length

297                   + v.target_machine_length),

298                   v.version_length) != 0)

299    {

300      if (cpp_get_options (pfile)->warn_invalid_pch)

301        cpp_error (pfile, CPP_DL_WARNING,

302                   "%s: created by version `%.*s', but this is version `%s'",

303                   name, v.version_length,

304                   (short_strings + v.host_machine_length

305                    + v.target_machine_length),

306                   version_string);

307        return 2;

308    }

309    if (v.flags_info != current_flags_info)

310    {

311      if (cpp_get_options (pfile)->warn_invalid_pch)

312        cpp_error (pfile, CPP_DL_WARNING,

313                  "%s: created using different flags",

314                  name);

315      return 2;

316    }

317 

318    /* The allowable debug info combinations are that either the PCH file

319      was built with the same as is being used now, or the PCH file was

320      built for some kind of debug info but now none is in use.  */

321    if (v.debug_info_type != write_symbols

322        && write_symbols != NO_DEBUG)

323    {

324      if (cpp_get_options (pfile)->warn_invalid_pch)

325        cpp_error (pfile, CPP_DL_WARNING,

326                   "%s: created with -g%s, but used with -g%s", name,

327                   debug_type_names[v.debug_info_type],

328                   debug_type_names[write_symbols]);

329      return 2;

330    }

331 

332   /* If the text segment was not loaded at the same address as it was

333      when the PCH file was created, function pointers loaded from the

334      PCH will not be valid. We could in theory remap all the function

335      pointers, but no support for that exists at present.  */

336    if (v.pch_init != &pch_init)

337    {

338      if (cpp_get_options (pfile)->warn_invalid_pch)

339        cpp_error (pfile, CPP_DL_WARNING,

340                   "%s: had text segment at different address", name);

341      return 2;

342    }

343 

344    /* Check the target-specific validity data.  */

345    {

346      void *this_file_data = xmalloc (v.target_data_length);

347      const char *msg;

348     

349      if ((size_t) read (fd, this_file_data, v.target_data_length)

350          != v.target_data_length)

351        fatal_error ("can't read %s: %m", name);

352      msg = targetm.pch_valid_p (this_file_data, v.target_data_length);

353      free (this_file_data);

354      if (msg != NULL)

355      {

356        if (cpp_get_options (pfile)->warn_invalid_pch)

357          cpp_error (pfile, CPP_DL_WARNING, "%s: %s", name, msg);

358        return 2;

359      }

360    }

361 

362    /* Check the preprocessor macros are the same as when the PCH was

363      generated.  */

364   

365    result = cpp_valid_state (pfile, name, fd);

366    if (result == -1)

367      return 2;

368    else

369      return result == 0;

370  }

 

如果target_data之前的域都是有效的,紧接着这个数据的验证是依赖于目标平台的。然而对于GCC目前所支持的大部平台,默认的方法就可以了。

 

4112 const char *

4113 default_pch_valid_p (const void *data_p, size_t len)                                     in toplev.c

4114 {

4115   const char *data = (const char *)data_p;

4116   const char *flag_that_differs = NULL;

4117   size_t i;

4118

4119   /* -fpic and -fpie also usually make a PCH invalid.  */

4120   if (data[0] != flag_pic)

4121     return _("created and used with different settings of -fpic");

4122   if (data[1] != flag_pie)

4123     return _("created and used with different settings of -fpie");

4124   data += 2;

4125

4126   /* Check target_flags.  */

4127   if (memcmp (data, &target_flags, sizeof (target_flags)) != 0)

4128   {

4129     for (i = 0; i < ARRAY_SIZE (target_switches); i++)

4130     {

4131       int bits;

4132       int tf;

4133

4134       memcpy (&tf, data, sizeof (target_flags));

4135

4136       bits = target_switches[i].value;

4137       if (bits < 0)

4138         bits = -bits;

4139       if ((target_flags & bits) != (tf & bits))

4140       {

4141         flag_that_differs = target_switches[i].name;

4142         goto make_message;

4143       }

4144     }

4145     abort ();

4146   }

4147   data += sizeof (target_flags);

4148   len -= sizeof (target_flags);

4149

4150   /* Check string options.  */

4151 #ifdef TARGET_OPTIONS

4152   for (i = 0; i < ARRAY_SIZE (target_options); i++)

4153   {

4154     const char *str = *target_options[i].variable;

4155     size_t l;

4156     if (! str)

4157       str = "";

4158     l = strlen (str) + 1;

4159     if (len < l || memcmp (data, str, l) != 0)

4160     {

4161       flag_that_differs = target_options[i].prefix;

4162       goto make_message;

4163     }

4164     data += l;

4165     len -= l;

4166   }

4167 #endif

4168

4169   return NULL;

4170

4171  make_message:

4172   {

4173     char *r;

4174     asprintf (&r, _("created and used with differing settings of `-m%s'"),

4175                flag_that_differs);

4176     if (r == NULL)

4177       return _("out of memory");

4178     return r;

4179   }

4180 }

 

在函数中,可以看到target_data包含了以下信息。在初始化与目标平台相关选项一节中,我们已经看过了target_flagstarget_options的含义和设置。作为有效的PCH文件,其target_data必须与当前的所使用的相应的数据匹配。注意到在target_options部分,所有的目标选项都会出现,那些没有在编译中使用的选项,其内容将是“/0”

GCC-3.4.6源代码学习笔记(31)_第1张图片

10PCH文件中target data的布局

如果PCH文件是有效的,它即是我们所希冀的,因此在find_file_in_dir326行即可返回。否则就要尝试打开普通文件。

 

_cpp_find_file (continue)

 

418      if (entry)

419      {

420        /* Cache for START_DIR too, sharing the _cpp_file structure.  */

421        free ((char *) file->name);

422        free (file);

423        file = entry->u.file;

424      }

425      else

426      {

427        /* This is a new file; put it in the list.  */

428        file->next_file = pfile->all_files;

429        pfile->all_files = file;

430      }

431   

432      /* Store this new result in the hash table.  */

433      entry = new_file_hash_entry (pfile);

434      entry->next = *hash_slot;

435      entry->start_dir = start_dir;

436      entry->u.file = file;

437      *hash_slot = entry;

438   

439      return file;

440    }

 

如果418行的entry不为NULL,即找到缓存的文件,但此文件不是在start_dir所指定的目录下发现的。为了使今后在start_dir下查找该文件,不至于重复上面的操作,同样需要创建一个entrystart_dir和该文件绑定。

 

你可能感兴趣的:(String,struct,File,preprocessor,Pointers,combinations)