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

5.4. -include包含的头文件

根据【6】,由选项–include包含的头文件应该在源文件中所包含的头文件之前被引入,但要在被–macro指定的文件处理完成后,才能被处理。如果给出了多个-include选项,那么文件要按在命令行出现的顺序被引入。

 

finish_options (continue)

 

1466   include_cursor = 0;

1467   push_command_line_include ();

1468 }

 

首先在上面的1466行,include_cursor被置为0,表示还没有处理延迟处理选项中的-include选项。注意在下面的函数里,如果我们成功地加入了一个-include选项指定头文件,我们将在1480行返回,留下剩余未处理的-include选项在deferred_opts里。

 

1471   static void

1472   push_command_line_include (void)                                                          in c-opts.c

1473   {

1474     while (include_cursor < deferred_count)

1475     {

1476       struct deferred_opt *opt = &deferred_opts[include_cursor++];

1477  

1478       if (! cpp_opts->preprocessed && opt->code == OPT_include

1479           && cpp_push_include (parse_in, opt->arg))

1480         return;

1481     }

1482  

1483     if (include_cursor == deferred_count)

1484     {

1485       include_cursor++;

1486       /* -Wunused-macros should only warn about macros defined hereafter.  */

1487       cpp_opts->warn_unused_macros = warn_unused_macros;

1488       /* Restore the line map from <command line>.  */

1489       if (! cpp_opts->preprocessed)

1490         cpp_change_file (parse_in, LC_RENAME, main_input_filename);

1491  

1492       /* Set this here so the client can change the option if it wishes,

1493         and after stacking the main file so we don't trace the main file.  */

1494       cpp_get_line_maps (parse_in)->trace_includes

1495            = cpp_opts->print_include_names;

1496     }

1497   }

 

那么如何实现依次加入多个-include指定头文件呢?答案从cb_file_change开始。在cb_file_change中,有如下2行:

 

1509     if (new_map == 0 || (new_map->reason == LC_LEAVE && MAIN_FILE_P (new_map)))

1510     push_command_line_include ();

 

cb_file_changec_common_post_options1158行,被赋予了cpp_readercb域中的file_change钩子,这个钩子在_cpp_do_file_change里,得到调用。而且在这之前,_cpp_do_file_change先调用了linemap_add来往cpp_readermap链中将插入一个记录文件变化的line_map

如果是完成了文件的读入,例如,这里对-include包含头文件,那么_cpp_pop_buffer会被_cpp_get_fresh_line所调用。_cpp_pop_buffer的定义如下:

 

1949   void

1950   _cpp_pop_buffer (cpp_reader *pfile)                                                        in cpplib.c

1951   {

1952     cpp_buffer *buffer = pfile->buffer;

1953     struct _cpp_file *inc = buffer->file;

1954     struct if_stack *ifs;

1955  

1956     /* Walk back up the conditional stack till we reach its level at

1957       entry to this file, issuing error messages.  */

1958     for (ifs = buffer->if_stack; ifs; ifs = ifs->next)

1959       cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0,

1960                           "unterminated #%s", dtable[ifs->type].name);

1961  

1962     /* In case of a missing #endif.  */

1963     pfile->state.skipping = 0;

1964  

1965     /* _cpp_do_file_change expects pfile->buffer to be the new one.  */

1966     pfile->buffer = buffer->prev;

1967  

1968     free (buffer->notes);

1969  

1970     /* Free the buffer object now; we may want to push a new buffer

1971       in _cpp_push_next_include_file.  */

1972     obstack_free (&pfile->buffer_ob, buffer);

1973  

1974     if (inc)

1975     {

1976       _cpp_pop_file_buffer (pfile, inc);

1977  

1978       _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);

1979     }

1980   }

 

上面1953行的buffer->file只有在_cpp_stack_file里才被设置,代表文件的主读入缓存,而该文件在处理过程中临时创建的读入缓存(如do_pragma),都是在obstack上创建,即不设置file域,也不需要手动释放。

对于我们的-include包含的头文件,这个line_map的构造将符合1509行条件,将通过push_command_line_include尝试读入下一-include头文件。注意其1479行的cpp_push_include里调用了_cpp_stack_include(参考堆叠文件(PCH文件除外)一节)。如此循环往复,直到所有-include头文件处理完成。

5.5. PCH头文件准备

如果在命令行上给出了选项–output-pch,头文件除了被编译外,还会产生PCH文件(预编译头文件)。在这个选项中,给出了PCH文件名,并且保存在变量pch_file里。在这里pch_init为将要产生的PCH文件准备文件头。

 

108  void

109  pch_init (void)                                                                                          in c-pch.c

110   {

111     FILE *f;

112     struct c_pch_validity v;

113     void *target_validity;

114     static const char partial_pch[IDENT_LENGTH] = "gpcWrite";

115     unsigned int current_flags_info = 0;

116    

117     if (! pch_file)

118       return;

119  

120    if (flag_unit_at_a_time)

121      current_flags_info |= FLAG_UNIT_AT_A_TIME_SET;

122 

123    f = fopen (pch_file, "w+b");

124    if (f == NULL)

125      fatal_error ("can't create precompiled header %s: %m", pch_file);

126    pch_outfile = f;

127   

128    if (strlen (host_machine) > 255 || strlen (target_machine) > 255

129        || strlen (version_string) > 255)

130      abort ();

131   

132    v.host_machine_length = strlen (host_machine);

133    v.target_machine_length = strlen (target_machine);

134    v.version_length = strlen (version_string);

135    v.debug_info_type = write_symbols;

136    v.flags_info = current_flags_info;

137    v.pch_init = &pch_init;

138    target_validity = targetm.get_pch_validity (&v.target_data_length);

139   

140    if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1

141        || fwrite (&v, sizeof (v), 1, f) != 1

142        || fwrite (host_machine, v.host_machine_length, 1, f) != 1

143        || fwrite (target_machine, v.target_machine_length, 1, f) != 1

144        || fwrite (version_string, v.version_length, 1, f) != 1

145        || fwrite (target_validity, v.target_data_length, 1, f) != 1)

146      fatal_error ("can't write to %s: %m", pch_file);

147 

148    /* We need to be able to re-read the output.  */

149   /* The driver always provides a valid -o option.  */

150    if (asm_file_name == NULL

151        || strcmp (asm_file_name, "-") == 0)

152      fatal_error ("`%s' is not a valid output file", asm_file_name);

153   

154    asm_file_startpos = ftell (asm_out_file);

155   

156    /* Let the debugging format deal with the PCHness.  */

157    (*debug_hooks->handle_pch) (0);

158   

159    cpp_save_state (parse_in, f);

160  }

 

我们已经看过,c_pch_validity描述了PCH文件的结构,参考图形pch布局。在138行,钩子get_pch_validity将为PCH文件产生目标数据。在这里,这个钩子把调用转给default_get_pch_validity

 

4069 void *

4070 default_get_pch_validity (size_t *len)                                                                in toplev.c

4071 {

4072 #ifdef TARGET_OPTIONS

4073   size_t i;

4074 #endif

4075   char *result, *r;

4076

4077   *len = sizeof (target_flags) + 2;

4078 #ifdef TARGET_OPTIONS

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

4080   {

4081     *len += 1;

4082     if (*target_options[i].variable)

4083       *len += strlen (*target_options[i].variable);

4084   }

4085 #endif

4086

4087   result = r = xmalloc (*len);

4088   r[0] = flag_pic;

4089   r[1] = flag_pie;

4090   r += 2;

4091   memcpy (r, &target_flags, sizeof (target_flags));

4092   r += sizeof (target_flags);

4093

4094 #ifdef TARGET_OPTIONS

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

4096   {

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

4098     size_t l;

4099     if (! str)

4100       str = "";

4101     l = strlen (str) + 1;

4102     memcpy (r, str, l);

4103     r += l;

4104   }

4105 #endif

4106

4107   return result;

4108 }

 

target_options的内容参考初始化与目标平台相关选项一节,而PCH文件目标数据段的布局参考图PCH文件中target data的布局

下面的函数出于依赖性检测的目的,保存parse_in中当前所有的定义。它在处理第一个源文件前执行。在那个时候,parse_in包含了由finish_options加入的定义(包括内建定义,由-D-U选项引入的定义)。这里参数f是由–output-pch 指定,保存在pch_file中的文件的打开句柄。

 

192    int

193    cpp_save_state (cpp_reader *r, FILE *f)                                                    in cpppch.c

194    {

195     /* Save the list of non-void identifiers for the dependency checking.  */

196      r->savedstate = xmalloc (sizeof (struct cpp_savedstate));

197      r->savedstate->definedhash = htab_create (100, cpp_string_hash,

198                                         cpp_string_eq, NULL);

199      cpp_forall_identifiers (r, save_idents, r->savedstate);

200     

201      /* Write out the list of defined identifiers.  */

202      cpp_forall_identifiers (r, write_macdef, f);

203   

204      return 0;

205  }

 

结构体cpp_savestate的定义如下。域definedhash是保存定义名字的哈希表。

 

103    struct cpp_savedstate                                                                                in cpppch.c

104    {

105      /* A hash table of the defined identifiers.  */

106     htab_t definedhash;

107      /* The size of the definitions of those identifiers (the size of

108        'definedstrs').  */

109      size_t hashsize;

110       /* Number of definitions */

111       size_t n_defs;

112       /* Array of definitions. In cpp_write_pch_deps it is used for sorting.  */

113       cpp_hashnode **defs;

114       /* Space for the next definition. Definitions are null-terminated

115         strings.  */

116       unsigned char *definedstrs;

117     };

 

函数cpp_forall_identifiers遍历parse_inhash_table—这个标识符所用的哈希表。我们在前面的章节已经看过,该哈希表中的节点可以有2种方式解读,一种是树节点,另一种是cpp_hashnode,即在下面传给参数hn。注意到在134行,htab_find_slot的最后的参数是INSERT,它将自动插入缺少的标识符。

 

122    static int

123    save_idents (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)

124    {

125      struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;

126     

127      if (hn->type != NT_VOID)

128      {

129        struct cpp_string news;

130        void **slot;

131   

132        news.len = NODE_LEN (hn);

133        news.text= NODE_NAME (hn);

134        slot = htab_find_slot (ss->definedhash, &news, INSERT);

135        if (*slot == NULL)

136        {

137          struct cpp_string *sp;

138          unsigned char *text;

139          

140          sp = xmalloc (sizeof (struct cpp_string));

141          *slot = sp;

142   

143          sp->len = NODE_LEN (hn);

144          sp->text = text = xmalloc (NODE_LEN (hn));

145          memcpy (text, NODE_NAME (hn), NODE_LEN (hn));

146        }

147      }

148   

149      return 1;

150    }

 

在第一次遍历中,我们得到所有标识符的名字。而在第二次遍历中,我们则记录所有的宏定义。注意,因为我们尚在预处理中,在预处理器看来,节点只有3种类型:NT_VOIDNT_MACRONT_ASSERTION

 

48      static int

49      write_macdef (cpp_reader *pfile, cpp_hashnode *hn, void *file_p)                     in cpppch.c

50      {

51        FILE *f = (FILE *) file_p;

52        switch (hn->type)

53        {

54          case NT_VOID:

55            if (! (hn->flags & NODE_POISONED))

56              return 1;

57           

58          case NT_MACRO:

59            if ((hn->flags & NODE_BUILTIN))

60              return 1;

61     

62            {

63              struct macrodef_struct s;

64              const unsigned char *defn;

65     

66              s.name_length = NODE_LEN (hn);

67              s.flags = hn->flags & NODE_POISONED;

68     

69              if (hn->type == NT_MACRO)

70              {

71                defn = cpp_macro_definition (pfile, hn);

72                s.definition_length = ustrlen (defn);

73              }

74              else

75              {

76                defn = NODE_NAME (hn);

77                s.definition_length = s.name_length;

78              }

79          

80              if (fwrite (&s, sizeof (s), 1, f) != 1

81                 || fwrite (defn, 1, s.definition_length, f) != s.definition_length)

82              {

83                cpp_errno (pfile, CPP_DL_ERROR,

84                          "while writing precompiled header");

85                return 0;

86              }

87            }

88            return 1;

89            

90          case NT_ASSERTION:

91            /* Not currently implemented.  */

92            return 1;

93     

94          default:

95            abort ();

96        }

97      }

 

宏的定义被hashnodecpp_macro域,及cpp_readermacro_buffer域所记录。其写入PCH文件的内容就如同读入宏定义一节所显示的那样。

 

1605   const unsigned char *

1606   cpp_macro_definition (cpp_reader *pfile, const cpp_hashnode *node)   in cppmacro.c

1607   {

1608     unsigned int i, len;

1609     const cpp_macro *macro = node->value.macro;

1610     unsigned char *buffer;

1611  

1612     if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))

1613     {

1614       cpp_error (pfile, CPP_DL_ICE,

1615                "invalid hash type %d in cpp_macro_definition", node->type);

1616       return 0;

1617     }

1618  

1619     /* Calculate length.  */

1620     len = NODE_LEN (node) + 2;                     /* ' ' and NUL.  */

1621     if (macro->fun_like)

1622     {

1623       len += 4;             /* "()" plus possible final ".." of named

1624                        varargs (we have + 1 below).  */

1625       for (i = 0; i < macro->paramc; i++)

1626         len += NODE_LEN (macro->params[i]) + 1; /* "," */

1627     }

1628  

1629     /* This should match below where we fill in the buffer.  */

1630     if (CPP_OPTION (pfile, traditional))

1631       len += _cpp_replacement_text_len (macro);

1632     else

1633     {

1634       for (i = 0; i < macro->count; i++)

1635       {

1636         cpp_token *token = &macro->exp.tokens[i];

1637  

1638         if (token->type == CPP_MACRO_ARG)

1639           len += NODE_LEN (macro->params[token->val.arg_no - 1]);

1640        else

1641           len += cpp_token_len (token);

1642  

1643         if (token->flags & STRINGIFY_ARG)

1644           len++;                /* "#" */

1645         if (token->flags & PASTE_LEFT)

1646           len += 3;             /* " ##" */

1647         if (token->flags & PREV_WHITE)

1648           len++;              /* " " */

1649       }

1650     }

1651  

1652     if (len > pfile->macro_buffer_len)

1653     {

1654       pfile->macro_buffer = xrealloc (pfile->macro_buffer, len);

1655       pfile->macro_buffer_len = len;

1656     }

1657  

1658     /* Fill in the buffer. Start with the macro name.  */

1659     buffer = pfile->macro_buffer;

1660     memcpy (buffer, NODE_NAME (node), NODE_LEN (node));

1661     buffer += NODE_LEN (node);

1662  

1663     /* Parameter names.  */

1664     if (macro->fun_like)

1665     {

1666       *buffer++ = '(';

1667       for (i = 0; i < macro->paramc; i++)

1668       {

1669         cpp_hashnode *param = macro->params[i];

1670  

1671         if (param != pfile->spec_nodes.n__VA_ARGS__)

1672         {

1673           memcpy (buffer, NODE_NAME (param), NODE_LEN (param));

1674           buffer += NODE_LEN (param);

1675         }

1676  

1677         if (i + 1 < macro->paramc)

1678           /* Don't emit a space after the comma here; we're trying

1679             to emit a Dwarf-friendly definition, and the Dwarf spec

1680             forbids spaces in the argument list.  */

1681          *buffer++ = ',';

1682         else if (macro->variadic)

1683          *buffer++ = '.', *buffer++ = '.', *buffer++ = '.';

1684       }

1685       *buffer++ = ')';

1686     }

1687  

1688     /* The Dwarf spec requires a space after the macro name, even if the

1689       definition is the empty string.  */

1690     *buffer++ = ' ';

1691  

1692     if (CPP_OPTION (pfile, traditional))

1693       buffer = _cpp_copy_replacement_text (macro, buffer);

1694     else if (macro->count)

1695     /* Expansion tokens.  */

1696     {

1697       for (i = 0; i < macro->count; i++)

1698       {

1699         cpp_token *token = &macro->exp.tokens[i];

1700  

1701         if (token->flags & PREV_WHITE)

1702           *buffer++ = ' ';

1703         if (token->flags & STRINGIFY_ARG)

1704           *buffer++ = '#';

1705  

1706         if (token->type == CPP_MACRO_ARG)

1707         {

1708           memcpy (buffer,

1709                   NODE_NAME (macro->params[token->val.arg_no - 1]),

1710                   NODE_LEN (macro->params[token->val.arg_no - 1]));

1711           buffer += NODE_LEN (macro->params[token->val.arg_no - 1]);

1712         }

1713         else

1714           buffer = cpp_spell_token (pfile, token, buffer);

1715  

1716         if (token->flags & PASTE_LEFT)

1717         {

1718           *buffer++ = ' ';

1719           *buffer++ = '#';

1720           *buffer++ = '#';

1721           /* Next has PREV_WHITE; see _cpp_create_definition.  */

1722         }

1723       }

1724     }

1725  

1726     *buffer = '/0';

1727     return pfile->macro_buffer;

1728   }

 

这个函数走入宏的定义,首先计算出所需要的缓存,然后拷贝在macro_buffer中的整个定义,接着返回write_macrodef 将其写入PCH文件。

 

你可能感兴趣的:(struct,String,File,buffer,token,include)