1 | /* Target file hash table management for GNU Make. |
---|
2 | Copyright (C) 1988,89,90,91,92,93,94,95,96,97 Free Software Foundation, Inc. |
---|
3 | This file is part of GNU Make. |
---|
4 | |
---|
5 | GNU Make is free software; you can redistribute it and/or modify |
---|
6 | it under the terms of the GNU General Public License as published by |
---|
7 | the Free Software Foundation; either version 2, or (at your option) |
---|
8 | any later version. |
---|
9 | |
---|
10 | GNU Make is distributed in the hope that it will be useful, |
---|
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | GNU General Public License for more details. |
---|
14 | |
---|
15 | You should have received a copy of the GNU General Public License |
---|
16 | along with GNU Make; see the file COPYING. If not, write to |
---|
17 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
18 | Boston, MA 02111-1307, USA. */ |
---|
19 | |
---|
20 | #include "make.h" |
---|
21 | |
---|
22 | #include <assert.h> |
---|
23 | |
---|
24 | #include "dep.h" |
---|
25 | #include "filedef.h" |
---|
26 | #include "job.h" |
---|
27 | #include "commands.h" |
---|
28 | #include "variable.h" |
---|
29 | |
---|
30 | |
---|
31 | /* Hash table of files the makefile knows how to make. */ |
---|
32 | |
---|
33 | #ifndef FILE_BUCKETS |
---|
34 | #define FILE_BUCKETS 1007 |
---|
35 | #endif |
---|
36 | static struct file *files[FILE_BUCKETS]; |
---|
37 | |
---|
38 | /* Whether or not .SECONDARY with no prerequisites was given. */ |
---|
39 | static int all_secondary = 0; |
---|
40 | |
---|
41 | /* Access the hash table of all file records. |
---|
42 | lookup_file given a name, return the struct file * for that name, |
---|
43 | or nil if there is none. |
---|
44 | enter_file similar, but create one if there is none. */ |
---|
45 | |
---|
46 | struct file * |
---|
47 | lookup_file (name) |
---|
48 | char *name; |
---|
49 | { |
---|
50 | register struct file *f; |
---|
51 | register char *n; |
---|
52 | register unsigned int hashval; |
---|
53 | #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) |
---|
54 | register char *lname, *ln; |
---|
55 | #endif |
---|
56 | |
---|
57 | assert (*name != '\0'); |
---|
58 | |
---|
59 | /* This is also done in parse_file_seq, so this is redundant |
---|
60 | for names read from makefiles. It is here for names passed |
---|
61 | on the command line. */ |
---|
62 | #ifdef VMS |
---|
63 | # ifndef WANT_CASE_SENSITIVE_TARGETS |
---|
64 | lname = (char *)malloc(strlen(name) + 1); |
---|
65 | for (n=name, ln=lname; *n != '\0'; ++n, ++ln) |
---|
66 | *ln = isupper((unsigned char)*n) ? tolower((unsigned char)*n) : *n; |
---|
67 | *ln = '\0'; |
---|
68 | name = lname; |
---|
69 | # endif |
---|
70 | |
---|
71 | while (name[0] == '[' && name[1] == ']' && name[2] != '\0') |
---|
72 | name += 2; |
---|
73 | #endif |
---|
74 | while (name[0] == '.' && name[1] == '/' && name[2] != '\0') |
---|
75 | { |
---|
76 | name += 2; |
---|
77 | while (*name == '/') |
---|
78 | /* Skip following slashes: ".//foo" is "foo", not "/foo". */ |
---|
79 | ++name; |
---|
80 | } |
---|
81 | |
---|
82 | if (*name == '\0') |
---|
83 | /* It was all slashes after a dot. */ |
---|
84 | #ifdef VMS |
---|
85 | name = "[]"; |
---|
86 | #else |
---|
87 | #ifdef _AMIGA |
---|
88 | name = ""; |
---|
89 | #else |
---|
90 | name = "./"; |
---|
91 | #endif /* AMIGA */ |
---|
92 | #endif /* VMS */ |
---|
93 | |
---|
94 | hashval = 0; |
---|
95 | for (n = name; *n != '\0'; ++n) |
---|
96 | HASHI (hashval, *n); |
---|
97 | hashval %= FILE_BUCKETS; |
---|
98 | |
---|
99 | for (f = files[hashval]; f != 0; f = f->next) |
---|
100 | { |
---|
101 | if (strieq (f->hname, name)) |
---|
102 | { |
---|
103 | #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) |
---|
104 | free (lname); |
---|
105 | #endif |
---|
106 | return f; |
---|
107 | } |
---|
108 | } |
---|
109 | #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) |
---|
110 | free (lname); |
---|
111 | #endif |
---|
112 | return 0; |
---|
113 | } |
---|
114 | |
---|
115 | struct file * |
---|
116 | enter_file (name) |
---|
117 | char *name; |
---|
118 | { |
---|
119 | register struct file *f, *new; |
---|
120 | register char *n; |
---|
121 | register unsigned int hashval; |
---|
122 | #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) |
---|
123 | char *lname, *ln; |
---|
124 | #endif |
---|
125 | |
---|
126 | assert (*name != '\0'); |
---|
127 | |
---|
128 | #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) |
---|
129 | lname = (char *)malloc (strlen (name) + 1); |
---|
130 | for (n = name, ln = lname; *n != '\0'; ++n, ++ln) |
---|
131 | { |
---|
132 | if (isupper((unsigned char)*n)) |
---|
133 | *ln = tolower((unsigned char)*n); |
---|
134 | else |
---|
135 | *ln = *n; |
---|
136 | } |
---|
137 | *ln = 0; |
---|
138 | /* Creates a possible leak, old value of name is unreachable, but I |
---|
139 | currently don't know how to fix it. */ |
---|
140 | name = lname; |
---|
141 | #endif |
---|
142 | |
---|
143 | hashval = 0; |
---|
144 | for (n = name; *n != '\0'; ++n) |
---|
145 | HASHI (hashval, *n); |
---|
146 | hashval %= FILE_BUCKETS; |
---|
147 | |
---|
148 | for (f = files[hashval]; f != 0; f = f->next) |
---|
149 | if (strieq (f->hname, name)) |
---|
150 | break; |
---|
151 | |
---|
152 | if (f != 0 && !f->double_colon) |
---|
153 | { |
---|
154 | #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) |
---|
155 | free(lname); |
---|
156 | #endif |
---|
157 | return f; |
---|
158 | } |
---|
159 | |
---|
160 | new = (struct file *) xmalloc (sizeof (struct file)); |
---|
161 | bzero ((char *) new, sizeof (struct file)); |
---|
162 | new->name = new->hname = name; |
---|
163 | new->update_status = -1; |
---|
164 | |
---|
165 | if (f == 0) |
---|
166 | { |
---|
167 | /* This is a completely new file. */ |
---|
168 | new->next = files[hashval]; |
---|
169 | files[hashval] = new; |
---|
170 | } |
---|
171 | else |
---|
172 | { |
---|
173 | /* There is already a double-colon entry for this file. */ |
---|
174 | new->double_colon = f; |
---|
175 | while (f->prev != 0) |
---|
176 | f = f->prev; |
---|
177 | f->prev = new; |
---|
178 | } |
---|
179 | |
---|
180 | return new; |
---|
181 | } |
---|
182 | |
---|
183 | /* Rehash FILE to NAME. This is not as simple as resetting |
---|
184 | the `hname' member, since it must be put in a new hash bucket, |
---|
185 | and possibly merged with an existing file called NAME. */ |
---|
186 | |
---|
187 | void |
---|
188 | rehash_file (file, name) |
---|
189 | register struct file *file; |
---|
190 | char *name; |
---|
191 | { |
---|
192 | char *oldname = file->hname; |
---|
193 | register unsigned int oldhash; |
---|
194 | register char *n; |
---|
195 | |
---|
196 | while (file->renamed != 0) |
---|
197 | file = file->renamed; |
---|
198 | |
---|
199 | /* Find the hash values of the old and new names. */ |
---|
200 | |
---|
201 | oldhash = 0; |
---|
202 | for (n = oldname; *n != '\0'; ++n) |
---|
203 | HASHI (oldhash, *n); |
---|
204 | |
---|
205 | file_hash_enter (file, name, oldhash, file->name); |
---|
206 | } |
---|
207 | |
---|
208 | /* Rename FILE to NAME. This is not as simple as resetting |
---|
209 | the `name' member, since it must be put in a new hash bucket, |
---|
210 | and possibly merged with an existing file called NAME. */ |
---|
211 | |
---|
212 | void |
---|
213 | rename_file (file, name) |
---|
214 | register struct file *file; |
---|
215 | char *name; |
---|
216 | { |
---|
217 | rehash_file(file, name); |
---|
218 | while (file) |
---|
219 | { |
---|
220 | file->name = file->hname; |
---|
221 | file = file->prev; |
---|
222 | } |
---|
223 | } |
---|
224 | |
---|
225 | void |
---|
226 | file_hash_enter (file, name, oldhash, oldname) |
---|
227 | register struct file *file; |
---|
228 | char *name; |
---|
229 | unsigned int oldhash; |
---|
230 | char *oldname; |
---|
231 | { |
---|
232 | unsigned int oldbucket = oldhash % FILE_BUCKETS; |
---|
233 | register unsigned int newhash, newbucket; |
---|
234 | struct file *oldfile; |
---|
235 | register char *n; |
---|
236 | register struct file *f; |
---|
237 | |
---|
238 | newhash = 0; |
---|
239 | for (n = name; *n != '\0'; ++n) |
---|
240 | HASHI (newhash, *n); |
---|
241 | newbucket = newhash % FILE_BUCKETS; |
---|
242 | |
---|
243 | /* Look for an existing file under the new name. */ |
---|
244 | |
---|
245 | for (oldfile = files[newbucket]; oldfile != 0; oldfile = oldfile->next) |
---|
246 | if (strieq (oldfile->hname, name)) |
---|
247 | break; |
---|
248 | |
---|
249 | /* If the old file is the same as the new file, never mind. */ |
---|
250 | if (oldfile == file) |
---|
251 | return; |
---|
252 | |
---|
253 | if (oldhash != 0 && (newbucket != oldbucket || oldfile != 0)) |
---|
254 | { |
---|
255 | /* Remove FILE from its hash bucket. */ |
---|
256 | |
---|
257 | struct file *lastf = 0; |
---|
258 | |
---|
259 | for (f = files[oldbucket]; f != file; f = f->next) |
---|
260 | lastf = f; |
---|
261 | |
---|
262 | if (lastf == 0) |
---|
263 | files[oldbucket] = f->next; |
---|
264 | else |
---|
265 | lastf->next = f->next; |
---|
266 | } |
---|
267 | |
---|
268 | /* Give FILE its new name. */ |
---|
269 | |
---|
270 | file->hname = name; |
---|
271 | for (f = file->double_colon; f != 0; f = f->prev) |
---|
272 | f->hname = name; |
---|
273 | |
---|
274 | if (oldfile == 0) |
---|
275 | { |
---|
276 | /* There is no existing file with the new name. */ |
---|
277 | |
---|
278 | if (newbucket != oldbucket) |
---|
279 | { |
---|
280 | /* Put FILE in its new hash bucket. */ |
---|
281 | file->next = files[newbucket]; |
---|
282 | files[newbucket] = file; |
---|
283 | } |
---|
284 | } |
---|
285 | else |
---|
286 | { |
---|
287 | /* There is an existing file with the new name. |
---|
288 | We must merge FILE into the existing file. */ |
---|
289 | |
---|
290 | register struct dep *d; |
---|
291 | |
---|
292 | if (file->cmds != 0) |
---|
293 | { |
---|
294 | if (oldfile->cmds == 0) |
---|
295 | oldfile->cmds = file->cmds; |
---|
296 | else if (file->cmds != oldfile->cmds) |
---|
297 | { |
---|
298 | /* We have two sets of commands. We will go with the |
---|
299 | one given in the rule explicitly mentioning this name, |
---|
300 | but give a message to let the user know what's going on. */ |
---|
301 | if (oldfile->cmds->fileinfo.filenm != 0) |
---|
302 | error (&file->cmds->fileinfo, |
---|
303 | _("Commands were specified for \ |
---|
304 | file `%s' at %s:%lu,"), |
---|
305 | oldname, oldfile->cmds->fileinfo.filenm, |
---|
306 | oldfile->cmds->fileinfo.lineno); |
---|
307 | else |
---|
308 | error (&file->cmds->fileinfo, |
---|
309 | _("Commands for file `%s' were found by \ |
---|
310 | implicit rule search,"), |
---|
311 | oldname); |
---|
312 | error (&file->cmds->fileinfo, |
---|
313 | _("but `%s' is now considered the same file \ |
---|
314 | as `%s'."), |
---|
315 | oldname, name); |
---|
316 | error (&file->cmds->fileinfo, |
---|
317 | _("Commands for `%s' will be ignored \ |
---|
318 | in favor of those for `%s'."), |
---|
319 | name, oldname); |
---|
320 | } |
---|
321 | } |
---|
322 | |
---|
323 | /* Merge the dependencies of the two files. */ |
---|
324 | |
---|
325 | d = oldfile->deps; |
---|
326 | if (d == 0) |
---|
327 | oldfile->deps = file->deps; |
---|
328 | else |
---|
329 | { |
---|
330 | while (d->next != 0) |
---|
331 | d = d->next; |
---|
332 | d->next = file->deps; |
---|
333 | } |
---|
334 | |
---|
335 | merge_variable_set_lists (&oldfile->variables, file->variables); |
---|
336 | |
---|
337 | if (oldfile->double_colon && file->is_target && !file->double_colon) |
---|
338 | fatal (NILF, _("can't rename single-colon `%s' to double-colon `%s'"), |
---|
339 | oldname, name); |
---|
340 | if (!oldfile->double_colon && file->double_colon) |
---|
341 | { |
---|
342 | if (oldfile->is_target) |
---|
343 | fatal (NILF, _("can't rename double-colon `%s' to single-colon `%s'"), |
---|
344 | oldname, name); |
---|
345 | else |
---|
346 | oldfile->double_colon = file->double_colon; |
---|
347 | } |
---|
348 | |
---|
349 | if (file->last_mtime > oldfile->last_mtime) |
---|
350 | /* %%% Kludge so -W wins on a file that gets vpathized. */ |
---|
351 | oldfile->last_mtime = file->last_mtime; |
---|
352 | |
---|
353 | oldfile->mtime_before_update = file->mtime_before_update; |
---|
354 | |
---|
355 | #define MERGE(field) oldfile->field |= file->field |
---|
356 | MERGE (precious); |
---|
357 | MERGE (tried_implicit); |
---|
358 | MERGE (updating); |
---|
359 | MERGE (updated); |
---|
360 | MERGE (is_target); |
---|
361 | MERGE (cmd_target); |
---|
362 | MERGE (phony); |
---|
363 | MERGE (ignore_vpath); |
---|
364 | #undef MERGE |
---|
365 | |
---|
366 | file->renamed = oldfile; |
---|
367 | } |
---|
368 | } |
---|
369 | |
---|
370 | /* Remove all nonprecious intermediate files. |
---|
371 | If SIG is nonzero, this was caused by a fatal signal, |
---|
372 | meaning that a different message will be printed, and |
---|
373 | the message will go to stderr rather than stdout. */ |
---|
374 | |
---|
375 | void |
---|
376 | remove_intermediates (sig) |
---|
377 | int sig; |
---|
378 | { |
---|
379 | register int i; |
---|
380 | register struct file *f; |
---|
381 | char doneany; |
---|
382 | |
---|
383 | /* If there's no way we will ever remove anything anyway, punt early. */ |
---|
384 | if (question_flag || touch_flag || all_secondary) |
---|
385 | return; |
---|
386 | |
---|
387 | if (sig && just_print_flag) |
---|
388 | return; |
---|
389 | |
---|
390 | doneany = 0; |
---|
391 | for (i = 0; i < FILE_BUCKETS; ++i) |
---|
392 | for (f = files[i]; f != 0; f = f->next) |
---|
393 | if (f->intermediate && (f->dontcare || !f->precious) |
---|
394 | && !f->secondary && !f->cmd_target) |
---|
395 | { |
---|
396 | int status; |
---|
397 | if (f->update_status == -1) |
---|
398 | /* If nothing would have created this file yet, |
---|
399 | don't print an "rm" command for it. */ |
---|
400 | continue; |
---|
401 | if (just_print_flag) |
---|
402 | status = 0; |
---|
403 | else |
---|
404 | { |
---|
405 | status = unlink (f->name); |
---|
406 | if (status < 0 && errno == ENOENT) |
---|
407 | continue; |
---|
408 | } |
---|
409 | if (!f->dontcare) |
---|
410 | { |
---|
411 | if (sig) |
---|
412 | error (NILF, _("*** Deleting intermediate file `%s'"), f->name); |
---|
413 | else if (!silent_flag) |
---|
414 | { |
---|
415 | if (! doneany) |
---|
416 | { |
---|
417 | fputs ("rm ", stdout); |
---|
418 | doneany = 1; |
---|
419 | } |
---|
420 | else |
---|
421 | putchar (' '); |
---|
422 | fputs (f->name, stdout); |
---|
423 | fflush (stdout); |
---|
424 | } |
---|
425 | if (status < 0) |
---|
426 | perror_with_name ("unlink: ", f->name); |
---|
427 | } |
---|
428 | } |
---|
429 | |
---|
430 | if (doneany && !sig) |
---|
431 | { |
---|
432 | putchar ('\n'); |
---|
433 | fflush (stdout); |
---|
434 | } |
---|
435 | } |
---|
436 | |
---|
437 | /* For each dependency of each file, make the `struct dep' point |
---|
438 | at the appropriate `struct file' (which may have to be created). |
---|
439 | |
---|
440 | Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT, |
---|
441 | and various other special targets. */ |
---|
442 | |
---|
443 | void |
---|
444 | snap_deps () |
---|
445 | { |
---|
446 | register struct file *f, *f2; |
---|
447 | register struct dep *d; |
---|
448 | register int i; |
---|
449 | |
---|
450 | /* Enter each dependency name as a file. */ |
---|
451 | for (i = 0; i < FILE_BUCKETS; ++i) |
---|
452 | for (f = files[i]; f != 0; f = f->next) |
---|
453 | for (f2 = f; f2 != 0; f2 = f2->prev) |
---|
454 | for (d = f2->deps; d != 0; d = d->next) |
---|
455 | if (d->name != 0) |
---|
456 | { |
---|
457 | d->file = lookup_file (d->name); |
---|
458 | if (d->file == 0) |
---|
459 | d->file = enter_file (d->name); |
---|
460 | else |
---|
461 | free (d->name); |
---|
462 | d->name = 0; |
---|
463 | } |
---|
464 | |
---|
465 | for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev) |
---|
466 | for (d = f->deps; d != 0; d = d->next) |
---|
467 | for (f2 = d->file; f2 != 0; f2 = f2->prev) |
---|
468 | f2->precious = 1; |
---|
469 | |
---|
470 | for (f = lookup_file (".PHONY"); f != 0; f = f->prev) |
---|
471 | for (d = f->deps; d != 0; d = d->next) |
---|
472 | for (f2 = d->file; f2 != 0; f2 = f2->prev) |
---|
473 | { |
---|
474 | /* Mark this file as phony and nonexistent. */ |
---|
475 | f2->phony = 1; |
---|
476 | f2->last_mtime = NONEXISTENT_MTIME; |
---|
477 | f2->mtime_before_update = NONEXISTENT_MTIME; |
---|
478 | } |
---|
479 | |
---|
480 | for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev) |
---|
481 | { |
---|
482 | /* .INTERMEDIATE with deps listed |
---|
483 | marks those deps as intermediate files. */ |
---|
484 | for (d = f->deps; d != 0; d = d->next) |
---|
485 | for (f2 = d->file; f2 != 0; f2 = f2->prev) |
---|
486 | f2->intermediate = 1; |
---|
487 | /* .INTERMEDIATE with no deps does nothing. |
---|
488 | Marking all files as intermediates is useless |
---|
489 | since the goal targets would be deleted after they are built. */ |
---|
490 | } |
---|
491 | |
---|
492 | for (f = lookup_file (".SECONDARY"); f != 0; f = f->prev) |
---|
493 | { |
---|
494 | /* .SECONDARY with deps listed |
---|
495 | marks those deps as intermediate files |
---|
496 | in that they don't get rebuilt if not actually needed; |
---|
497 | but unlike real intermediate files, |
---|
498 | these are not deleted after make finishes. */ |
---|
499 | if (f->deps) |
---|
500 | for (d = f->deps; d != 0; d = d->next) |
---|
501 | for (f2 = d->file; f2 != 0; f2 = f2->prev) |
---|
502 | f2->intermediate = f2->secondary = 1; |
---|
503 | /* .SECONDARY with no deps listed marks *all* files that way. */ |
---|
504 | else |
---|
505 | all_secondary = 1; |
---|
506 | } |
---|
507 | |
---|
508 | f = lookup_file (".EXPORT_ALL_VARIABLES"); |
---|
509 | if (f != 0 && f->is_target) |
---|
510 | export_all_variables = 1; |
---|
511 | |
---|
512 | f = lookup_file (".IGNORE"); |
---|
513 | if (f != 0 && f->is_target) |
---|
514 | { |
---|
515 | if (f->deps == 0) |
---|
516 | ignore_errors_flag = 1; |
---|
517 | else |
---|
518 | for (d = f->deps; d != 0; d = d->next) |
---|
519 | for (f2 = d->file; f2 != 0; f2 = f2->prev) |
---|
520 | f2->command_flags |= COMMANDS_NOERROR; |
---|
521 | } |
---|
522 | |
---|
523 | f = lookup_file (".SILENT"); |
---|
524 | if (f != 0 && f->is_target) |
---|
525 | { |
---|
526 | if (f->deps == 0) |
---|
527 | silent_flag = 1; |
---|
528 | else |
---|
529 | for (d = f->deps; d != 0; d = d->next) |
---|
530 | for (f2 = d->file; f2 != 0; f2 = f2->prev) |
---|
531 | f2->command_flags |= COMMANDS_SILENT; |
---|
532 | } |
---|
533 | |
---|
534 | f = lookup_file (".POSIX"); |
---|
535 | if (f != 0 && f->is_target) |
---|
536 | posix_pedantic = 1; |
---|
537 | |
---|
538 | f = lookup_file (".NOTPARALLEL"); |
---|
539 | if (f != 0 && f->is_target) |
---|
540 | not_parallel = 1; |
---|
541 | } |
---|
542 | |
---|
543 | /* Set the `command_state' member of FILE and all its `also_make's. */ |
---|
544 | |
---|
545 | void |
---|
546 | set_command_state (file, state) |
---|
547 | struct file *file; |
---|
548 | int state; |
---|
549 | { |
---|
550 | struct dep *d; |
---|
551 | |
---|
552 | file->command_state = state; |
---|
553 | |
---|
554 | for (d = file->also_make; d != 0; d = d->next) |
---|
555 | d->file->command_state = state; |
---|
556 | } |
---|
557 | |
---|
558 | /* Convert an external file timestamp to internal form. */ |
---|
559 | |
---|
560 | FILE_TIMESTAMP |
---|
561 | file_timestamp_cons (fname, s, ns) |
---|
562 | char const *fname; |
---|
563 | time_t s; |
---|
564 | int ns; |
---|
565 | { |
---|
566 | int offset = ORDINARY_MTIME_MIN + (FILE_TIMESTAMP_HI_RES ? ns : 0); |
---|
567 | FILE_TIMESTAMP product = (FILE_TIMESTAMP) s << FILE_TIMESTAMP_LO_BITS; |
---|
568 | FILE_TIMESTAMP ts = product + offset; |
---|
569 | |
---|
570 | if (! (s <= FILE_TIMESTAMP_S (ORDINARY_MTIME_MAX) |
---|
571 | && product <= ts && ts <= ORDINARY_MTIME_MAX)) |
---|
572 | { |
---|
573 | char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; |
---|
574 | ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX; |
---|
575 | file_timestamp_sprintf (buf, ts); |
---|
576 | error (NILF, _("%s: Timestamp out of range; substituting %s"), |
---|
577 | fname ? fname : _("Current time"), buf); |
---|
578 | } |
---|
579 | |
---|
580 | return ts; |
---|
581 | } |
---|
582 | |
---|
583 | /* Get and print file timestamps. */ |
---|
584 | |
---|
585 | FILE_TIMESTAMP |
---|
586 | file_timestamp_now () |
---|
587 | { |
---|
588 | time_t s; |
---|
589 | int ns; |
---|
590 | |
---|
591 | /* Don't bother with high-resolution clocks if file timestamps have |
---|
592 | only one-second resolution. The code below should work, but it's |
---|
593 | not worth the hassle of debugging it on hosts where it fails. */ |
---|
594 | if (FILE_TIMESTAMP_HI_RES) |
---|
595 | { |
---|
596 | #if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME |
---|
597 | { |
---|
598 | struct timespec timespec; |
---|
599 | if (clock_gettime (CLOCK_REALTIME, ×pec) == 0) |
---|
600 | { |
---|
601 | s = timespec.tv_sec; |
---|
602 | ns = timespec.tv_nsec; |
---|
603 | goto got_time; |
---|
604 | } |
---|
605 | } |
---|
606 | #endif |
---|
607 | #if HAVE_GETTIMEOFDAY |
---|
608 | { |
---|
609 | struct timeval timeval; |
---|
610 | if (gettimeofday (&timeval, 0) == 0) |
---|
611 | { |
---|
612 | s = timeval.tv_sec; |
---|
613 | ns = timeval.tv_usec * 1000; |
---|
614 | goto got_time; |
---|
615 | } |
---|
616 | } |
---|
617 | #endif |
---|
618 | } |
---|
619 | |
---|
620 | s = time ((time_t *) 0); |
---|
621 | ns = 0; |
---|
622 | |
---|
623 | got_time: |
---|
624 | return file_timestamp_cons (0, s, ns); |
---|
625 | } |
---|
626 | |
---|
627 | void |
---|
628 | file_timestamp_sprintf (p, ts) |
---|
629 | char *p; |
---|
630 | FILE_TIMESTAMP ts; |
---|
631 | { |
---|
632 | time_t t = FILE_TIMESTAMP_S (ts); |
---|
633 | struct tm *tm = localtime (&t); |
---|
634 | |
---|
635 | if (tm) |
---|
636 | sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d", |
---|
637 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
---|
638 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
---|
639 | else if (t < 0) |
---|
640 | sprintf (p, "%ld", (long) t); |
---|
641 | else |
---|
642 | sprintf (p, "%lu", (unsigned long) t); |
---|
643 | p += strlen (p); |
---|
644 | |
---|
645 | /* Append nanoseconds as a fraction, but remove trailing zeros. |
---|
646 | We don't know the actual timestamp resolution, since clock_getres |
---|
647 | applies only to local times, whereas this timestamp might come |
---|
648 | from a remote filesystem. So removing trailing zeros is the |
---|
649 | best guess that we can do. */ |
---|
650 | sprintf (p, ".%09ld", (long) FILE_TIMESTAMP_NS (ts)); |
---|
651 | p += strlen (p) - 1; |
---|
652 | while (*p == '0') |
---|
653 | p--; |
---|
654 | p += *p != '.'; |
---|
655 | |
---|
656 | *p = '\0'; |
---|
657 | } |
---|
658 | |
---|
659 | /* Print the data base of files. */ |
---|
660 | |
---|
661 | static void |
---|
662 | print_file (f) |
---|
663 | struct file *f; |
---|
664 | { |
---|
665 | register struct dep *d; |
---|
666 | |
---|
667 | putchar ('\n'); |
---|
668 | if (!f->is_target) |
---|
669 | puts (_("# Not a target:")); |
---|
670 | printf ("%s:%s", f->name, f->double_colon ? ":" : ""); |
---|
671 | |
---|
672 | for (d = f->deps; d != 0; d = d->next) |
---|
673 | printf (" %s", dep_name (d)); |
---|
674 | putchar ('\n'); |
---|
675 | |
---|
676 | if (f->precious) |
---|
677 | puts (_("# Precious file (prerequisite of .PRECIOUS).")); |
---|
678 | if (f->phony) |
---|
679 | puts (_("# Phony target (prerequisite of .PHONY).")); |
---|
680 | if (f->cmd_target) |
---|
681 | puts (_("# Command-line target.")); |
---|
682 | if (f->dontcare) |
---|
683 | puts (_("# A default or MAKEFILES makefile.")); |
---|
684 | puts (f->tried_implicit |
---|
685 | ? _("# Implicit rule search has been done.") |
---|
686 | : _("# Implicit rule search has not been done.")); |
---|
687 | if (f->stem != 0) |
---|
688 | printf (_("# Implicit/static pattern stem: `%s'\n"), f->stem); |
---|
689 | if (f->intermediate) |
---|
690 | puts (_("# File is an intermediate prerequisite.")); |
---|
691 | if (f->also_make != 0) |
---|
692 | { |
---|
693 | fputs (_("# Also makes:"), stdout); |
---|
694 | for (d = f->also_make; d != 0; d = d->next) |
---|
695 | printf (" %s", dep_name (d)); |
---|
696 | putchar ('\n'); |
---|
697 | } |
---|
698 | if (f->last_mtime == UNKNOWN_MTIME) |
---|
699 | puts (_("# Modification time never checked.")); |
---|
700 | else if (f->last_mtime == NONEXISTENT_MTIME) |
---|
701 | puts (_("# File does not exist.")); |
---|
702 | else if (f->last_mtime == OLD_MTIME) |
---|
703 | puts (_("# File is very old.")); |
---|
704 | else |
---|
705 | { |
---|
706 | char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; |
---|
707 | file_timestamp_sprintf (buf, f->last_mtime); |
---|
708 | printf (_("# Last modified %s\n"), buf); |
---|
709 | } |
---|
710 | puts (f->updated |
---|
711 | ? _("# File has been updated.") : _("# File has not been updated.")); |
---|
712 | switch (f->command_state) |
---|
713 | { |
---|
714 | case cs_running: |
---|
715 | puts (_("# Commands currently running (THIS IS A BUG).")); |
---|
716 | break; |
---|
717 | case cs_deps_running: |
---|
718 | puts (_("# Dependencies commands running (THIS IS A BUG).")); |
---|
719 | break; |
---|
720 | case cs_not_started: |
---|
721 | case cs_finished: |
---|
722 | switch (f->update_status) |
---|
723 | { |
---|
724 | case -1: |
---|
725 | break; |
---|
726 | case 0: |
---|
727 | puts (_("# Successfully updated.")); |
---|
728 | break; |
---|
729 | case 1: |
---|
730 | assert (question_flag); |
---|
731 | puts (_("# Needs to be updated (-q is set).")); |
---|
732 | break; |
---|
733 | case 2: |
---|
734 | puts (_("# Failed to be updated.")); |
---|
735 | break; |
---|
736 | default: |
---|
737 | puts (_("# Invalid value in `update_status' member!")); |
---|
738 | fflush (stdout); |
---|
739 | fflush (stderr); |
---|
740 | abort (); |
---|
741 | } |
---|
742 | break; |
---|
743 | default: |
---|
744 | puts (_("# Invalid value in `command_state' member!")); |
---|
745 | fflush (stdout); |
---|
746 | fflush (stderr); |
---|
747 | abort (); |
---|
748 | } |
---|
749 | |
---|
750 | if (f->variables != 0) |
---|
751 | print_file_variables (f); |
---|
752 | |
---|
753 | if (f->cmds != 0) |
---|
754 | print_commands (f->cmds); |
---|
755 | } |
---|
756 | |
---|
757 | void |
---|
758 | print_file_data_base () |
---|
759 | { |
---|
760 | register unsigned int i, nfiles, per_bucket; |
---|
761 | register struct file *file; |
---|
762 | |
---|
763 | puts (_("\n# Files")); |
---|
764 | |
---|
765 | per_bucket = nfiles = 0; |
---|
766 | for (i = 0; i < FILE_BUCKETS; ++i) |
---|
767 | { |
---|
768 | register unsigned int this_bucket = 0; |
---|
769 | |
---|
770 | for (file = files[i]; file != 0; file = file->next) |
---|
771 | { |
---|
772 | register struct file *f; |
---|
773 | |
---|
774 | ++this_bucket; |
---|
775 | |
---|
776 | for (f = file; f != 0; f = f->prev) |
---|
777 | print_file (f); |
---|
778 | } |
---|
779 | |
---|
780 | nfiles += this_bucket; |
---|
781 | if (this_bucket > per_bucket) |
---|
782 | per_bucket = this_bucket; |
---|
783 | } |
---|
784 | |
---|
785 | if (nfiles == 0) |
---|
786 | puts (_("\n# No files.")); |
---|
787 | else |
---|
788 | { |
---|
789 | printf (_("\n# %u files in %u hash buckets.\n"), nfiles, FILE_BUCKETS); |
---|
790 | #ifndef NO_FLOAT |
---|
791 | printf (_("# average %.3f files per bucket, max %u files in one bucket.\n"), |
---|
792 | ((double) nfiles) / ((double) FILE_BUCKETS), per_bucket); |
---|
793 | #endif |
---|
794 | } |
---|
795 | } |
---|
796 | |
---|
797 | /* EOF */ |
---|