VirtualBox

source: kBuild/trunk/src/gmake/remake.c@ 311

Last change on this file since 311 was 287, checked in by bird, 20 years ago

join + optimizations.

  • Property svn:eol-style set to native
File size: 44.6 KB
Line 
1/* Basic dependency engine for GNU Make.
2Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999,
32002 Free Software Foundation, Inc.
4This file is part of GNU Make.
5
6GNU Make is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Make is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Make; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include "make.h"
22#include "filedef.h"
23#include "job.h"
24#include "commands.h"
25#include "dep.h"
26#include "variable.h"
27#include "debug.h"
28
29#include <assert.h>
30
31#ifdef HAVE_FCNTL_H
32#include <fcntl.h>
33#else
34#include <sys/file.h>
35#endif
36
37#ifdef VMS
38#include <starlet.h>
39#endif
40#ifdef WINDOWS32
41#include <io.h>
42#endif
43
44extern int try_implicit_rule PARAMS ((struct file *file, unsigned int depth));
45
46
47/* The test for circular dependencies is based on the 'updating' bit in
48 `struct file'. However, double colon targets have seperate `struct
49 file's; make sure we always use the base of the double colon chain. */
50
51#define start_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\
52 ->updating = 1)
53#define finish_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\
54 ->updating = 0)
55#define is_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\
56 ->updating)
57
58
59/* Incremented when a command is started (under -n, when one would be). */
60unsigned int commands_started = 0;
61
62/* Current value for pruning the scan of the goal chain (toggle 0/1). */
63static unsigned int considered;
64
65static int update_file PARAMS ((struct file *file, unsigned int depth));
66static int update_file_1 PARAMS ((struct file *file, unsigned int depth));
67static int check_dep PARAMS ((struct file *file, unsigned int depth, FILE_TIMESTAMP this_mtime, int *must_make_ptr));
68static int touch_file PARAMS ((struct file *file));
69static void remake_file PARAMS ((struct file *file));
70static FILE_TIMESTAMP name_mtime PARAMS ((char *name));
71static int library_search PARAMS ((char **lib, FILE_TIMESTAMP *mtime_ptr));
72
73
74
75/* Remake all the goals in the `struct dep' chain GOALS. Return -1 if nothing
76 was done, 0 if all goals were updated successfully, or 1 if a goal failed.
77
78 If rebuilding_makefiles is nonzero, these goals are makefiles, so -t, -q,
79 and -n should be disabled for them unless they were also command-line
80 targets, and we should only make one goal at a time and return as soon as
81 one goal whose `changed' member is nonzero is successfully made. */
82
83int
84update_goal_chain (struct dep *goals)
85{
86 int t = touch_flag, q = question_flag, n = just_print_flag;
87 unsigned int j = job_slots;
88 int status = -1;
89
90#define MTIME(file) (rebuilding_makefiles ? file_mtime_no_search (file) \
91 : file_mtime (file))
92
93 /* Duplicate the chain so we can remove things from it. */
94
95 goals = copy_dep_chain (goals);
96
97 {
98 /* Clear the `changed' flag of each goal in the chain.
99 We will use the flag below to notice when any commands
100 have actually been run for a target. When no commands
101 have been run, we give an "up to date" diagnostic. */
102
103 struct dep *g;
104 for (g = goals; g != 0; g = g->next)
105 g->changed = 0;
106 }
107
108 /* All files start with the considered bit 0, so the global value is 1. */
109 considered = 1;
110
111 /* Update all the goals until they are all finished. */
112
113 while (goals != 0)
114 {
115 register struct dep *g, *lastgoal;
116
117 /* Start jobs that are waiting for the load to go down. */
118
119 start_waiting_jobs ();
120
121 /* Wait for a child to die. */
122
123 reap_children (1, 0);
124
125 lastgoal = 0;
126 g = goals;
127 while (g != 0)
128 {
129 /* Iterate over all double-colon entries for this file. */
130 struct file *file;
131 int stop = 0, any_not_updated = 0;
132
133 for (file = g->file->double_colon ? g->file->double_colon : g->file;
134 file != NULL;
135 file = file->prev)
136 {
137 unsigned int ocommands_started;
138 int x;
139 check_renamed (file);
140 if (rebuilding_makefiles)
141 {
142 if (file->cmd_target)
143 {
144 touch_flag = t;
145 question_flag = q;
146 just_print_flag = n;
147 }
148 else
149 touch_flag = question_flag = just_print_flag = 0;
150 }
151
152 /* Save the old value of `commands_started' so we can compare
153 later. It will be incremented when any commands are
154 actually run. */
155 ocommands_started = commands_started;
156
157 x = update_file (file, rebuilding_makefiles ? 1 : 0);
158 check_renamed (file);
159
160 /* Set the goal's `changed' flag if any commands were started
161 by calling update_file above. We check this flag below to
162 decide when to give an "up to date" diagnostic. */
163 g->changed += commands_started - ocommands_started;
164
165 /* If we updated a file and STATUS was not already 1, set it to
166 1 if updating failed, or to 0 if updating succeeded. Leave
167 STATUS as it is if no updating was done. */
168
169 stop = 0;
170 if ((x != 0 || file->updated) && status < 1)
171 {
172 if (file->update_status != 0)
173 {
174 /* Updating failed, or -q triggered. The STATUS value
175 tells our caller which. */
176 status = file->update_status;
177 /* If -q just triggered, stop immediately. It doesn't
178 matter how much more we run, since we already know
179 the answer to return. */
180 stop = (question_flag && !keep_going_flag
181 && !rebuilding_makefiles);
182 }
183 else
184 {
185 FILE_TIMESTAMP mtime = MTIME (file);
186 check_renamed (file);
187
188 if (file->updated && g->changed &&
189 mtime != file->mtime_before_update)
190 {
191 /* Updating was done. If this is a makefile and
192 just_print_flag or question_flag is set (meaning
193 -n or -q was given and this file was specified
194 as a command-line target), don't change STATUS.
195 If STATUS is changed, we will get re-exec'd, and
196 enter an infinite loop. */
197 if (!rebuilding_makefiles
198 || (!just_print_flag && !question_flag))
199 status = 0;
200 if (rebuilding_makefiles && file->dontcare)
201 /* This is a default makefile; stop remaking. */
202 stop = 1;
203 }
204 }
205 }
206
207 /* Keep track if any double-colon entry is not finished.
208 When they are all finished, the goal is finished. */
209 any_not_updated |= !file->updated;
210
211 if (stop)
212 break;
213 }
214
215 /* Reset FILE since it is null at the end of the loop. */
216 file = g->file;
217
218 if (stop || !any_not_updated)
219 {
220 /* If we have found nothing whatever to do for the goal,
221 print a message saying nothing needs doing. */
222
223 if (!rebuilding_makefiles
224 /* If the update_status is zero, we updated successfully
225 or not at all. G->changed will have been set above if
226 any commands were actually started for this goal. */
227 && file->update_status == 0 && !g->changed
228 /* Never give a message under -s or -q. */
229 && !silent_flag && !question_flag)
230 message (1, ((file->phony || file->cmds == 0)
231 ? _("Nothing to be done for `%s'.")
232 : _("`%s' is up to date.")),
233 file->name);
234
235 /* This goal is finished. Remove it from the chain. */
236 if (lastgoal == 0)
237 goals = g->next;
238 else
239 lastgoal->next = g->next;
240
241 /* Free the storage. */
242 free ((char *) g);
243
244 g = lastgoal == 0 ? goals : lastgoal->next;
245
246 if (stop)
247 break;
248 }
249 else
250 {
251 lastgoal = g;
252 g = g->next;
253 }
254 }
255
256 /* If we reached the end of the dependency graph toggle the considered
257 flag for the next pass. */
258 if (g == 0)
259 considered = !considered;
260 }
261
262 if (rebuilding_makefiles)
263 {
264 touch_flag = t;
265 question_flag = q;
266 just_print_flag = n;
267 job_slots = j;
268 }
269 return status;
270}
271
272
273/* If FILE is not up to date, execute the commands for it.
274 Return 0 if successful, 1 if unsuccessful;
275 but with some flag settings, just call `exit' if unsuccessful.
276
277 DEPTH is the depth in recursions of this function.
278 We increment it during the consideration of our dependencies,
279 then decrement it again after finding out whether this file
280 is out of date.
281
282 If there are multiple double-colon entries for FILE,
283 each is considered in turn. */
284
285static int
286update_file (struct file *file, unsigned int depth)
287{
288 register int status = 0;
289 register struct file *f;
290
291 f = file->double_colon ? file->double_colon : file;
292
293 /* Prune the dependency graph: if we've already been here on _this_
294 pass through the dependency graph, we don't have to go any further.
295 We won't reap_children until we start the next pass, so no state
296 change is possible below here until then. */
297 if (f->considered == considered)
298 {
299 DBF (DB_VERBOSE, _("Pruning file `%s'.\n"));
300 return f->command_state == cs_finished ? f->update_status : 0;
301 }
302
303 /* This loop runs until we start commands for a double colon rule, or until
304 the chain is exhausted. */
305 for (; f != 0; f = f->prev)
306 {
307 f->considered = considered;
308
309 status |= update_file_1 (f, depth);
310 check_renamed (f);
311
312 /* If we got an error, don't bother with double_colon etc. */
313 if (status != 0 && !keep_going_flag)
314 return status;
315
316 if (f->command_state == cs_running
317 || f->command_state == cs_deps_running)
318 {
319 /* Don't run the other :: rules for this
320 file until this rule is finished. */
321 status = 0;
322 break;
323 }
324 }
325
326 /* Process the remaining rules in the double colon chain so they're marked
327 considered. Start their prerequisites, too. */
328 if (file->double_colon)
329 for (; f != 0 ; f = f->prev)
330 {
331 struct dep *d;
332
333 f->considered = considered;
334
335 for (d = f->deps; d != 0; d = d->next)
336 status |= update_file (d->file, depth + 1);
337 }
338
339 return status;
340}
341
342
343/* Show a message stating the target failed to build. */
344
345static void
346complain (const struct file *file)
347{
348 const char *msg_noparent
349 = _("%sNo rule to make target `%s'%s");
350 const char *msg_parent
351 = _("%sNo rule to make target `%s', needed by `%s'%s");
352
353 if (!keep_going_flag)
354 {
355 if (file->parent == 0)
356 fatal (NILF, msg_noparent, "", file->name, "");
357
358 fatal (NILF, msg_parent, "", file->name, file->parent->name, "");
359 }
360
361 if (file->parent == 0)
362 error (NILF, msg_noparent, "*** ", file->name, ".");
363 else
364 error (NILF, msg_parent, "*** ", file->name, file->parent->name, ".");
365}
366
367/* Consider a single `struct file' and update it as appropriate. */
368
369static int
370update_file_1 (struct file *file, unsigned int depth)
371{
372 register FILE_TIMESTAMP this_mtime;
373 int noexist, must_make, deps_changed;
374 int dep_status = 0;
375 register struct dep *d, *lastd;
376 int running = 0;
377
378 DBF (DB_VERBOSE, _("Considering target file `%s'.\n"));
379
380 if (file->updated)
381 {
382 if (file->update_status > 0)
383 {
384 DBF (DB_VERBOSE,
385 _("Recently tried and failed to update file `%s'.\n"));
386
387 /* If the file we tried to make is marked dontcare then no message
388 was printed about it when it failed during the makefile rebuild.
389 If we're trying to build it again in the normal rebuild, print a
390 message now. */
391 if (file->dontcare && !rebuilding_makefiles)
392 {
393 file->dontcare = 0;
394 complain (file);
395 }
396
397 return file->update_status;
398 }
399
400 DBF (DB_VERBOSE, _("File `%s' was considered already.\n"));
401 return 0;
402 }
403
404 switch (file->command_state)
405 {
406 case cs_not_started:
407 case cs_deps_running:
408 break;
409 case cs_running:
410 DBF (DB_VERBOSE, _("Still updating file `%s'.\n"));
411 return 0;
412 case cs_finished:
413 DBF (DB_VERBOSE, _("Finished updating file `%s'.\n"));
414 return file->update_status;
415 default:
416 abort ();
417 }
418
419 ++depth;
420
421 /* Notice recursive update of the same file. */
422 start_updating (file);
423
424 /* Looking at the file's modtime beforehand allows the possibility
425 that its name may be changed by a VPATH search, and thus it may
426 not need an implicit rule. If this were not done, the file
427 might get implicit commands that apply to its initial name, only
428 to have that name replaced with another found by VPATH search. */
429
430 this_mtime = file_mtime (file);
431 check_renamed (file);
432 noexist = this_mtime == NONEXISTENT_MTIME;
433 if (noexist)
434 DBF (DB_BASIC, _("File `%s' does not exist.\n"));
435 else if (ORDINARY_MTIME_MIN <= this_mtime && this_mtime <= ORDINARY_MTIME_MAX
436 && file->low_resolution_time)
437 {
438 /* Avoid spurious rebuilds due to low resolution time stamps. */
439 int ns = FILE_TIMESTAMP_NS (this_mtime);
440 if (ns != 0)
441 error (NILF, _("*** Warning: .LOW_RESOLUTION_TIME file `%s' has a high resolution time stamp"),
442 file->name);
443 this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns;
444 }
445
446 must_make = noexist;
447
448 /* If file was specified as a target with no commands,
449 come up with some default commands. */
450
451 if (!file->phony && file->cmds == 0 && !file->tried_implicit)
452 {
453 if (try_implicit_rule (file, depth))
454 DBF (DB_IMPLICIT, _("Found an implicit rule for `%s'.\n"));
455 else
456 DBF (DB_IMPLICIT, _("No implicit rule found for `%s'.\n"));
457 file->tried_implicit = 1;
458 }
459 if (file->cmds == 0 && !file->is_target
460 && default_file != 0 && default_file->cmds != 0)
461 {
462 DBF (DB_IMPLICIT, _("Using default commands for `%s'.\n"));
463 file->cmds = default_file->cmds;
464 }
465
466 /* Update all non-intermediate files we depend on, if necessary,
467 and see whether any of them is more recent than this file. */
468
469 lastd = 0;
470 d = file->deps;
471 while (d != 0)
472 {
473 FILE_TIMESTAMP mtime;
474 int maybe_make;
475 int dontcare = 0;
476
477 check_renamed (d->file);
478
479 mtime = file_mtime (d->file);
480 check_renamed (d->file);
481
482 if (is_updating (d->file))
483 {
484 error (NILF, _("Circular %s <- %s dependency dropped."),
485 file->name, d->file->name);
486 /* We cannot free D here because our the caller will still have
487 a reference to it when we were called recursively via
488 check_dep below. */
489 if (lastd == 0)
490 file->deps = d->next;
491 else
492 lastd->next = d->next;
493 d = d->next;
494 continue;
495 }
496
497 d->file->parent = file;
498 maybe_make = must_make;
499
500 /* Inherit dontcare flag from our parent. */
501 if (rebuilding_makefiles)
502 {
503 dontcare = d->file->dontcare;
504 d->file->dontcare = file->dontcare;
505 }
506
507
508 dep_status |= check_dep (d->file, depth, this_mtime, &maybe_make);
509
510 /* Restore original dontcare flag. */
511 if (rebuilding_makefiles)
512 d->file->dontcare = dontcare;
513
514 if (! d->ignore_mtime)
515 must_make = maybe_make;
516
517 check_renamed (d->file);
518
519 {
520 register struct file *f = d->file;
521 if (f->double_colon)
522 f = f->double_colon;
523 do
524 {
525 running |= (f->command_state == cs_running
526 || f->command_state == cs_deps_running);
527 f = f->prev;
528 }
529 while (f != 0);
530 }
531
532 if (dep_status != 0 && !keep_going_flag)
533 break;
534
535 if (!running)
536 d->changed = file_mtime (d->file) != mtime;
537
538 lastd = d;
539 d = d->next;
540 }
541
542 /* Now we know whether this target needs updating.
543 If it does, update all the intermediate files we depend on. */
544
545 if (must_make || always_make_flag)
546 {
547 for (d = file->deps; d != 0; d = d->next)
548 if (d->file->intermediate)
549 {
550 int dontcare = 0;
551
552 FILE_TIMESTAMP mtime = file_mtime (d->file);
553 check_renamed (d->file);
554 d->file->parent = file;
555
556 /* Inherit dontcare flag from our parent. */
557 if (rebuilding_makefiles)
558 {
559 dontcare = d->file->dontcare;
560 d->file->dontcare = file->dontcare;
561 }
562
563
564 dep_status |= update_file (d->file, depth);
565
566 /* Restore original dontcare flag. */
567 if (rebuilding_makefiles)
568 d->file->dontcare = dontcare;
569
570 check_renamed (d->file);
571
572 {
573 register struct file *f = d->file;
574 if (f->double_colon)
575 f = f->double_colon;
576 do
577 {
578 running |= (f->command_state == cs_running
579 || f->command_state == cs_deps_running);
580 f = f->prev;
581 }
582 while (f != 0);
583 }
584
585 if (dep_status != 0 && !keep_going_flag)
586 break;
587
588 if (!running)
589 d->changed = ((file->phony && file->cmds != 0)
590 || file_mtime (d->file) != mtime);
591 }
592 }
593
594 finish_updating (file);
595
596 DBF (DB_VERBOSE, _("Finished prerequisites of target file `%s'.\n"));
597
598 if (running)
599 {
600 set_command_state (file, cs_deps_running);
601 --depth;
602 DBF (DB_VERBOSE, _("The prerequisites of `%s' are being made.\n"));
603 return 0;
604 }
605
606 /* If any dependency failed, give up now. */
607
608 if (dep_status != 0)
609 {
610 file->update_status = dep_status;
611 notice_finished_file (file);
612
613 --depth;
614
615 DBF (DB_VERBOSE, _("Giving up on target file `%s'.\n"));
616
617 if (depth == 0 && keep_going_flag
618 && !just_print_flag && !question_flag)
619 error (NILF,
620 _("Target `%s' not remade because of errors."), file->name);
621
622 return dep_status;
623 }
624
625 if (file->command_state == cs_deps_running)
626 /* The commands for some deps were running on the last iteration, but
627 they have finished now. Reset the command_state to not_started to
628 simplify later bookkeeping. It is important that we do this only
629 when the prior state was cs_deps_running, because that prior state
630 was definitely propagated to FILE's also_make's by set_command_state
631 (called above), but in another state an also_make may have
632 independently changed to finished state, and we would confuse that
633 file's bookkeeping (updated, but not_started is bogus state). */
634 set_command_state (file, cs_not_started);
635
636 /* Now record which prerequisites are more
637 recent than this file, so we can define $?. */
638
639 deps_changed = 0;
640 for (d = file->deps; d != 0; d = d->next)
641 {
642 FILE_TIMESTAMP d_mtime = file_mtime (d->file);
643 check_renamed (d->file);
644
645 if (! d->ignore_mtime)
646 {
647#if 1
648 /* %%% In version 4, remove this code completely to
649 implement not remaking deps if their deps are newer
650 than their parents. */
651 if (d_mtime == NONEXISTENT_MTIME && !d->file->intermediate)
652 /* We must remake if this dep does not
653 exist and is not intermediate. */
654 must_make = 1;
655#endif
656
657 /* Set DEPS_CHANGED if this dep actually changed. */
658 deps_changed |= d->changed;
659 }
660
661 /* Set D->changed if either this dep actually changed,
662 or its dependent, FILE, is older or does not exist. */
663 d->changed |= noexist || d_mtime > this_mtime;
664
665 if (!noexist && ISDB (DB_BASIC|DB_VERBOSE))
666 {
667 const char *fmt = 0;
668
669 if (d->ignore_mtime)
670 {
671 if (ISDB (DB_VERBOSE))
672 fmt = _("Prerequisite `%s' is order-only for target `%s'.\n");
673 }
674 else if (d_mtime == NONEXISTENT_MTIME)
675 {
676 if (ISDB (DB_BASIC))
677 fmt = _("Prerequisite `%s' of target `%s' does not exist.\n");
678 }
679 else if (d->changed)
680 {
681 if (ISDB (DB_BASIC))
682 fmt = _("Prerequisite `%s' is newer than target `%s'.\n");
683 }
684 else if (ISDB (DB_VERBOSE))
685 fmt = _("Prerequisite `%s' is older than target `%s'.\n");
686
687 if (fmt)
688 {
689 print_spaces (depth);
690 printf (fmt, dep_name (d), file->name);
691 fflush (stdout);
692 }
693 }
694 }
695
696 /* Here depth returns to the value it had when we were called. */
697 depth--;
698
699 if (file->double_colon && file->deps == 0)
700 {
701 must_make = 1;
702 DBF (DB_BASIC,
703 _("Target `%s' is double-colon and has no prerequisites.\n"));
704 }
705 else if (!noexist && file->is_target && !deps_changed && file->cmds == 0
706 && !always_make_flag)
707 {
708 must_make = 0;
709 DBF (DB_VERBOSE,
710 _("No commands for `%s' and no prerequisites actually changed.\n"));
711 }
712 else if (!must_make && file->cmds != 0 && always_make_flag)
713 {
714 must_make = 1;
715 DBF (DB_VERBOSE, _("Making `%s' due to always-make flag.\n"));
716 }
717
718 if (!must_make)
719 {
720 if (ISDB (DB_VERBOSE))
721 {
722 print_spaces (depth);
723 printf (_("No need to remake target `%s'"), file->name);
724 if (!streq (file->name, file->hname))
725 printf (_("; using VPATH name `%s'"), file->hname);
726 puts (".");
727 fflush (stdout);
728 }
729
730 notice_finished_file (file);
731
732 /* Since we don't need to remake the file, convert it to use the
733 VPATH filename if we found one. hfile will be either the
734 local name if no VPATH or the VPATH name if one was found. */
735
736 while (file)
737 {
738 file->name = file->hname;
739 file = file->prev;
740 }
741
742 return 0;
743 }
744
745 DBF (DB_BASIC, _("Must remake target `%s'.\n"));
746
747 /* It needs to be remade. If it's VPATH and not reset via GPATH, toss the
748 VPATH. */
749 if (!streq(file->name, file->hname))
750 {
751 DB (DB_BASIC, (_(" Ignoring VPATH name `%s'.\n"), file->hname));
752 file->ignore_vpath = 1;
753 }
754
755 /* Now, take appropriate actions to remake the file. */
756 remake_file (file);
757
758 if (file->command_state != cs_finished)
759 {
760 DBF (DB_VERBOSE, _("Commands of `%s' are being run.\n"));
761 return 0;
762 }
763
764 switch (file->update_status)
765 {
766 case 2:
767 DBF (DB_BASIC, _("Failed to remake target file `%s'.\n"));
768 break;
769 case 0:
770 DBF (DB_BASIC, _("Successfully remade target file `%s'.\n"));
771 break;
772 case 1:
773 DBF (DB_BASIC, _("Target file `%s' needs remade under -q.\n"));
774 break;
775 default:
776 assert (file->update_status >= 0 && file->update_status <= 2);
777 break;
778 }
779
780 file->updated = 1;
781 return file->update_status;
782}
783
784
785/* Set FILE's `updated' flag and re-check its mtime and the mtime's of all
786 files listed in its `also_make' member. Under -t, this function also
787 touches FILE.
788
789 On return, FILE->update_status will no longer be -1 if it was. */
790
791void
792notice_finished_file (struct file *file)
793{
794 struct dep *d;
795 int ran = file->command_state == cs_running;
796 int touched = 0;
797DB (DB_JOBS, (_("notice_finished_file - entering: file=%p `%s' update_status=%d command_state=%d\n"), file, file->name, file->update_status, file->command_state));
798 file->command_state = cs_finished;
799 file->updated = 1;
800
801 /* update not_parallel if the file was flagged for that. */
802 if (ran && (file->command_flags & COMMANDS_NOTPARALLEL))
803 {
804 assert(not_parallel == 1);
805 DB (DB_KMK, (_("not_parallel %d -> %d (file=%p `%s')\n"), not_parallel, not_parallel - 1, file, file->name));
806 --not_parallel;
807 }
808
809 if (touch_flag
810 /* The update status will be:
811 -1 if this target was not remade;
812 0 if 0 or more commands (+ or ${MAKE}) were run and won;
813 1 if some commands were run and lost.
814 We touch the target if it has commands which either were not run
815 or won when they ran (i.e. status is 0). */
816 && file->update_status == 0)
817 {
818 if (file->cmds != 0 && file->cmds->any_recurse)
819 {
820 /* If all the command lines were recursive,
821 we don't want to do the touching. */
822 unsigned int i;
823 for (i = 0; i < file->cmds->ncommand_lines; ++i)
824 if (!(file->cmds->lines_flags[i] & COMMANDS_RECURSE))
825 goto have_nonrecursing;
826 }
827 else
828 {
829 have_nonrecursing:
830 if (file->phony)
831 file->update_status = 0;
832 /* According to POSIX, -t doesn't affect targets with no cmds. */
833 else if (file->cmds != 0)
834 {
835 /* Should set file's modification date and do nothing else. */
836 file->update_status = touch_file (file);
837
838 /* Pretend we ran a real touch command, to suppress the
839 "`foo' is up to date" message. */
840 commands_started++;
841
842 /* Request for the timestamp to be updated (and distributed
843 to the double-colon entries). Simply setting ran=1 would
844 almost have done the trick, but messes up with the also_make
845 updating logic below. */
846 touched = 1;
847 }
848 }
849 }
850
851 if (file->mtime_before_update == UNKNOWN_MTIME)
852 file->mtime_before_update = file->last_mtime;
853
854 if ((ran && !file->phony) || touched)
855 {
856 struct file *f;
857 int i = 0;
858
859 /* If -n, -t, or -q and all the commands are recursive, we ran them so
860 really check the target's mtime again. Otherwise, assume the target
861 would have been updated. */
862
863 if (question_flag || just_print_flag || touch_flag)
864 {
865 for (i = file->cmds->ncommand_lines; i > 0; --i)
866 if (! (file->cmds->lines_flags[i-1] & COMMANDS_RECURSE))
867 break;
868 }
869
870 /* If there were no commands at all, it's always new. */
871
872 else if (file->is_target && file->cmds == 0)
873 i = 1;
874
875 file->last_mtime = i == 0 ? UNKNOWN_MTIME : NEW_MTIME;
876
877 /* Propagate the change of modification time to all the double-colon
878 entries for this file. */
879 for (f = file->double_colon; f != 0; f = f->prev)
880 f->last_mtime = file->last_mtime;
881 }
882
883 if (ran && file->update_status != -1)
884 /* We actually tried to update FILE, which has
885 updated its also_make's as well (if it worked).
886 If it didn't work, it wouldn't work again for them.
887 So mark them as updated with the same status. */
888 for (d = file->also_make; d != 0; d = d->next)
889 {
890 d->file->command_state = cs_finished;
891 d->file->updated = 1;
892 d->file->update_status = file->update_status;
893
894 if (ran && !d->file->phony)
895 /* Fetch the new modification time.
896 We do this instead of just invalidating the cached time
897 so that a vpath_search can happen. Otherwise, it would
898 never be done because the target is already updated. */
899 (void) f_mtime (d->file, 0);
900 }
901 else if (file->update_status == -1)
902 /* Nothing was done for FILE, but it needed nothing done.
903 So mark it now as "succeeded". */
904 file->update_status = 0;
905
906DB (DB_JOBS, (_("notice_finished_file - leaving: file=%p `%s' update_status=%d command_state=%d\n"), file, file->name, file->update_status, file->command_state));
907}
908
909
910/* Check whether another file (whose mtime is THIS_MTIME)
911 needs updating on account of a dependency which is file FILE.
912 If it does, store 1 in *MUST_MAKE_PTR.
913 In the process, update any non-intermediate files
914 that FILE depends on (including FILE itself).
915 Return nonzero if any updating failed. */
916
917static int
918check_dep (struct file *file, unsigned int depth,
919 FILE_TIMESTAMP this_mtime, int *must_make_ptr)
920{
921 struct dep *d;
922 int dep_status = 0;
923
924 ++depth;
925 start_updating (file);
926
927 if (file->phony || !file->intermediate)
928 {
929 /* If this is a non-intermediate file, update it and record
930 whether it is newer than THIS_MTIME. */
931 FILE_TIMESTAMP mtime;
932 dep_status = update_file (file, depth);
933 check_renamed (file);
934 mtime = file_mtime (file);
935 check_renamed (file);
936 if (mtime == NONEXISTENT_MTIME || mtime > this_mtime)
937 *must_make_ptr = 1;
938 }
939 else
940 {
941 /* FILE is an intermediate file. */
942 FILE_TIMESTAMP mtime;
943
944 if (!file->phony && file->cmds == 0 && !file->tried_implicit)
945 {
946 if (try_implicit_rule (file, depth))
947 DBF (DB_IMPLICIT, _("Found an implicit rule for `%s'.\n"));
948 else
949 DBF (DB_IMPLICIT, _("No implicit rule found for `%s'.\n"));
950 file->tried_implicit = 1;
951 }
952 if (file->cmds == 0 && !file->is_target
953 && default_file != 0 && default_file->cmds != 0)
954 {
955 DBF (DB_IMPLICIT, _("Using default commands for `%s'.\n"));
956 file->cmds = default_file->cmds;
957 }
958
959 /* If the intermediate file actually exists
960 and is newer, then we should remake from it. */
961 check_renamed (file);
962 mtime = file_mtime (file);
963 check_renamed (file);
964 if (mtime != NONEXISTENT_MTIME && mtime > this_mtime)
965 *must_make_ptr = 1;
966 /* Otherwise, update all non-intermediate files we depend on,
967 if necessary, and see whether any of them is more
968 recent than the file on whose behalf we are checking. */
969 else
970 {
971 struct dep *lastd;
972
973 lastd = 0;
974 d = file->deps;
975 while (d != 0)
976 {
977 int maybe_make;
978
979 if (is_updating (d->file))
980 {
981 error (NILF, _("Circular %s <- %s dependency dropped."),
982 file->name, d->file->name);
983 if (lastd == 0)
984 {
985 file->deps = d->next;
986 free ((char *) d);
987 d = file->deps;
988 }
989 else
990 {
991 lastd->next = d->next;
992 free ((char *) d);
993 d = lastd->next;
994 }
995 continue;
996 }
997
998 d->file->parent = file;
999 maybe_make = *must_make_ptr;
1000 dep_status |= check_dep (d->file, depth, this_mtime,
1001 &maybe_make);
1002 if (! d->ignore_mtime)
1003 *must_make_ptr = maybe_make;
1004 check_renamed (d->file);
1005 if (dep_status != 0 && !keep_going_flag)
1006 break;
1007
1008 if (d->file->command_state == cs_running
1009 || d->file->command_state == cs_deps_running)
1010 /* Record that some of FILE's deps are still being made.
1011 This tells the upper levels to wait on processing it until
1012 the commands are finished. */
1013 set_command_state (file, cs_deps_running);
1014
1015 lastd = d;
1016 d = d->next;
1017 }
1018 }
1019 }
1020
1021 finish_updating (file);
1022 return dep_status;
1023}
1024
1025
1026/* Touch FILE. Return zero if successful, one if not. */
1027
1028#define TOUCH_ERROR(call) return (perror_with_name (call, file->name), 1)
1029
1030static int
1031touch_file (struct file *file)
1032{
1033 if (!silent_flag)
1034 message (0, "touch %s", file->name);
1035
1036#ifndef NO_ARCHIVES
1037 if (ar_name (file->name))
1038 return ar_touch (file->name);
1039 else
1040#endif
1041 {
1042 int fd = open (file->name, O_RDWR | O_CREAT, 0666);
1043
1044 if (fd < 0)
1045 TOUCH_ERROR ("touch: open: ");
1046 else
1047 {
1048 struct stat statbuf;
1049 char buf;
1050 int e;
1051
1052 EINTRLOOP (e, fstat (fd, &statbuf));
1053 if (e < 0)
1054 TOUCH_ERROR ("touch: fstat: ");
1055 /* Rewrite character 0 same as it already is. */
1056 if (read (fd, &buf, 1) < 0)
1057 TOUCH_ERROR ("touch: read: ");
1058 if (lseek (fd, 0L, 0) < 0L)
1059 TOUCH_ERROR ("touch: lseek: ");
1060 if (write (fd, &buf, 1) < 0)
1061 TOUCH_ERROR ("touch: write: ");
1062 /* If file length was 0, we just
1063 changed it, so change it back. */
1064 if (statbuf.st_size == 0)
1065 {
1066 (void) close (fd);
1067 fd = open (file->name, O_RDWR | O_TRUNC, 0666);
1068 if (fd < 0)
1069 TOUCH_ERROR ("touch: open: ");
1070 }
1071 (void) close (fd);
1072 }
1073 }
1074
1075 return 0;
1076}
1077
1078
1079/* Having checked and updated the dependencies of FILE,
1080 do whatever is appropriate to remake FILE itself.
1081 Return the status from executing FILE's commands. */
1082
1083static void
1084remake_file (struct file *file)
1085{
1086 if (file->cmds == 0)
1087 {
1088 if (file->phony)
1089 /* Phony target. Pretend it succeeded. */
1090 file->update_status = 0;
1091 else if (file->is_target)
1092 /* This is a nonexistent target file we cannot make.
1093 Pretend it was successfully remade. */
1094 file->update_status = 0;
1095 else
1096 {
1097 /* This is a dependency file we cannot remake. Fail. */
1098 if (!rebuilding_makefiles || !file->dontcare)
1099 complain (file);
1100 file->update_status = 2;
1101 }
1102 }
1103 else
1104 {
1105 chop_commands (file->cmds);
1106
1107 /* The normal case: start some commands. */
1108 if (!touch_flag || file->cmds->any_recurse)
1109 {
1110 execute_file_commands (file);
1111 return;
1112 }
1113
1114 /* This tells notice_finished_file it is ok to touch the file. */
1115 file->update_status = 0;
1116 }
1117
1118 /* This does the touching under -t. */
1119 notice_finished_file (file);
1120}
1121
1122
1123/* Return the mtime of a file, given a `struct file'.
1124 Caches the time in the struct file to avoid excess stat calls.
1125
1126 If the file is not found, and SEARCH is nonzero, VPATH searching and
1127 replacement is done. If that fails, a library (-lLIBNAME) is tried and
1128 the library's actual name (/lib/libLIBNAME.a, etc.) is substituted into
1129 FILE. */
1130
1131FILE_TIMESTAMP
1132f_mtime (struct file *file, int search)
1133{
1134 FILE_TIMESTAMP mtime;
1135
1136 /* File's mtime is not known; must get it from the system. */
1137
1138#ifndef NO_ARCHIVES
1139 if (ar_name (file->name))
1140 {
1141 /* This file is an archive-member reference. */
1142
1143 char *arname, *memname;
1144 struct file *arfile;
1145 int arname_used = 0;
1146 time_t member_date;
1147
1148 /* Find the archive's name. */
1149 ar_parse_name (file->name, &arname, &memname);
1150
1151 /* Find the modification time of the archive itself.
1152 Also allow for its name to be changed via VPATH search. */
1153 arfile = lookup_file (arname);
1154 if (arfile == 0)
1155 {
1156 arfile = enter_file (arname);
1157 arname_used = 1;
1158 }
1159 mtime = f_mtime (arfile, search);
1160 check_renamed (arfile);
1161 if (search && strcmp (arfile->hname, arname))
1162 {
1163 /* The archive's name has changed.
1164 Change the archive-member reference accordingly. */
1165
1166 char *name;
1167 unsigned int arlen, memlen;
1168
1169 if (!arname_used)
1170 {
1171 free (arname);
1172 arname_used = 1;
1173 }
1174
1175 arname = arfile->hname;
1176 arlen = strlen (arname);
1177 memlen = strlen (memname);
1178
1179 /* free (file->name); */
1180
1181 name = (char *) xmalloc (arlen + 1 + memlen + 2);
1182 bcopy (arname, name, arlen);
1183 name[arlen] = '(';
1184 bcopy (memname, name + arlen + 1, memlen);
1185 name[arlen + 1 + memlen] = ')';
1186 name[arlen + 1 + memlen + 1] = '\0';
1187
1188 /* If the archive was found with GPATH, make the change permanent;
1189 otherwise defer it until later. */
1190 if (arfile->name == arfile->hname)
1191 rename_file (file, name);
1192 else
1193 rehash_file (file, name);
1194 check_renamed (file);
1195 }
1196
1197 if (!arname_used)
1198 free (arname);
1199 free (memname);
1200
1201 file->low_resolution_time = 1;
1202
1203 if (mtime == NONEXISTENT_MTIME)
1204 /* The archive doesn't exist, so its members don't exist either. */
1205 return NONEXISTENT_MTIME;
1206
1207 member_date = ar_member_date (file->hname);
1208 mtime = (member_date == (time_t) -1
1209 ? NONEXISTENT_MTIME
1210 : file_timestamp_cons (file->hname, member_date, 0));
1211 }
1212 else
1213#endif
1214 {
1215 mtime = name_mtime (file->name);
1216
1217 if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath)
1218 {
1219 /* If name_mtime failed, search VPATH. */
1220 char *name = file->name;
1221 if (vpath_search (&name, &mtime)
1222 /* Last resort, is it a library (-lxxx)? */
1223 || (name[0] == '-' && name[1] == 'l'
1224 && library_search (&name, &mtime)))
1225 {
1226 if (mtime != UNKNOWN_MTIME)
1227 /* vpath_search and library_search store UNKNOWN_MTIME
1228 if they didn't need to do a stat call for their work. */
1229 file->last_mtime = mtime;
1230
1231 /* If we found it in VPATH, see if it's in GPATH too; if so,
1232 change the name right now; if not, defer until after the
1233 dependencies are updated. */
1234 if (gpath_search (name, strlen(name) - strlen(file->name) - 1))
1235 {
1236 rename_file (file, name);
1237 check_renamed (file);
1238 return file_mtime (file);
1239 }
1240
1241 rehash_file (file, name);
1242 check_renamed (file);
1243 mtime = name_mtime (name);
1244 }
1245 }
1246 }
1247
1248 {
1249 /* Files can have bogus timestamps that nothing newly made will be
1250 "newer" than. Updating their dependents could just result in loops.
1251 So notify the user of the anomaly with a warning.
1252
1253 We only need to do this once, for now. */
1254
1255 if (!clock_skew_detected
1256 && mtime != NONEXISTENT_MTIME
1257 && !file->updated)
1258 {
1259 static FILE_TIMESTAMP adjusted_now;
1260
1261 FILE_TIMESTAMP adjusted_mtime = mtime;
1262
1263#if defined(WINDOWS32) || defined(__MSDOS__)
1264 /* Experimentation has shown that FAT filesystems can set file times
1265 up to 3 seconds into the future! Play it safe. */
1266
1267#define FAT_ADJ_OFFSET (FILE_TIMESTAMP) 3
1268
1269 FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS;
1270 if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime)
1271 adjusted_mtime -= adjustment;
1272#elif defined(__EMX__)
1273 /* FAT filesystems round time to the nearest even second!
1274 Allow for any file (NTFS or FAT) to perhaps suffer from this
1275 brain damage. */
1276 FILE_TIMESTAMP adjustment = (((FILE_TIMESTAMP_S (adjusted_mtime) & 1) == 0
1277 && FILE_TIMESTAMP_NS (adjusted_mtime) == 0)
1278 ? (FILE_TIMESTAMP) 1 << FILE_TIMESTAMP_LO_BITS
1279 : 0);
1280#endif
1281
1282 /* If the file's time appears to be in the future, update our
1283 concept of the present and try once more. */
1284 if (adjusted_now < adjusted_mtime)
1285 {
1286 int resolution;
1287 FILE_TIMESTAMP now = file_timestamp_now (&resolution);
1288 adjusted_now = now + (resolution - 1);
1289 if (adjusted_now < adjusted_mtime)
1290 {
1291#ifdef NO_FLOAT
1292 error (NILF, _("Warning: File `%s' has modification time in the future"),
1293 file->name);
1294#else
1295 double from_now =
1296 (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now)
1297 + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now))
1298 / 1e9));
1299 error (NILF, _("Warning: File `%s' has modification time %.2g s in the future"),
1300 file->name, from_now);
1301#endif
1302 clock_skew_detected = 1;
1303 }
1304 }
1305 }
1306 }
1307
1308 /* Store the mtime into all the entries for this file. */
1309 if (file->double_colon)
1310 file = file->double_colon;
1311
1312 do
1313 {
1314 /* If this file is not implicit but it is intermediate then it was
1315 made so by the .INTERMEDIATE target. If this file has never
1316 been built by us but was found now, it existed before make
1317 started. So, turn off the intermediate bit so make doesn't
1318 delete it, since it didn't create it. */
1319 if (mtime != NONEXISTENT_MTIME && file->command_state == cs_not_started
1320 && file->command_state == cs_not_started
1321 && !file->tried_implicit && file->intermediate)
1322 file->intermediate = 0;
1323
1324 file->last_mtime = mtime;
1325 file = file->prev;
1326 }
1327 while (file != 0);
1328
1329 return mtime;
1330}
1331
1332
1333/* Return the mtime of the file or archive-member reference NAME. */
1334
1335/* First, we check with stat(). If the file does not exist, then we return
1336 NONEXISTENT_MTIME. If it does, and the symlink check flag is set, then
1337 examine each indirection of the symlink and find the newest mtime.
1338 This causes one duplicate stat() when -L is being used, but the code is
1339 much cleaner. */
1340
1341static FILE_TIMESTAMP
1342name_mtime (char *name)
1343{
1344 FILE_TIMESTAMP mtime;
1345 struct stat st;
1346 int e;
1347
1348 EINTRLOOP (e, stat (name, &st));
1349 if (e != 0)
1350 {
1351 if (errno != ENOENT && errno != ENOTDIR)
1352 perror_with_name ("stat: ", name);
1353 return NONEXISTENT_MTIME;
1354 }
1355 mtime = FILE_TIMESTAMP_STAT_MODTIME (name, st);
1356
1357#ifdef MAKE_SYMLINKS
1358#ifndef S_ISLNK
1359# define S_ISLNK(_m) (((_m)&S_IFMT)==S_IFLNK)
1360#endif
1361 if (check_symlink_flag)
1362 {
1363 PATH_VAR (lpath);
1364
1365 /* Check each symbolic link segment (if any). Find the latest mtime
1366 amongst all of them (and the target file of course).
1367 Note that we have already successfully dereferenced all the links
1368 above. So, if we run into any error trying to lstat(), or
1369 readlink(), or whatever, something bizarre-o happened. Just give up
1370 and use whatever mtime we've already computed at that point. */
1371 strcpy (lpath, name);
1372 while (1)
1373 {
1374 FILE_TIMESTAMP ltime;
1375 PATH_VAR (lbuf);
1376 long llen;
1377 char *p;
1378
1379 EINTRLOOP (e, lstat (lpath, &st));
1380 if (e)
1381 {
1382 /* Eh? Just take what we have. */
1383 perror_with_name ("lstat: ", lpath);
1384 break;
1385 }
1386
1387 /* If this is not a symlink, we're done (we started with the real
1388 file's mtime so we don't need to test it again). */
1389 if (!S_ISLNK (st.st_mode))
1390 break;
1391
1392 /* If this mtime is newer than what we had, keep the new one. */
1393 ltime = FILE_TIMESTAMP_STAT_MODTIME (lpath, st);
1394 if (ltime > mtime)
1395 mtime = ltime;
1396
1397 /* Set up to check the file pointed to by this link. */
1398 EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX));
1399 if (llen < 0)
1400 {
1401 /* Eh? Just take what we have. */
1402 perror_with_name ("readlink: ", lpath);
1403 break;
1404 }
1405 lbuf[llen] = '\0';
1406
1407 /* If the target is fully-qualified or the source is just a
1408 filename, then the new path is the target. Otherwise it's the
1409 source directory plus the target. */
1410 if (lbuf[0] == '/' || (p = strrchr (lpath, '/')) == NULL)
1411 strcpy (lpath, lbuf);
1412 else if ((p - lpath) + llen + 2 > GET_PATH_MAX)
1413 /* Eh? Path too long! Again, just go with what we have. */
1414 break;
1415 else
1416 /* Create the next step in the symlink chain. */
1417 strcpy (p+1, lbuf);
1418 }
1419 }
1420#endif
1421
1422 return mtime;
1423}
1424
1425
1426/* Search for a library file specified as -lLIBNAME, searching for a
1427 suitable library file in the system library directories and the VPATH
1428 directories. */
1429
1430static int
1431library_search (char **lib, FILE_TIMESTAMP *mtime_ptr)
1432{
1433 static char *dirs[] =
1434 {
1435#ifndef _AMIGA
1436 "/lib",
1437 "/usr/lib",
1438#endif
1439#if defined(WINDOWS32) && !defined(LIBDIR)
1440/*
1441 * This is completely up to the user at product install time. Just define
1442 * a placeholder.
1443 */
1444#define LIBDIR "."
1445#endif
1446 LIBDIR, /* Defined by configuration. */
1447 0
1448 };
1449
1450 static char *libpatterns = NULL;
1451
1452 char *libname = &(*lib)[2]; /* Name without the `-l'. */
1453 FILE_TIMESTAMP mtime;
1454
1455 /* Loop variables for the libpatterns value. */
1456 char *p, *p2;
1457 unsigned int len;
1458
1459 char *file, **dp;
1460
1461 /* If we don't have libpatterns, get it. */
1462 if (!libpatterns)
1463 {
1464 int save = warn_undefined_variables_flag;
1465 warn_undefined_variables_flag = 0;
1466
1467 libpatterns = xstrdup (variable_expand ("$(strip $(.LIBPATTERNS))"));
1468
1469 warn_undefined_variables_flag = save;
1470 }
1471
1472 /* Loop through all the patterns in .LIBPATTERNS, and search on each one. */
1473 p2 = libpatterns;
1474 while ((p = find_next_token (&p2, &len)) != 0)
1475 {
1476 static char *buf = NULL;
1477 static unsigned int buflen = 0;
1478 static int libdir_maxlen = -1;
1479 char *libbuf = variable_expand ("");
1480
1481 /* Expand the pattern using LIBNAME as a replacement. */
1482 {
1483 char c = p[len];
1484 char *p3, *p4;
1485
1486 p[len] = '\0';
1487 p3 = find_percent (p);
1488 if (!p3)
1489 {
1490 /* Give a warning if there is no pattern, then remove the
1491 pattern so it's ignored next time. */
1492 error (NILF, _(".LIBPATTERNS element `%s' is not a pattern"), p);
1493 for (; len; --len, ++p)
1494 *p = ' ';
1495 *p = c;
1496 continue;
1497 }
1498 p4 = variable_buffer_output (libbuf, p, p3-p);
1499 p4 = variable_buffer_output (p4, libname, strlen (libname));
1500 p4 = variable_buffer_output (p4, p3+1, len - (p3-p));
1501 p[len] = c;
1502 }
1503
1504 /* Look first for `libNAME.a' in the current directory. */
1505 mtime = name_mtime (libbuf);
1506 if (mtime != NONEXISTENT_MTIME)
1507 {
1508 *lib = xstrdup (libbuf);
1509 if (mtime_ptr != 0)
1510 *mtime_ptr = mtime;
1511 return 1;
1512 }
1513
1514 /* Now try VPATH search on that. */
1515
1516 file = libbuf;
1517 if (vpath_search (&file, mtime_ptr))
1518 {
1519 *lib = file;
1520 return 1;
1521 }
1522
1523 /* Now try the standard set of directories. */
1524
1525 if (!buflen)
1526 {
1527 for (dp = dirs; *dp != 0; ++dp)
1528 {
1529 int l = strlen (*dp);
1530 if (l > libdir_maxlen)
1531 libdir_maxlen = l;
1532 }
1533 buflen = strlen (libbuf);
1534 buf = xmalloc(libdir_maxlen + buflen + 2);
1535 }
1536 else if (buflen < strlen (libbuf))
1537 {
1538 buflen = strlen (libbuf);
1539 buf = xrealloc (buf, libdir_maxlen + buflen + 2);
1540 }
1541
1542 for (dp = dirs; *dp != 0; ++dp)
1543 {
1544 sprintf (buf, "%s/%s", *dp, libbuf);
1545 mtime = name_mtime (buf);
1546 if (mtime != NONEXISTENT_MTIME)
1547 {
1548 *lib = xstrdup (buf);
1549 if (mtime_ptr != 0)
1550 *mtime_ptr = mtime;
1551 return 1;
1552 }
1553 }
1554 }
1555
1556 return 0;
1557}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette