VirtualBox

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

Last change on this file since 393 was 352, checked in by bird, 19 years ago

Fixed not_parallel assertion in notice_finished_file.

  • Property svn:eol-style set to native
File size: 44.7 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;
797 DB (DB_JOBS, (_("notice_finished_file - entering: file=%p `%s' update_status=%d command_state=%d\n"),
798 file, file->name, file->update_status, file->command_state));
799 file->command_state = cs_finished;
800 file->updated = 1;
801
802 /* update not_parallel if the file was flagged for that. */
803 if (ran && (file->command_flags & (COMMANDS_NOTPARALLEL | COMMANDS_NO_COMMANDS))
804 == COMMANDS_NOTPARALLEL)
805 {
806 DB (DB_KMK, (_("not_parallel %d -> %d (file=%p `%s')\n"), not_parallel,
807 not_parallel - 1, file, file->name));
808 assert(not_parallel >= 1);
809 --not_parallel;
810 }
811
812 if (touch_flag
813 /* The update status will be:
814 -1 if this target was not remade;
815 0 if 0 or more commands (+ or ${MAKE}) were run and won;
816 1 if some commands were run and lost.
817 We touch the target if it has commands which either were not run
818 or won when they ran (i.e. status is 0). */
819 && file->update_status == 0)
820 {
821 if (file->cmds != 0 && file->cmds->any_recurse)
822 {
823 /* If all the command lines were recursive,
824 we don't want to do the touching. */
825 unsigned int i;
826 for (i = 0; i < file->cmds->ncommand_lines; ++i)
827 if (!(file->cmds->lines_flags[i] & COMMANDS_RECURSE))
828 goto have_nonrecursing;
829 }
830 else
831 {
832 have_nonrecursing:
833 if (file->phony)
834 file->update_status = 0;
835 /* According to POSIX, -t doesn't affect targets with no cmds. */
836 else if (file->cmds != 0)
837 {
838 /* Should set file's modification date and do nothing else. */
839 file->update_status = touch_file (file);
840
841 /* Pretend we ran a real touch command, to suppress the
842 "`foo' is up to date" message. */
843 commands_started++;
844
845 /* Request for the timestamp to be updated (and distributed
846 to the double-colon entries). Simply setting ran=1 would
847 almost have done the trick, but messes up with the also_make
848 updating logic below. */
849 touched = 1;
850 }
851 }
852 }
853
854 if (file->mtime_before_update == UNKNOWN_MTIME)
855 file->mtime_before_update = file->last_mtime;
856
857 if ((ran && !file->phony) || touched)
858 {
859 struct file *f;
860 int i = 0;
861
862 /* If -n, -t, or -q and all the commands are recursive, we ran them so
863 really check the target's mtime again. Otherwise, assume the target
864 would have been updated. */
865
866 if (question_flag || just_print_flag || touch_flag)
867 {
868 for (i = file->cmds->ncommand_lines; i > 0; --i)
869 if (! (file->cmds->lines_flags[i-1] & COMMANDS_RECURSE))
870 break;
871 }
872
873 /* If there were no commands at all, it's always new. */
874
875 else if (file->is_target && file->cmds == 0)
876 i = 1;
877
878 file->last_mtime = i == 0 ? UNKNOWN_MTIME : NEW_MTIME;
879
880 /* Propagate the change of modification time to all the double-colon
881 entries for this file. */
882 for (f = file->double_colon; f != 0; f = f->prev)
883 f->last_mtime = file->last_mtime;
884 }
885
886 if (ran && file->update_status != -1)
887 /* We actually tried to update FILE, which has
888 updated its also_make's as well (if it worked).
889 If it didn't work, it wouldn't work again for them.
890 So mark them as updated with the same status. */
891 for (d = file->also_make; d != 0; d = d->next)
892 {
893 d->file->command_state = cs_finished;
894 d->file->updated = 1;
895 d->file->update_status = file->update_status;
896
897 if (ran && !d->file->phony)
898 /* Fetch the new modification time.
899 We do this instead of just invalidating the cached time
900 so that a vpath_search can happen. Otherwise, it would
901 never be done because the target is already updated. */
902 (void) f_mtime (d->file, 0);
903 }
904 else if (file->update_status == -1)
905 /* Nothing was done for FILE, but it needed nothing done.
906 So mark it now as "succeeded". */
907 file->update_status = 0;
908
909DB (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));
910}
911
912
913/* Check whether another file (whose mtime is THIS_MTIME)
914 needs updating on account of a dependency which is file FILE.
915 If it does, store 1 in *MUST_MAKE_PTR.
916 In the process, update any non-intermediate files
917 that FILE depends on (including FILE itself).
918 Return nonzero if any updating failed. */
919
920static int
921check_dep (struct file *file, unsigned int depth,
922 FILE_TIMESTAMP this_mtime, int *must_make_ptr)
923{
924 struct dep *d;
925 int dep_status = 0;
926
927 ++depth;
928 start_updating (file);
929
930 if (file->phony || !file->intermediate)
931 {
932 /* If this is a non-intermediate file, update it and record
933 whether it is newer than THIS_MTIME. */
934 FILE_TIMESTAMP mtime;
935 dep_status = update_file (file, depth);
936 check_renamed (file);
937 mtime = file_mtime (file);
938 check_renamed (file);
939 if (mtime == NONEXISTENT_MTIME || mtime > this_mtime)
940 *must_make_ptr = 1;
941 }
942 else
943 {
944 /* FILE is an intermediate file. */
945 FILE_TIMESTAMP mtime;
946
947 if (!file->phony && file->cmds == 0 && !file->tried_implicit)
948 {
949 if (try_implicit_rule (file, depth))
950 DBF (DB_IMPLICIT, _("Found an implicit rule for `%s'.\n"));
951 else
952 DBF (DB_IMPLICIT, _("No implicit rule found for `%s'.\n"));
953 file->tried_implicit = 1;
954 }
955 if (file->cmds == 0 && !file->is_target
956 && default_file != 0 && default_file->cmds != 0)
957 {
958 DBF (DB_IMPLICIT, _("Using default commands for `%s'.\n"));
959 file->cmds = default_file->cmds;
960 }
961
962 /* If the intermediate file actually exists
963 and is newer, then we should remake from it. */
964 check_renamed (file);
965 mtime = file_mtime (file);
966 check_renamed (file);
967 if (mtime != NONEXISTENT_MTIME && mtime > this_mtime)
968 *must_make_ptr = 1;
969 /* Otherwise, update all non-intermediate files we depend on,
970 if necessary, and see whether any of them is more
971 recent than the file on whose behalf we are checking. */
972 else
973 {
974 struct dep *lastd;
975
976 lastd = 0;
977 d = file->deps;
978 while (d != 0)
979 {
980 int maybe_make;
981
982 if (is_updating (d->file))
983 {
984 error (NILF, _("Circular %s <- %s dependency dropped."),
985 file->name, d->file->name);
986 if (lastd == 0)
987 {
988 file->deps = d->next;
989 free ((char *) d);
990 d = file->deps;
991 }
992 else
993 {
994 lastd->next = d->next;
995 free ((char *) d);
996 d = lastd->next;
997 }
998 continue;
999 }
1000
1001 d->file->parent = file;
1002 maybe_make = *must_make_ptr;
1003 dep_status |= check_dep (d->file, depth, this_mtime,
1004 &maybe_make);
1005 if (! d->ignore_mtime)
1006 *must_make_ptr = maybe_make;
1007 check_renamed (d->file);
1008 if (dep_status != 0 && !keep_going_flag)
1009 break;
1010
1011 if (d->file->command_state == cs_running
1012 || d->file->command_state == cs_deps_running)
1013 /* Record that some of FILE's deps are still being made.
1014 This tells the upper levels to wait on processing it until
1015 the commands are finished. */
1016 set_command_state (file, cs_deps_running);
1017
1018 lastd = d;
1019 d = d->next;
1020 }
1021 }
1022 }
1023
1024 finish_updating (file);
1025 return dep_status;
1026}
1027
1028
1029/* Touch FILE. Return zero if successful, one if not. */
1030
1031#define TOUCH_ERROR(call) return (perror_with_name (call, file->name), 1)
1032
1033static int
1034touch_file (struct file *file)
1035{
1036 if (!silent_flag)
1037 message (0, "touch %s", file->name);
1038
1039#ifndef NO_ARCHIVES
1040 if (ar_name (file->name))
1041 return ar_touch (file->name);
1042 else
1043#endif
1044 {
1045 int fd = open (file->name, O_RDWR | O_CREAT, 0666);
1046
1047 if (fd < 0)
1048 TOUCH_ERROR ("touch: open: ");
1049 else
1050 {
1051 struct stat statbuf;
1052 char buf;
1053 int e;
1054
1055 EINTRLOOP (e, fstat (fd, &statbuf));
1056 if (e < 0)
1057 TOUCH_ERROR ("touch: fstat: ");
1058 /* Rewrite character 0 same as it already is. */
1059 if (read (fd, &buf, 1) < 0)
1060 TOUCH_ERROR ("touch: read: ");
1061 if (lseek (fd, 0L, 0) < 0L)
1062 TOUCH_ERROR ("touch: lseek: ");
1063 if (write (fd, &buf, 1) < 0)
1064 TOUCH_ERROR ("touch: write: ");
1065 /* If file length was 0, we just
1066 changed it, so change it back. */
1067 if (statbuf.st_size == 0)
1068 {
1069 (void) close (fd);
1070 fd = open (file->name, O_RDWR | O_TRUNC, 0666);
1071 if (fd < 0)
1072 TOUCH_ERROR ("touch: open: ");
1073 }
1074 (void) close (fd);
1075 }
1076 }
1077
1078 return 0;
1079}
1080
1081
1082/* Having checked and updated the dependencies of FILE,
1083 do whatever is appropriate to remake FILE itself.
1084 Return the status from executing FILE's commands. */
1085
1086static void
1087remake_file (struct file *file)
1088{
1089 if (file->cmds == 0)
1090 {
1091 if (file->phony)
1092 /* Phony target. Pretend it succeeded. */
1093 file->update_status = 0;
1094 else if (file->is_target)
1095 /* This is a nonexistent target file we cannot make.
1096 Pretend it was successfully remade. */
1097 file->update_status = 0;
1098 else
1099 {
1100 /* This is a dependency file we cannot remake. Fail. */
1101 if (!rebuilding_makefiles || !file->dontcare)
1102 complain (file);
1103 file->update_status = 2;
1104 }
1105 }
1106 else
1107 {
1108 chop_commands (file->cmds);
1109
1110 /* The normal case: start some commands. */
1111 if (!touch_flag || file->cmds->any_recurse)
1112 {
1113 execute_file_commands (file);
1114 return;
1115 }
1116
1117 /* This tells notice_finished_file it is ok to touch the file. */
1118 file->update_status = 0;
1119 }
1120
1121 /* This does the touching under -t. */
1122 notice_finished_file (file);
1123}
1124
1125
1126/* Return the mtime of a file, given a `struct file'.
1127 Caches the time in the struct file to avoid excess stat calls.
1128
1129 If the file is not found, and SEARCH is nonzero, VPATH searching and
1130 replacement is done. If that fails, a library (-lLIBNAME) is tried and
1131 the library's actual name (/lib/libLIBNAME.a, etc.) is substituted into
1132 FILE. */
1133
1134FILE_TIMESTAMP
1135f_mtime (struct file *file, int search)
1136{
1137 FILE_TIMESTAMP mtime;
1138
1139 /* File's mtime is not known; must get it from the system. */
1140
1141#ifndef NO_ARCHIVES
1142 if (ar_name (file->name))
1143 {
1144 /* This file is an archive-member reference. */
1145
1146 char *arname, *memname;
1147 struct file *arfile;
1148 int arname_used = 0;
1149 time_t member_date;
1150
1151 /* Find the archive's name. */
1152 ar_parse_name (file->name, &arname, &memname);
1153
1154 /* Find the modification time of the archive itself.
1155 Also allow for its name to be changed via VPATH search. */
1156 arfile = lookup_file (arname);
1157 if (arfile == 0)
1158 {
1159 arfile = enter_file (arname);
1160 arname_used = 1;
1161 }
1162 mtime = f_mtime (arfile, search);
1163 check_renamed (arfile);
1164 if (search && strcmp (arfile->hname, arname))
1165 {
1166 /* The archive's name has changed.
1167 Change the archive-member reference accordingly. */
1168
1169 char *name;
1170 unsigned int arlen, memlen;
1171
1172 if (!arname_used)
1173 {
1174 free (arname);
1175 arname_used = 1;
1176 }
1177
1178 arname = arfile->hname;
1179 arlen = strlen (arname);
1180 memlen = strlen (memname);
1181
1182 /* free (file->name); */
1183
1184 name = (char *) xmalloc (arlen + 1 + memlen + 2);
1185 bcopy (arname, name, arlen);
1186 name[arlen] = '(';
1187 bcopy (memname, name + arlen + 1, memlen);
1188 name[arlen + 1 + memlen] = ')';
1189 name[arlen + 1 + memlen + 1] = '\0';
1190
1191 /* If the archive was found with GPATH, make the change permanent;
1192 otherwise defer it until later. */
1193 if (arfile->name == arfile->hname)
1194 rename_file (file, name);
1195 else
1196 rehash_file (file, name);
1197 check_renamed (file);
1198 }
1199
1200 if (!arname_used)
1201 free (arname);
1202 free (memname);
1203
1204 file->low_resolution_time = 1;
1205
1206 if (mtime == NONEXISTENT_MTIME)
1207 /* The archive doesn't exist, so its members don't exist either. */
1208 return NONEXISTENT_MTIME;
1209
1210 member_date = ar_member_date (file->hname);
1211 mtime = (member_date == (time_t) -1
1212 ? NONEXISTENT_MTIME
1213 : file_timestamp_cons (file->hname, member_date, 0));
1214 }
1215 else
1216#endif
1217 {
1218 mtime = name_mtime (file->name);
1219
1220 if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath)
1221 {
1222 /* If name_mtime failed, search VPATH. */
1223 char *name = file->name;
1224 if (vpath_search (&name, &mtime)
1225 /* Last resort, is it a library (-lxxx)? */
1226 || (name[0] == '-' && name[1] == 'l'
1227 && library_search (&name, &mtime)))
1228 {
1229 if (mtime != UNKNOWN_MTIME)
1230 /* vpath_search and library_search store UNKNOWN_MTIME
1231 if they didn't need to do a stat call for their work. */
1232 file->last_mtime = mtime;
1233
1234 /* If we found it in VPATH, see if it's in GPATH too; if so,
1235 change the name right now; if not, defer until after the
1236 dependencies are updated. */
1237 if (gpath_search (name, strlen(name) - strlen(file->name) - 1))
1238 {
1239 rename_file (file, name);
1240 check_renamed (file);
1241 return file_mtime (file);
1242 }
1243
1244 rehash_file (file, name);
1245 check_renamed (file);
1246 mtime = name_mtime (name);
1247 }
1248 }
1249 }
1250
1251 {
1252 /* Files can have bogus timestamps that nothing newly made will be
1253 "newer" than. Updating their dependents could just result in loops.
1254 So notify the user of the anomaly with a warning.
1255
1256 We only need to do this once, for now. */
1257
1258 if (!clock_skew_detected
1259 && mtime != NONEXISTENT_MTIME
1260 && !file->updated)
1261 {
1262 static FILE_TIMESTAMP adjusted_now;
1263
1264 FILE_TIMESTAMP adjusted_mtime = mtime;
1265
1266#if defined(WINDOWS32) || defined(__MSDOS__)
1267 /* Experimentation has shown that FAT filesystems can set file times
1268 up to 3 seconds into the future! Play it safe. */
1269
1270#define FAT_ADJ_OFFSET (FILE_TIMESTAMP) 3
1271
1272 FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS;
1273 if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime)
1274 adjusted_mtime -= adjustment;
1275#elif defined(__EMX__)
1276 /* FAT filesystems round time to the nearest even second!
1277 Allow for any file (NTFS or FAT) to perhaps suffer from this
1278 brain damage. */
1279 FILE_TIMESTAMP adjustment = (((FILE_TIMESTAMP_S (adjusted_mtime) & 1) == 0
1280 && FILE_TIMESTAMP_NS (adjusted_mtime) == 0)
1281 ? (FILE_TIMESTAMP) 1 << FILE_TIMESTAMP_LO_BITS
1282 : 0);
1283#endif
1284
1285 /* If the file's time appears to be in the future, update our
1286 concept of the present and try once more. */
1287 if (adjusted_now < adjusted_mtime)
1288 {
1289 int resolution;
1290 FILE_TIMESTAMP now = file_timestamp_now (&resolution);
1291 adjusted_now = now + (resolution - 1);
1292 if (adjusted_now < adjusted_mtime)
1293 {
1294#ifdef NO_FLOAT
1295 error (NILF, _("Warning: File `%s' has modification time in the future"),
1296 file->name);
1297#else
1298 double from_now =
1299 (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now)
1300 + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now))
1301 / 1e9));
1302 error (NILF, _("Warning: File `%s' has modification time %.2g s in the future"),
1303 file->name, from_now);
1304#endif
1305 clock_skew_detected = 1;
1306 }
1307 }
1308 }
1309 }
1310
1311 /* Store the mtime into all the entries for this file. */
1312 if (file->double_colon)
1313 file = file->double_colon;
1314
1315 do
1316 {
1317 /* If this file is not implicit but it is intermediate then it was
1318 made so by the .INTERMEDIATE target. If this file has never
1319 been built by us but was found now, it existed before make
1320 started. So, turn off the intermediate bit so make doesn't
1321 delete it, since it didn't create it. */
1322 if (mtime != NONEXISTENT_MTIME && file->command_state == cs_not_started
1323 && file->command_state == cs_not_started
1324 && !file->tried_implicit && file->intermediate)
1325 file->intermediate = 0;
1326
1327 file->last_mtime = mtime;
1328 file = file->prev;
1329 }
1330 while (file != 0);
1331
1332 return mtime;
1333}
1334
1335
1336/* Return the mtime of the file or archive-member reference NAME. */
1337
1338/* First, we check with stat(). If the file does not exist, then we return
1339 NONEXISTENT_MTIME. If it does, and the symlink check flag is set, then
1340 examine each indirection of the symlink and find the newest mtime.
1341 This causes one duplicate stat() when -L is being used, but the code is
1342 much cleaner. */
1343
1344static FILE_TIMESTAMP
1345name_mtime (char *name)
1346{
1347 FILE_TIMESTAMP mtime;
1348 struct stat st;
1349 int e;
1350
1351 EINTRLOOP (e, stat (name, &st));
1352 if (e != 0)
1353 {
1354 if (errno != ENOENT && errno != ENOTDIR)
1355 perror_with_name ("stat: ", name);
1356 return NONEXISTENT_MTIME;
1357 }
1358 mtime = FILE_TIMESTAMP_STAT_MODTIME (name, st);
1359
1360#ifdef MAKE_SYMLINKS
1361#ifndef S_ISLNK
1362# define S_ISLNK(_m) (((_m)&S_IFMT)==S_IFLNK)
1363#endif
1364 if (check_symlink_flag)
1365 {
1366 PATH_VAR (lpath);
1367
1368 /* Check each symbolic link segment (if any). Find the latest mtime
1369 amongst all of them (and the target file of course).
1370 Note that we have already successfully dereferenced all the links
1371 above. So, if we run into any error trying to lstat(), or
1372 readlink(), or whatever, something bizarre-o happened. Just give up
1373 and use whatever mtime we've already computed at that point. */
1374 strcpy (lpath, name);
1375 while (1)
1376 {
1377 FILE_TIMESTAMP ltime;
1378 PATH_VAR (lbuf);
1379 long llen;
1380 char *p;
1381
1382 EINTRLOOP (e, lstat (lpath, &st));
1383 if (e)
1384 {
1385 /* Eh? Just take what we have. */
1386 perror_with_name ("lstat: ", lpath);
1387 break;
1388 }
1389
1390 /* If this is not a symlink, we're done (we started with the real
1391 file's mtime so we don't need to test it again). */
1392 if (!S_ISLNK (st.st_mode))
1393 break;
1394
1395 /* If this mtime is newer than what we had, keep the new one. */
1396 ltime = FILE_TIMESTAMP_STAT_MODTIME (lpath, st);
1397 if (ltime > mtime)
1398 mtime = ltime;
1399
1400 /* Set up to check the file pointed to by this link. */
1401 EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX));
1402 if (llen < 0)
1403 {
1404 /* Eh? Just take what we have. */
1405 perror_with_name ("readlink: ", lpath);
1406 break;
1407 }
1408 lbuf[llen] = '\0';
1409
1410 /* If the target is fully-qualified or the source is just a
1411 filename, then the new path is the target. Otherwise it's the
1412 source directory plus the target. */
1413 if (lbuf[0] == '/' || (p = strrchr (lpath, '/')) == NULL)
1414 strcpy (lpath, lbuf);
1415 else if ((p - lpath) + llen + 2 > GET_PATH_MAX)
1416 /* Eh? Path too long! Again, just go with what we have. */
1417 break;
1418 else
1419 /* Create the next step in the symlink chain. */
1420 strcpy (p+1, lbuf);
1421 }
1422 }
1423#endif
1424
1425 return mtime;
1426}
1427
1428
1429/* Search for a library file specified as -lLIBNAME, searching for a
1430 suitable library file in the system library directories and the VPATH
1431 directories. */
1432
1433static int
1434library_search (char **lib, FILE_TIMESTAMP *mtime_ptr)
1435{
1436 static char *dirs[] =
1437 {
1438#ifndef _AMIGA
1439 "/lib",
1440 "/usr/lib",
1441#endif
1442#if defined(WINDOWS32) && !defined(LIBDIR)
1443/*
1444 * This is completely up to the user at product install time. Just define
1445 * a placeholder.
1446 */
1447#define LIBDIR "."
1448#endif
1449 LIBDIR, /* Defined by configuration. */
1450 0
1451 };
1452
1453 static char *libpatterns = NULL;
1454
1455 char *libname = &(*lib)[2]; /* Name without the `-l'. */
1456 FILE_TIMESTAMP mtime;
1457
1458 /* Loop variables for the libpatterns value. */
1459 char *p, *p2;
1460 unsigned int len;
1461
1462 char *file, **dp;
1463
1464 /* If we don't have libpatterns, get it. */
1465 if (!libpatterns)
1466 {
1467 int save = warn_undefined_variables_flag;
1468 warn_undefined_variables_flag = 0;
1469
1470 libpatterns = xstrdup (variable_expand ("$(strip $(.LIBPATTERNS))"));
1471
1472 warn_undefined_variables_flag = save;
1473 }
1474
1475 /* Loop through all the patterns in .LIBPATTERNS, and search on each one. */
1476 p2 = libpatterns;
1477 while ((p = find_next_token (&p2, &len)) != 0)
1478 {
1479 static char *buf = NULL;
1480 static unsigned int buflen = 0;
1481 static int libdir_maxlen = -1;
1482 char *libbuf = variable_expand ("");
1483
1484 /* Expand the pattern using LIBNAME as a replacement. */
1485 {
1486 char c = p[len];
1487 char *p3, *p4;
1488
1489 p[len] = '\0';
1490 p3 = find_percent (p);
1491 if (!p3)
1492 {
1493 /* Give a warning if there is no pattern, then remove the
1494 pattern so it's ignored next time. */
1495 error (NILF, _(".LIBPATTERNS element `%s' is not a pattern"), p);
1496 for (; len; --len, ++p)
1497 *p = ' ';
1498 *p = c;
1499 continue;
1500 }
1501 p4 = variable_buffer_output (libbuf, p, p3-p);
1502 p4 = variable_buffer_output (p4, libname, strlen (libname));
1503 p4 = variable_buffer_output (p4, p3+1, len - (p3-p));
1504 p[len] = c;
1505 }
1506
1507 /* Look first for `libNAME.a' in the current directory. */
1508 mtime = name_mtime (libbuf);
1509 if (mtime != NONEXISTENT_MTIME)
1510 {
1511 *lib = xstrdup (libbuf);
1512 if (mtime_ptr != 0)
1513 *mtime_ptr = mtime;
1514 return 1;
1515 }
1516
1517 /* Now try VPATH search on that. */
1518
1519 file = libbuf;
1520 if (vpath_search (&file, mtime_ptr))
1521 {
1522 *lib = file;
1523 return 1;
1524 }
1525
1526 /* Now try the standard set of directories. */
1527
1528 if (!buflen)
1529 {
1530 for (dp = dirs; *dp != 0; ++dp)
1531 {
1532 int l = strlen (*dp);
1533 if (l > libdir_maxlen)
1534 libdir_maxlen = l;
1535 }
1536 buflen = strlen (libbuf);
1537 buf = xmalloc(libdir_maxlen + buflen + 2);
1538 }
1539 else if (buflen < strlen (libbuf))
1540 {
1541 buflen = strlen (libbuf);
1542 buf = xrealloc (buf, libdir_maxlen + buflen + 2);
1543 }
1544
1545 for (dp = dirs; *dp != 0; ++dp)
1546 {
1547 sprintf (buf, "%s/%s", *dp, libbuf);
1548 mtime = name_mtime (buf);
1549 if (mtime != NONEXISTENT_MTIME)
1550 {
1551 *lib = xstrdup (buf);
1552 if (mtime_ptr != 0)
1553 *mtime_ptr = mtime;
1554 return 1;
1555 }
1556 }
1557 }
1558
1559 return 0;
1560}
Note: See TracBrowser for help on using the repository browser.

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