c-pch.c: Add comments in various places.
[gcc.git] / gcc / c-pch.c
1 /* Precompiled header implementation for the C languages.
2 Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "version.h"
25 #include "cpplib.h"
26 #include "tree.h"
27 #include "flags.h"
28 #include "c-common.h"
29 #include "output.h"
30 #include "toplev.h"
31 #include "debug.h"
32 #include "c-pragma.h"
33 #include "ggc.h"
34 #include "langhooks.h"
35 #include "hosthooks.h"
36
37 /* This structure is read very early when validating the PCH, and
38 might be read for a PCH which is for a completely different compiler
39 for a different operating system. Thus, it should really only contain
40 'unsigned char' entries, at least in the initial entries.
41
42 If you add or change entries before version_length, you should increase
43 the version number in get_ident(). */
44
45 struct c_pch_validity
46 {
47 unsigned char host_machine_length;
48 unsigned char target_machine_length;
49 unsigned char version_length;
50 unsigned char debug_info_type;
51 };
52
53 struct c_pch_header
54 {
55 unsigned long asm_size;
56 };
57
58 #define IDENT_LENGTH 8
59
60 /* The file we'll be writing the PCH to. */
61 static FILE *pch_outfile;
62
63 /* The position in the assembler output file when pch_init was called. */
64 static long asm_file_startpos;
65
66 /* The host and target machines. */
67 static const char host_machine[] = HOST_MACHINE;
68 static const char target_machine[] = TARGET_MACHINE;
69
70 static const char *get_ident (void);
71
72 /* Compute an appropriate 8-byte magic number for the PCH file, so that
73 utilities like file(1) can identify it, and so that GCC can quickly
74 ignore non-PCH files and PCH files that are of a completely different
75 format. */
76
77 static const char *
78 get_ident(void)
79 {
80 static char result[IDENT_LENGTH];
81 static const char template[IDENT_LENGTH] = "gpch.012";
82 static const char c_language_chars[] = "Co+O";
83
84 memcpy (result, template, IDENT_LENGTH);
85 result[4] = c_language_chars[c_language];
86
87 return result;
88 }
89
90 /* Prepare to write a PCH file. This is called at the start of
91 compilation. */
92
93 void
94 pch_init (void)
95 {
96 FILE *f;
97 struct c_pch_validity v;
98
99 if (! pch_file)
100 return;
101
102 f = fopen (pch_file, "w+b");
103 if (f == NULL)
104 fatal_error ("can't open %s: %m", pch_file);
105 pch_outfile = f;
106
107 if (strlen (host_machine) > 255 || strlen (target_machine) > 255
108 || strlen (version_string) > 255)
109 abort ();
110
111 v.host_machine_length = strlen (host_machine);
112 v.target_machine_length = strlen (target_machine);
113 v.version_length = strlen (version_string);
114
115 v.debug_info_type = write_symbols;
116 if (fwrite (get_ident(), IDENT_LENGTH, 1, f) != 1
117 || fwrite (&v, sizeof (v), 1, f) != 1
118 || fwrite (host_machine, v.host_machine_length, 1, f) != 1
119 || fwrite (target_machine, v.target_machine_length, 1, f) != 1
120 || fwrite (version_string, v.version_length, 1, f) != 1)
121 fatal_error ("can't write to %s: %m", pch_file);
122
123 /* We need to be able to re-read the output. */
124 /* The driver always provides a valid -o option. */
125 if (asm_file_name == NULL
126 || strcmp (asm_file_name, "-") == 0)
127 fatal_error ("`%s' is not a valid output file", asm_file_name);
128
129 asm_file_startpos = ftell (asm_out_file);
130
131 /* Let the debugging format deal with the PCHness. */
132 (*debug_hooks->handle_pch) (0);
133
134 cpp_save_state (parse_in, f);
135 }
136
137 /* Write the PCH file. This is called at the end of a compilation which
138 will produce a PCH file. */
139
140 void
141 c_common_write_pch (void)
142 {
143 char *buf;
144 long asm_file_end;
145 long written;
146 struct c_pch_header h;
147
148 (*debug_hooks->handle_pch) (1);
149
150 cpp_write_pch_deps (parse_in, pch_outfile);
151
152 asm_file_end = ftell (asm_out_file);
153 h.asm_size = asm_file_end - asm_file_startpos;
154
155 if (fwrite (&h, sizeof (h), 1, pch_outfile) != 1)
156 fatal_error ("can't write %s: %m", pch_file);
157
158 buf = xmalloc (16384);
159 fflush (asm_out_file);
160
161 if (fseek (asm_out_file, asm_file_startpos, SEEK_SET) != 0)
162 fatal_error ("can't seek in %s: %m", asm_file_name);
163
164 for (written = asm_file_startpos; written < asm_file_end; )
165 {
166 long size = asm_file_end - written;
167 if (size > 16384)
168 size = 16384;
169 if (fread (buf, size, 1, asm_out_file) != 1)
170 fatal_error ("can't read %s: %m", asm_file_name);
171 if (fwrite (buf, size, 1, pch_outfile) != 1)
172 fatal_error ("can't write %s: %m", pch_file);
173 written += size;
174 }
175 free (buf);
176 /* asm_out_file can be written afterwards, so must be flushed first. */
177 fflush (asm_out_file);
178
179 gt_pch_save (pch_outfile);
180 cpp_write_pch_state (parse_in, pch_outfile);
181
182 fclose (pch_outfile);
183 }
184
185 /* Check the PCH file called NAME, open on FD, to see if it can be used
186 in this compilation. */
187
188 int
189 c_common_valid_pch (cpp_reader *pfile, const char *name, int fd)
190 {
191 int sizeread;
192 int result;
193 char ident[IDENT_LENGTH];
194 char short_strings[256 * 3];
195 int strings_length;
196 const char *pch_ident;
197 struct c_pch_validity v;
198
199 /* Perform a quick test of whether this is a valid
200 precompiled header for the current language. */
201
202 sizeread = read (fd, ident, IDENT_LENGTH);
203 if (sizeread == -1)
204 fatal_error ("can't read %s: %m", name);
205 else if (sizeread != IDENT_LENGTH)
206 return 2;
207
208 pch_ident = get_ident();
209 if (memcmp (ident, pch_ident, IDENT_LENGTH) != 0)
210 {
211 if (cpp_get_options (pfile)->warn_invalid_pch)
212 {
213 if (memcmp (ident, pch_ident, 5) == 0)
214 /* It's a PCH, for the right language, but has the wrong version.
215 */
216 cpp_error (pfile, DL_WARNING,
217 "%s: not compatible with this GCC version", name);
218 else if (memcmp (ident, pch_ident, 4) == 0)
219 /* It's a PCH for the wrong language. */
220 cpp_error (pfile, DL_WARNING, "%s: not for %s", name,
221 lang_hooks.name);
222 else
223 /* Not any kind of PCH. */
224 cpp_error (pfile, DL_WARNING, "%s: not a PCH file", name);
225 }
226 return 2;
227 }
228
229 /* At this point, we know it's a PCH file, so it ought to be long enough
230 that we can read a c_pch_validity structure. */
231 if (read (fd, &v, sizeof (v)) != sizeof (v))
232 fatal_error ("can't read %s: %m", name);
233
234 strings_length = (v.host_machine_length + v.target_machine_length
235 + v.version_length);
236 if (read (fd, short_strings, strings_length) != strings_length)
237 fatal_error ("can't read %s: %m", name);
238 if (v.host_machine_length != strlen (host_machine)
239 || memcmp (host_machine, short_strings, strlen (host_machine)) != 0)
240 {
241 if (cpp_get_options (pfile)->warn_invalid_pch)
242 cpp_error (pfile, DL_WARNING,
243 "%s: created on host `%.*s', but used on host `%s'", name,
244 v.host_machine_length, short_strings, host_machine);
245 return 2;
246 }
247 if (v.target_machine_length != strlen (target_machine)
248 || memcmp (target_machine, short_strings + v.host_machine_length,
249 strlen (target_machine)) != 0)
250 {
251 if (cpp_get_options (pfile)->warn_invalid_pch)
252 cpp_error (pfile, DL_WARNING,
253 "%s: created for target `%.*s', but used for target `%s'",
254 name, v.target_machine_length,
255 short_strings + v.host_machine_length, target_machine);
256 return 2;
257 }
258 if (v.version_length != strlen (version_string)
259 || memcmp (version_string,
260 (short_strings + v.host_machine_length
261 + v.target_machine_length),
262 v.version_length) != 0)
263 {
264 if (cpp_get_options (pfile)->warn_invalid_pch)
265 cpp_error (pfile, DL_WARNING,
266 "%s: created by version `%.*s', but this is version `%s'",
267 name, v.version_length,
268 (short_strings + v.host_machine_length
269 + v.target_machine_length),
270 version_string);
271 return 2;
272 }
273
274 /* The allowable debug info combinations are that either the PCH file
275 was built with the same as is being used now, or the PCH file was
276 built for some kind of debug info but now none is in use. */
277 if (v.debug_info_type != write_symbols
278 && write_symbols != NO_DEBUG)
279 {
280 if (cpp_get_options (pfile)->warn_invalid_pch)
281 cpp_error (pfile, DL_WARNING,
282 "%s: created with -g%s, but used with -g%s", name,
283 debug_type_names[v.debug_info_type],
284 debug_type_names[write_symbols]);
285 return 2;
286 }
287
288 /* Check the preprocessor macros are the same as when the PCH was
289 generated. */
290
291 result = cpp_valid_state (pfile, name, fd);
292 if (result == -1)
293 return 2;
294 else
295 return result == 0;
296 }
297
298 /* Load in the PCH file NAME, open on FD. It was originally searched for
299 by ORIG_NAME. */
300
301 void
302 c_common_read_pch (cpp_reader *pfile, const char *name,
303 int fd, const char *orig_name ATTRIBUTE_UNUSED)
304 {
305 FILE *f;
306 struct c_pch_header h;
307 char *buf;
308 unsigned long written;
309 struct save_macro_data *smd;
310
311 f = fdopen (fd, "rb");
312 if (f == NULL)
313 {
314 cpp_errno (pfile, DL_ERROR, "calling fdopen");
315 return;
316 }
317
318 cpp_get_callbacks (parse_in)->valid_pch = NULL;
319
320 if (fread (&h, sizeof (h), 1, f) != 1)
321 {
322 cpp_errno (pfile, DL_ERROR, "reading");
323 return;
324 }
325
326 buf = xmalloc (16384);
327 for (written = 0; written < h.asm_size; )
328 {
329 long size = h.asm_size - written;
330 if (size > 16384)
331 size = 16384;
332 if (fread (buf, size, 1, f) != 1
333 || fwrite (buf, size, 1, asm_out_file) != 1)
334 cpp_errno (pfile, DL_ERROR, "reading");
335 written += size;
336 }
337 free (buf);
338
339 cpp_prepare_state (pfile, &smd);
340
341 gt_pch_restore (f);
342
343 if (cpp_read_state (pfile, name, f, smd) != 0)
344 return;
345
346 fclose (f);
347 }
348
349 /* Indicate that no more PCH files should be read. */
350
351 void
352 c_common_no_more_pch (void)
353 {
354 if (cpp_get_callbacks (parse_in)->valid_pch)
355 {
356 cpp_get_callbacks (parse_in)->valid_pch = NULL;
357 host_hooks.gt_pch_use_address (NULL, 0);
358 }
359 }