VirtualBox

source: kBuild/trunk/src/kmk/incdep.c@ 1806

Last change on this file since 1806 was 1804, checked in by bird, 17 years ago

incdep: windows build fixes and some adjustments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 40.4 KB
Line 
1#ifdef CONFIG_WITH_INCLUDEDEP
2/* $Id: incdep.c 1804 2008-09-21 19:55:08Z bird $ */
3/** @file
4 * incdep - Simple dependency files.
5 */
6
7/*
8 * Copyright (c) 2006-2008 knut st. osmundsen <[email protected]>
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 *
26 */
27
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#ifdef __OS2__
33# define INCL_BASE
34# define INCL_ERRORS
35#endif
36
37#include "make.h"
38
39#if !defined(WINDOWS32) && !defined(__OS2__)
40# define HAVE_PTHREAD
41#endif
42
43#include <assert.h>
44
45#include <glob.h>
46
47#include "dep.h"
48#include "filedef.h"
49#include "job.h"
50#include "commands.h"
51#include "variable.h"
52#include "rule.h"
53#include "debug.h"
54#include "hash.h"
55
56#ifdef HAVE_FCNTL_H
57# include <fcntl.h>
58#else
59# include <sys/file.h>
60#endif
61
62#ifdef WINDOWS32
63# include <io.h>
64# include <process.h>
65# include <Windows.h>
66# define PARSE_IN_WORKER
67#endif
68
69#ifdef __OS2__
70# include <os2.h>
71# include <sys/fmutex.h>
72#endif
73
74#ifdef HAVE_PTHREAD
75# include <pthread.h>
76#endif
77
78
79/*******************************************************************************
80* Structures and Typedefs *
81*******************************************************************************/
82
83struct incdep_variable_in_set
84{
85 struct incdep_variable_in_set *next;
86 /* the parameters */
87 char *name; /* xmalloc'ed -> strcache */
88 unsigned int name_length;
89 const char *value; /* xmalloc'ed */
90 unsigned int value_length;
91 int duplicate_value; /* 0 */
92 enum variable_origin origin;
93 int recursive;
94 struct variable_set *set;
95 const struct floc *flocp; /* NILF */
96};
97
98struct incdep_variable_def
99{
100 struct incdep_variable_def *next;
101 /* the parameters */
102 const struct floc *flocp; /* NILF */
103 char *name; /* xmalloc'ed -> strcache */
104 unsigned int name_length; /* (not an actual parameter) */
105 char *value; /* xmalloc'ed, free it */
106 enum variable_origin origin;
107 enum variable_flavor flavor;
108 int target_var;
109};
110
111struct incdep_recorded_files
112{
113 struct incdep_recorded_files *next;
114
115 /* the parameters */
116 struct nameseq *filenames; /* only one file? its name needs be strcache'ed */
117 const char *pattern; /* NULL */
118 const char *pattern_percent; /* NULL */
119 struct dep *deps; /* names need to be strcache'ed */
120 unsigned int cmds_started; /* 0 */
121 char *commands; /* NULL */
122 unsigned int commands_idx; /* 0 */
123 int two_colon; /* 0 */
124 const struct floc *flocp; /* NILF */
125};
126
127
128/* per dep file structure. */
129struct incdep
130{
131 struct incdep *next;
132 char *file_base;
133 char *file_end;
134
135 int is_worker;
136#ifdef PARSE_IN_WORKER
137 unsigned int err_line_no;
138 const char *err_msg;
139
140 struct incdep_variable_in_set *recorded_variables_in_set_head;
141 struct incdep_variable_in_set *recorded_variables_in_set_tail;
142
143 struct incdep_variable_def *recorded_variable_defs_head;
144 struct incdep_variable_def *recorded_variable_defs_tail;
145
146 struct incdep_recorded_files *recorded_files_head;
147 struct incdep_recorded_files *recorded_files_tail;
148#endif
149
150 char name[1];
151};
152
153
154/*******************************************************************************
155* Global Variables *
156*******************************************************************************/
157
158/* mutex protecting the globals and an associated condition/event. */
159#ifdef HAVE_PTHREAD
160static pthread_mutex_t incdep_mtx;
161static pthread_cond_t incdep_cond_todo;
162static pthread_cond_t incdep_cond_done;
163
164#elif defined (WINDOWS32)
165static CRITICAL_SECTION incdep_mtx;
166static HANDLE incdep_hev_todo;
167static HANDLE incdep_hev_done;
168static int volatile incdep_hev_todo_waiters;
169static int volatile incdep_hev_done_waiters;
170
171#elif defined (__OS2__)
172static fmutex incdep_mtx;
173static HEV incdep_hev_todo;
174static HEV incdep_hev_done;
175static int volatile incdep_hev_todo_waiters;
176static int volatile incdep_hev_done_waiters;
177#endif
178
179/* flag indicating whether the threads, lock and event/condvars has
180 been initialized or not. */
181static int incdep_initialized;
182
183/* the list of files that needs reading. */
184static struct incdep * volatile incdep_head_todo;
185static struct incdep * volatile incdep_tail_todo;
186
187/* the number of files that are currently being read. */
188static int volatile incdep_num_reading;
189
190/* the list of files that have been read. */
191static struct incdep * volatile incdep_head_done;
192static struct incdep * volatile incdep_tail_done;
193
194/* The handles to the worker threads. */
195#ifdef HAVE_PTHREAD
196static pthread_t incdep_threads[2];
197#elif defined (WINDOWS32)
198static HANDLE incdep_threads[2];
199#elif defined (__OS2__)
200static TID incdep_threads[2];
201#endif
202static unsigned incdep_num_threads;
203
204/* flag indicating whether the worker threads should terminate or not. */
205static int volatile incdep_terminate;
206
207
208/*******************************************************************************
209* Internal Functions *
210*******************************************************************************/
211static void incdep_flush_it (struct floc *);
212static void eval_include_dep_file (struct incdep *, struct floc *, int);
213
214
215
216/* acquires the lock */
217void
218incdep_lock(void)
219{
220#ifdef HAVE_PTHREAD
221 pthread_mutex_lock (&incdep_mtx);
222#elif defined (WINDOWS32)
223 EnterCriticalSection (&incdep_mtx);
224#elif defined (__OS2__)
225 _fmutex_request (&incdep_mtx, 0)
226#endif
227}
228
229/* releases the lock */
230void
231incdep_unlock(void)
232{
233#ifdef HAVE_PTHREAD
234 pthread_mutex_unlock (&incdep_mtx);
235#elif defined(WINDOWS32)
236 LeaveCriticalSection (&incdep_mtx);
237#elif defined(__OS2__)
238 _fmutex_release (&incdep_mtx)
239#endif
240}
241
242/* signals the main thread that there is stuff todo. caller owns the lock. */
243static void
244incdep_signal_done (void)
245{
246#ifdef HAVE_PTHREAD
247 pthread_cond_broadcast (&incdep_cond_done);
248#elif defined (WINDOWS32)
249 if (incdep_hev_done_waiters)
250 SetEvent (incdep_hev_done);
251#elif defined (__OS2__)
252 if (incdep_hev_done_waiters)
253 DosPostEventSem (incdep_hev_done);
254#endif
255}
256
257/* waits for a reader to finish reading. caller owns the lock. */
258static void
259incdep_wait_done (void)
260{
261#ifdef HAVE_PTHREAD
262 pthread_cond_wait (&incdep_cond_done, &incdep_mtx);
263
264#elif defined (WINDOWS32)
265 ResetEvent (incdep_hev_done);
266 incdep_hev_done_waiters++;
267 incdep_unlock ();
268 WaitForSingleObject (incdep_hev_done, INFINITE);
269 incdep_lock ();
270 incdep_hev_done_waiters--;
271
272#elif defined (__OS2__)
273 ULONG ulIgnore;
274 DosResetEventSem (incdep_hev_done, &ulIgnore);
275 incdep_hev_done_waiters++;
276 incdep_unlock ();
277 DosWaitEventSem (incdep_hev_done, SEM_INDEFINITE_WAIT);
278 incdep_lock ();
279 incdep_hev_done_waiters--;
280#endif
281}
282
283/* signals the worker threads. caller owns the lock. */
284static void
285incdep_signal_todo (void)
286{
287#ifdef HAVE_PTHREAD
288 pthread_cond_broadcast (&incdep_cond_todo);
289#elif defined(WINDOWS32)
290 if (incdep_hev_todo_waiters)
291 SetEvent (incdep_hev_todo);
292#elif defined(__OS2__)
293 if (incdep_hev_todo_waiters)
294 DosPostEventSem (incdep_hev_todo);
295#endif
296}
297
298/* waits for stuff to arrive in the todo list. caller owns the lock. */
299static void
300incdep_wait_todo (void)
301{
302#ifdef HAVE_PTHREAD
303 pthread_cond_wait (&incdep_cond_todo, &incdep_mtx);
304
305#elif defined (WINDOWS32)
306 ResetEvent (incdep_hev_todo);
307 incdep_hev_todo_waiters++;
308 incdep_unlock ();
309 WaitForSingleObject (incdep_hev_todo, INFINITE);
310 incdep_lock ();
311 incdep_hev_todo_waiters--;
312
313#elif defined (__OS2__)
314 ULONG ulIgnore;
315 DosResetEventSem (incdep_hev_todo, &ulIgnore);
316 incdep_hev_todo_waiters++;
317 incdep_unlock ();
318 DosWaitEventSem (incdep_hev_todo, SEM_INDEFINITE_WAIT);
319 incdep_lock ();
320 incdep_hev_todo_waiters--;
321#endif
322}
323
324/* Reads a dep file into memory. */
325static int
326incdep_read_file (struct incdep *cur, struct floc *f)
327{
328 int fd;
329 struct stat st;
330
331 errno = 0;
332#ifdef O_BINARY
333 fd = open (cur->name, O_RDONLY | O_BINARY, 0);
334#else
335 fd = open (cur->name, O_RDONLY, 0);
336#endif
337 if (fd < 0)
338 {
339 /* ignore non-existing dependency files. */
340 int err = errno;
341 if (err == ENOENT || stat (cur->name, &st) != 0)
342 return 1;
343 error (f, "%s: %s", cur->name, strerror (err));
344 return -1;
345 }
346 if (!fstat (fd, &st))
347 {
348 cur->file_base = xmalloc (st.st_size + 1);
349 if (read (fd, cur->file_base, st.st_size) == st.st_size)
350 {
351 close (fd);
352 cur->file_end = cur->file_base + st.st_size;
353 cur->file_base[st.st_size] = '\0';
354 return 0;
355 }
356
357 /* bail out */
358
359 error (f, "%s: read: %s", cur->name, strerror (errno));
360 free (cur->file_base);
361 }
362 else
363 error (f, "%s: fstat: %s", cur->name, strerror (errno));
364
365 close (fd);
366 cur->file_base = cur->file_end = NULL;
367 return -1;
368}
369
370/* Free the incdep structure. */
371static void
372incdep_free (struct incdep *cur)
373{
374#ifdef PARSE_IN_WORKER
375 assert (!cur->recorded_variables_in_set_head);
376 assert (!cur->recorded_variable_defs_head);
377 assert (!cur->recorded_files_head);
378#endif
379
380 free (cur->file_base);
381 free (cur);
382}
383
384/* A worker thread. */
385void
386incdep_worker (void)
387{
388 incdep_lock ();
389
390 while (!incdep_terminate)
391 {
392 /* get job from the todo list. */
393
394 struct incdep *cur = incdep_head_todo;
395 if (!cur)
396 {
397 incdep_wait_todo ();
398 continue;
399 }
400 if (cur->next)
401 incdep_head_todo = cur->next;
402 else
403 incdep_head_todo = incdep_tail_todo = NULL;
404 incdep_num_reading++;
405
406 /* read the file. */
407
408 incdep_unlock ();
409 incdep_read_file (cur, NILF);
410#ifdef PARSE_IN_WORKER
411 eval_include_dep_file (cur, NILF, 1 /* is_worker */);
412#endif
413 incdep_lock ();
414
415 /* insert finished job into the done list. */
416
417 incdep_num_reading--;
418 cur->next = NULL;
419 if (incdep_tail_done)
420 incdep_tail_done->next = cur;
421 else
422 incdep_head_done = cur;
423 incdep_tail_done = cur;
424
425 incdep_signal_done ();
426 }
427
428 incdep_unlock ();
429}
430
431/* Thread library specific thread functions wrapping incdep_wroker. */
432#ifdef HAVE_PTHREAD
433static void *
434incdep_worker_pthread (void *ignore)
435{
436 incdep_worker ();
437 (void)ignore;
438 return NULL;
439}
440
441#elif defined (WINDOWS32)
442static unsigned __stdcall
443incdep_worker_windows (void *ignore)
444{
445 incdep_worker ();
446 (void)ignore;
447 return 0;
448}
449
450#elif defined (__OS2__)
451static void
452incdep_worker_os2 (void *ignore)
453{
454 incdep_worker ();
455 (void)ignore;
456}
457#endif
458
459/* Creates the the worker threads. */
460static void
461incdep_init (struct floc *f)
462{
463 unsigned i;
464#ifdef HAVE_PTHREAD
465 int rc;
466 pthread_attr_t attr;
467
468#elif defined (WINDOWS32)
469 unsigned tid;
470 uintptr_t hThread;
471
472#elif defined (__OS2__)
473 int rc;
474 int tid;
475#endif
476
477 /* create the mutex and two condition variables / event objects. */
478
479#ifdef HAVE_PTHREAD
480 rc = pthread_mutex_init (&incdep_mtx, NULL);
481 if (rc)
482 fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
483 rc = pthread_cond_init (&incdep_cond_todo, NULL);
484 if (rc)
485 fatal (f, _("pthread_cond_init failed: err=%d"), rc);
486 rc = pthread_cond_init (&incdep_cond_done, NULL);
487 if (rc)
488 fatal (f, _("pthread_cond_init failed: err=%d"), rc);
489
490#elif defined (WINDOWS32)
491 InitializeCriticalSection (&incdep_mtx);
492 incdep_hev_todo = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
493 if (!incdep_hev_todo)
494 fatal (f, _("CreateEvent failed: err=%d"), GetLastError());
495 incdep_hev_done = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
496 if (!incdep_hev_done)
497 fatal (f, _("CreateEvent failed: err=%d"), GetLastError());
498 incdep_hev_todo_waiters = 0;
499 incdep_hev_done_waiters = 0;
500
501#elif defined (__OS2__)
502 _fmutex_create (&incdep_mtx, 0)
503 rc = DosCreateEventSem (NULL, &incdep_hev_todo, 0, FALSE);
504 if (rc)
505 fatal (f, _("DosCreateEventSem failed: rc=%d"), rc);
506 rc = DosCreateEventSem (NULL, &incdep_hev_done, 0, FALSE);
507 if (rc)
508 fatal (f, _("DosCreateEventSem failed: rc=%d"), rc);
509 incdep_hev_todo_waiters = 0;
510 incdep_hev_done_waiters = 0;
511#endif
512
513 /* create the worker threads. */
514
515 incdep_terminate = 0;
516 incdep_num_threads = sizeof (incdep_threads) / sizeof (incdep_threads[0]);
517 if (incdep_num_threads + 1 > job_slots)
518 incdep_num_threads = job_slots <= 1 ? 1 : job_slots - 1;
519 for (i = 0; i < incdep_num_threads; i++)
520 {
521#ifdef HAVE_PTHREAD
522 rc = pthread_attr_init (&attr);
523 if (rc)
524 fatal (f, _("pthread_attr_init failed: err=%d"), rc);
525 /*rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); */
526 rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
527 if (rc)
528 fatal (f, _("pthread_attr_setdetachstate failed: err=%d"), rc);
529 rc = pthread_create (&incdep_threads[i], &attr,
530 incdep_worker_pthread, f);
531 if (rc)
532 fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
533 pthread_attr_destroy (&attr);
534
535#elif defined (WINDOWS32)
536 tid = 0;
537 hThread = _beginthreadex (NULL, 128*1024, incdep_worker_windows,
538 NULL, 0, &tid);
539 if (hThread == 0 || hThread == ~(uintptr_t)0)
540 fatal (f, _("_beginthreadex failed: err=%d"), errno);
541 incdep_threads[i] = (HANDLE)hThread;
542
543#elif defined (__OS2__)
544 tid = _beginthread (incdep_worker_os2, NULL, 128*1024, NULL);
545 if (tid <= 0)
546 fatal (f, _("_beginthread failed: err=%d"), errno);
547 incdep_threads[i] = tid;
548#endif
549 }
550
551 incdep_initialized = 1;
552}
553
554/* Flushes outstanding work and terminates the worker threads.
555 This is called from snap_deps(). */
556void
557incdep_flush_and_term (void)
558{
559 unsigned i;
560
561 if (!incdep_initialized)
562 return;
563
564 /* flush any out standing work */
565
566 incdep_flush_it (NILF);
567
568 /* tell the threads to terminate */
569
570 incdep_lock ();
571 incdep_terminate = 1;
572 incdep_signal_todo ();
573 incdep_unlock ();
574
575 /* wait for the threads to quit */
576
577 for (i = 0; i < incdep_num_threads; i++)
578 {
579 /* later? */
580 }
581 incdep_num_threads = 0;
582
583 /* destroy the lock and condition variables / event objects. */
584
585 /* later */
586
587 incdep_initialized = 0;
588}
589
590#ifdef PARSE_IN_WORKER
591/* Flushes the recorded instructions. */
592static void
593incdep_flush_recorded_instructions (struct incdep *cur)
594{
595 struct incdep_variable_in_set *rec_vis;
596 struct incdep_variable_def *rec_vd;
597 struct incdep_recorded_files *rec_f;
598
599 /* define_variable_in_set */
600
601 rec_vis = cur->recorded_variables_in_set_head;
602 cur->recorded_variables_in_set_head = cur->recorded_variables_in_set_tail = NULL;
603 if (rec_vis)
604 do
605 {
606 void *free_me = rec_vis;
607 define_variable_in_set (strcache_add_len (rec_vis->name, rec_vis->name_length),
608 rec_vis->name_length,
609 rec_vis->value,
610 rec_vis->value_length,
611 rec_vis->duplicate_value,
612 rec_vis->origin,
613 rec_vis->recursive,
614 rec_vis->set,
615 rec_vis->flocp);
616 free (rec_vis->name);
617 rec_vis = rec_vis->next;
618 free (free_me);
619 }
620 while (rec_vis);
621
622 /* do_variable_definition */
623
624 rec_vd = cur->recorded_variable_defs_head;
625 cur->recorded_variable_defs_head = cur->recorded_variable_defs_tail = NULL;
626 if (rec_vd)
627 do
628 {
629 void *free_me = rec_vd;
630 do_variable_definition (rec_vd->flocp,
631 strcache_add_len(rec_vd->name, rec_vd->name_length),
632 rec_vd->value,
633 rec_vd->origin,
634 rec_vd->flavor,
635 rec_vd->target_var);
636 free (rec_vd->name);
637 free (rec_vd->value);
638 rec_vd = rec_vd->next;
639 free (free_me);
640 }
641 while (rec_vd);
642
643 /* record_files */
644
645 rec_f = cur->recorded_files_head;
646 cur->recorded_files_head = cur->recorded_files_tail = NULL;
647 if (rec_f)
648 do
649 {
650 void *free_me = rec_f;
651 struct dep *dep;
652 const char *newname;
653
654 for (dep = rec_f->deps; dep; dep = dep->next)
655 {
656 newname = strcache_add (dep->name);
657 free ((char *)dep->name);
658 dep->name = newname;
659 }
660
661 newname = strcache_add (rec_f->filenames->name);
662 free ((char *)rec_f->filenames->name);
663 rec_f->filenames->name = newname;
664
665 record_files (rec_f->filenames,
666 rec_f->pattern,
667 rec_f->pattern_percent,
668 rec_f->deps,
669 rec_f->cmds_started,
670 rec_f->commands,
671 rec_f->commands_idx,
672 rec_f->two_colon,
673 rec_f->flocp);
674
675 rec_f = rec_f->next;
676 free (free_me);
677 }
678 while (rec_f);
679}
680#endif /* PARSE_IN_WORKER */
681
682/* Record / issue a warning about a misformed dep file. */
683static void
684incdep_warn (struct incdep *cur, unsigned int line_no, const char *msg)
685{
686 if (!cur->is_worker)
687 error (NILF, "%s(%d): %s", cur->name, line_no, msg);
688#ifdef PARSE_IN_WORKER
689 else
690 {
691 cur->err_line_no = line_no;
692 cur->err_msg = msg;
693 }
694#endif
695}
696
697/* Record / execute a strcache add. */
698static const char *
699incdep_record_strcache (struct incdep *cur, const char *str, int len)
700{
701 const char *ret;
702 if (!cur->is_worker)
703 {
704 /* Make sure the string is terminated before we hand it to
705 strcache_add_len so it does have to make a temporary copy
706 of it on the stack. */
707 char ch = str[len];
708 ((char *)str)[len] = '\0';
709 ret = strcache_add_len (str, len);
710 ((char *)str)[len] = ch;
711 }
712 else
713 {
714 /* Duplicate the string. The other recorders knows which arguments
715 needs to be added to the string cache later. */
716 char *newstr = xmalloc (len + 1);
717 memcpy (newstr, str, len);
718 newstr[len] = '\0';
719 ret = newstr;
720 }
721 return ret;
722}
723
724/* Record / perform a variable definition in a set.
725 The NAME is in the string cache.
726 The VALUE is on the heap.
727 The DUPLICATE_VALUE is always 0. */
728static void
729incdep_record_variable_in_set (struct incdep *cur,
730 const char *name, unsigned int name_length,
731 const char *value,
732 unsigned int value_length,
733 int duplicate_value,
734 enum variable_origin origin,
735 int recursive,
736 struct variable_set *set,
737 const struct floc *flocp)
738{
739 assert (!duplicate_value);
740 if (!cur->is_worker)
741 define_variable_in_set (name, name_length, value, value_length,
742 duplicate_value, origin, recursive, set, flocp);
743#ifdef PARSE_IN_WORKER
744 else
745 {
746 struct incdep_variable_in_set *rec = xmalloc (sizeof (*rec));
747 rec->name = (char *)name;
748 rec->name_length = name_length;
749 rec->value = value;
750 rec->value_length = value_length;
751 rec->duplicate_value = duplicate_value;
752 rec->origin = origin;
753 rec->recursive = recursive;
754 rec->set = set;
755 rec->flocp = flocp;
756
757 rec->next = NULL;
758 if (cur->recorded_variables_in_set_tail)
759 cur->recorded_variables_in_set_tail->next = rec;
760 else
761 cur->recorded_variables_in_set_head = rec;
762 cur->recorded_variables_in_set_tail = rec;
763 }
764#endif
765}
766
767/* Record / perform a variable definition. The VALUE should be disposed of. */
768static void
769incdep_record_variable_def (struct incdep *cur,
770 const struct floc *flocp,
771 const char *name,
772 unsigned int name_length,
773 char *value,
774 enum variable_origin origin,
775 enum variable_flavor flavor,
776 int target_var)
777{
778 if (!cur->is_worker)
779 {
780 do_variable_definition (flocp, name, value, origin, flavor, target_var);
781 free (value);
782 }
783#ifdef PARSE_IN_WORKER
784 else
785 {
786 struct incdep_variable_def *rec = xmalloc (sizeof (*rec));
787 rec->flocp = flocp;
788 rec->name = (char *)name;
789 rec->name_length = name_length;
790 rec->value = value;
791 rec->origin = origin;
792 rec->flavor = flavor;
793 rec->target_var = target_var;
794
795 rec->next = NULL;
796 if (cur->recorded_variable_defs_tail)
797 cur->recorded_variable_defs_tail->next = rec;
798 else
799 cur->recorded_variable_defs_head = rec;
800 cur->recorded_variable_defs_tail = rec;
801 }
802#endif
803}
804
805/* Record files.*/
806static void
807incdep_record_files (struct incdep *cur,
808 struct nameseq *filenames, const char *pattern,
809 const char *pattern_percent, struct dep *deps,
810 unsigned int cmds_started, char *commands,
811 unsigned int commands_idx, int two_colon,
812 const struct floc *flocp)
813{
814 if (!cur->is_worker)
815 record_files (filenames, pattern, pattern_percent, deps, cmds_started,
816 commands, commands_idx, two_colon, flocp);
817#ifdef PARSE_IN_WORKER
818 else
819 {
820 struct incdep_recorded_files *rec = xmalloc (sizeof (*rec));
821
822 rec->filenames = filenames;
823 rec->pattern = pattern;
824 rec->pattern_percent = pattern_percent;
825 rec->deps = deps;
826 rec->cmds_started = cmds_started;
827 rec->commands = commands;
828 rec->commands_idx = commands_idx;
829 rec->two_colon = two_colon;
830 rec->flocp = flocp;
831
832 rec->next = NULL;
833 if (cur->recorded_files_tail)
834 cur->recorded_files_tail->next = rec;
835 else
836 cur->recorded_files_head = rec;
837 cur->recorded_files_tail = rec;
838 }
839#endif
840}
841
842
843/* no nonsense dependency file including.
844
845 Because nobody wants bogus dependency files to break their incremental
846 builds with hard to comprehend error messages, this function does not
847 use the normal eval routine but does all the parsing itself. This isn't,
848 as much work as it sounds, because the necessary feature set is very
849 limited.
850
851 eval_include_dep_file groks:
852
853 define var
854 endef
855
856 var [|:|?|>]= value [\]
857
858 [\]
859 file: [deps] [\]
860
861 */
862static void
863eval_include_dep_file (struct incdep *curdep, struct floc *f, int is_worker)
864{
865 unsigned line_no = 1;
866 const char *file_end = curdep->file_end;
867 const char *cur = curdep->file_base;
868 const char *endp;
869
870 /* if no file data, just return immediately. */
871 if (!cur)
872 return;
873 curdep->is_worker = is_worker;
874
875 /* now parse the file. */
876 while (cur < file_end)
877 {
878 /* skip empty lines */
879 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
880 ++cur;
881 if (cur >= file_end)
882 break;
883 if (*cur == '#')
884 {
885 cur = memchr (cur, '\n', file_end - cur);
886 if (!cur)
887 break;
888 }
889 if (*cur == '\\')
890 {
891 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
892 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
893 : (file_end - cur == 1) ? 1 : 0;
894 if (eol_len)
895 {
896 cur += eol_len;
897 line_no++;
898 continue;
899 }
900 }
901 if (*cur == '\n')
902 {
903 cur++;
904 line_no++;
905 continue;
906 }
907
908 /* define var
909 ...
910 endef */
911 if (strneq (cur, "define ", 7))
912 {
913 const char *var;
914 unsigned var_len;
915 const char *value_start;
916 const char *value_end;
917 char *value;
918 unsigned value_len;
919 int found_endef = 0;
920
921 /* extract the variable name. */
922 cur += 7;
923 while (isblank ((unsigned char)*cur))
924 ++cur;
925 value_start = endp = memchr (cur, '\n', file_end - cur);
926 if (!endp)
927 endp = cur;
928 while (endp > cur && isspace ((unsigned char)endp[-1]))
929 --endp;
930 var_len = endp - cur;
931 if (!var_len)
932 {
933 incdep_warn (curdep, line_no, "bogus define statement.");
934 break;
935 }
936 var = incdep_record_strcache (curdep, cur, var_len);
937
938 /* find the end of the variable. */
939 cur = value_end = value_start = value_start + 1;
940 ++line_no;
941 while (cur < file_end)
942 {
943 /* check for endef, don't bother with skipping leading spaces. */
944 if ( file_end - cur >= 5
945 && strneq (cur, "endef", 5))
946 {
947 endp = cur + 5;
948 while (endp < file_end && isspace ((unsigned char)*endp) && *endp != '\n')
949 endp++;
950 if (endp >= file_end || *endp == '\n')
951 {
952 found_endef = 1;
953 cur = endp >= file_end ? file_end : endp + 1;
954 break;
955 }
956 }
957
958 /* skip a line ahead. */
959 cur = value_end = memchr (cur, '\n', file_end - cur);
960 if (cur != NULL)
961 ++cur;
962 else
963 cur = value_end = file_end;
964 ++line_no;
965 }
966
967 if (!found_endef)
968 {
969 incdep_warn (curdep, line_no, "missing endef, dropping the rest of the file.");
970 break;
971 }
972 value_len = value_end - value_start;
973 if (memchr (value_start, '\0', value_len))
974 {
975 incdep_warn (curdep, line_no, "'\\0' in define, dropping the rest of the file.");
976 break;
977 }
978
979 /* make a copy of the value, converting \r\n to \n, and define it. */
980 value = xmalloc (value_len + 1);
981 endp = memchr (value_start, '\r', value_len);
982 if (endp)
983 {
984 const char *src = value_start;
985 char *dst = value;
986 for (;;)
987 {
988 size_t len = endp - src;
989 memcpy (dst, src, len);
990 dst += len;
991 src = endp;
992 if (src + 1 < file_end && src[1] == '\n')
993 src++; /* skip the '\r' */
994 if (src >= value_end)
995 break;
996 endp = memchr (endp + 1, '\r', src - value_end);
997 if (!endp)
998 endp = value_end;
999 }
1000 value_len = dst - value;
1001 }
1002 else
1003 memcpy (value, value_start, value_len);
1004 value [value_len] = '\0';
1005
1006 incdep_record_variable_in_set (curdep,
1007 var, var_len, value, value_len,
1008 0 /* don't duplicate */, o_file,
1009 0 /* defines are recursive but this is faster */,
1010 NULL /* global set */, f);
1011 }
1012
1013 /* file: deps
1014 OR
1015 variable [:]= value */
1016 else
1017 {
1018 const char *colonp;
1019 const char *equalp;
1020
1021 /* Look for a colon and an equal sign, optimize for colon.
1022 Only one file is support and the colon / equal must be on
1023 the same line. */
1024 colonp = memchr (cur, ':', file_end - cur);
1025#ifdef HAVE_DOS_PATHS
1026 while ( colonp
1027 && colonp + 1 < file_end
1028 && (colonp[1] == '/' || colonp[1] == '\\')
1029 && colonp > cur
1030 && isalpha ((unsigned char)colonp[-1])
1031 && ( colonp == cur + 1
1032 || strchr (" \t(", colonp[-2]) != 0))
1033 colonp = memchr (colonp + 1, ':', file_end - (colonp + 1));
1034#endif
1035 endp = NULL;
1036 if ( !colonp
1037 || (endp = memchr (cur, '\n', colonp - cur)))
1038 {
1039 colonp = NULL;
1040 equalp = memchr (cur, '=', (endp ? endp : file_end) - cur);
1041 if ( !equalp
1042 || (!endp && memchr (cur, '\n', equalp - cur)))
1043 {
1044 incdep_warn (curdep, line_no, "no colon.");
1045 break;
1046 }
1047 }
1048 else
1049 equalp = memchr (cur, '=', (colonp + 2 <= file_end
1050 ? colonp + 2 : file_end) - cur);
1051 if (equalp)
1052 {
1053 /* An assignment of some sort. */
1054 const char *var;
1055 unsigned var_len;
1056 const char *value_start;
1057 const char *value_end;
1058 char *value;
1059 unsigned value_len;
1060 unsigned multi_line = 0;
1061 enum variable_flavor flavor;
1062
1063 /* figure the flavor first. */
1064 flavor = f_recursive;
1065 if (equalp > cur)
1066 {
1067 if (equalp[-1] == ':')
1068 flavor = f_simple;
1069 else if (equalp[-1] == '?')
1070 flavor = f_conditional;
1071 else if (equalp[-1] == '+')
1072 flavor = f_append;
1073 else if (equalp[-1] == '>')
1074 flavor = f_prepend;
1075 }
1076
1077 /* extract the variable name. */
1078 endp = flavor == f_recursive ? equalp : equalp - 1;
1079 while (endp > cur && isblank ((unsigned char)endp[-1]))
1080 --endp;
1081 var_len = endp - cur;
1082 if (!var_len)
1083 {
1084 incdep_warn (curdep, line_no, "empty variable. (includedep)");
1085 break;
1086 }
1087 if ( memchr (cur, '$', var_len)
1088 || memchr (cur, ' ', var_len)
1089 || memchr (cur, '\t', var_len))
1090 {
1091 incdep_warn (curdep, line_no, "fancy variable name. (includedep)");
1092 break;
1093 }
1094 var = incdep_record_strcache (curdep, cur, var_len);
1095
1096 /* find the start of the value. */
1097 cur = equalp + 1;
1098 while (cur < file_end && isblank ((unsigned char)*cur))
1099 cur++;
1100 value_start = cur;
1101
1102 /* find the end of the value / line (this isn't 101% correct). */
1103 value_end = cur;
1104 while (cur < file_end)
1105 {
1106 endp = value_end = memchr (cur, '\n', file_end - cur);
1107 if (!value_end)
1108 value_end = file_end;
1109 if (value_end - 1 >= cur && value_end[-1] == '\r')
1110 --value_end;
1111 if (value_end - 1 < cur || value_end[-1] != '\\')
1112 {
1113 cur = endp ? endp + 1 : file_end;
1114 break;
1115 }
1116 --value_end;
1117 if (value_end - 1 >= cur && value_end[-1] == '\\')
1118 {
1119 incdep_warn (curdep, line_no, "fancy escaping! (includedep)");
1120 cur = NULL;
1121 break;
1122 }
1123 if (!endp)
1124 {
1125 cur = file_end;
1126 break;
1127 }
1128
1129 cur = endp + 1;
1130 ++multi_line;
1131 ++line_no;
1132 }
1133 if (!cur)
1134 break;
1135 ++line_no;
1136
1137 /* make a copy of the value, converting \r\n to \n, and define it. */
1138 value_len = value_end - value_start;
1139 value = xmalloc (value_len + 1);
1140 if (!multi_line)
1141 memcpy (value, value_start, value_len);
1142 else
1143 {
1144 /* unescape it */
1145 const char *src = value_start;
1146 char *dst = value;
1147 while (src < value_end)
1148 {
1149 const char *nextp;
1150
1151 endp = memchr (src, '\n', value_end - src);
1152 if (!endp)
1153 nextp = endp = value_end;
1154 else
1155 nextp = endp + 1;
1156 if (endp > src && endp[-1] == '\r')
1157 --endp;
1158 if (endp > src && endp[-1] == '\\')
1159 --endp;
1160
1161 if (src != value_start)
1162 *dst++ = ' ';
1163 memcpy (dst, src, endp - src);
1164 dst += endp - src;
1165 src = nextp;
1166 }
1167 value_len = dst - value;
1168 }
1169 value [value_len] = '\0';
1170
1171 /* do the definition */
1172 if (flavor == f_recursive
1173 || ( flavor == f_simple
1174 && !memchr (value, '$', value_len)))
1175 incdep_record_variable_in_set (curdep,
1176 var, var_len, value, value_len,
1177 0 /* don't duplicate */, o_file,
1178 flavor == f_recursive /* recursive */,
1179 NULL /* global set */, f);
1180 else
1181 incdep_record_variable_def (curdep,
1182 f, var, var_len, value, o_file, flavor,
1183 0 /* not target var */);
1184 }
1185 else
1186 {
1187 /* file: dependencies */
1188
1189 struct nameseq *filenames = 0;
1190 struct dep *deps = 0;
1191 struct dep **nextdep = &deps;
1192 struct dep *dep;
1193
1194 /* extract the filename, ASSUME a single one. */
1195 endp = colonp;
1196 while (endp > cur && isblank ((unsigned char)endp[-1]))
1197 --endp;
1198 if (cur == endp)
1199 {
1200 incdep_warn (curdep, line_no, "empty filename.");
1201 break;
1202 }
1203 if ( memchr (cur, '$', endp - cur)
1204 || memchr (cur, ' ', endp - cur)
1205 || memchr (cur, '\t', endp - cur))
1206 {
1207 incdep_warn (curdep, line_no, "multiple / fancy file name. (includedep)");
1208 break;
1209 }
1210 filenames = xmalloc (sizeof (struct nameseq));
1211 memset (filenames, 0, sizeof (*filenames));
1212 filenames->name = incdep_record_strcache (curdep, cur, endp - cur);
1213
1214 /* parse any dependencies. */
1215 cur = colonp + 1;
1216 while (cur < file_end)
1217 {
1218 /* skip blanks and count lines. */
1219 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
1220 ++cur;
1221 if (cur >= file_end)
1222 break;
1223 if (*cur == '\n')
1224 {
1225 cur++;
1226 line_no++;
1227 break;
1228 }
1229
1230 /* continuation + eol? */
1231 if (*cur == '\\')
1232 {
1233 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1234 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1235 : (file_end - cur == 1) ? 1 : 0;
1236 if (eol_len)
1237 {
1238 cur += eol_len;
1239 line_no++;
1240 continue;
1241 }
1242 }
1243
1244 /* find the end of the filename */
1245 endp = cur;
1246 while (endp < file_end && !isspace ((unsigned char)*endp))
1247 ++endp;
1248
1249 /* add it to the list. */
1250 *nextdep = dep = alloc_dep ();
1251 dep->name = incdep_record_strcache (curdep, cur, endp - cur);
1252 nextdep = &dep->next;
1253
1254 cur = endp;
1255 }
1256
1257 /* enter the file with its dependencies. */
1258 incdep_record_files (curdep,
1259 filenames, NULL, NULL, deps, 0, NULL, 0, 0, f);
1260 }
1261 }
1262 }
1263
1264 /* free the file data */
1265 if (is_worker)
1266 {
1267 free (curdep->file_base);
1268 curdep->file_base = curdep->file_end = NULL;
1269 }
1270}
1271
1272/* Flushes the incdep todo and done lists. */
1273static void
1274incdep_flush_it (struct floc *f)
1275{
1276 incdep_lock ();
1277 for (;;)
1278 {
1279 struct incdep *cur = incdep_head_done;
1280
1281 /* if the done list is empty, grab a todo list entry. */
1282 if (!cur && incdep_head_todo)
1283 {
1284 cur = incdep_head_todo;
1285 if (cur->next)
1286 incdep_head_todo = cur->next;
1287 else
1288 incdep_head_todo = incdep_tail_todo = NULL;
1289 incdep_unlock ();
1290
1291 incdep_read_file (cur, f);
1292 eval_include_dep_file (cur, f, 0);
1293 incdep_free (cur);
1294
1295 incdep_lock ();
1296 continue;
1297 }
1298
1299 /* if the todo list and done list are empty we're either done
1300 or will have to wait for the thread(s) to finish. */
1301 if (!cur && !incdep_num_reading)
1302 break; /* done */
1303 if (!cur)
1304 {
1305 while (!incdep_head_done)
1306 incdep_wait_done ();
1307 cur = incdep_head_done;
1308 }
1309
1310 /* we grab the entire done list and work thru it. */
1311 incdep_head_done = incdep_tail_done = NULL;
1312 incdep_unlock ();
1313
1314 while (cur)
1315 {
1316 struct incdep *next = cur->next;
1317#ifdef PARSE_IN_WORKER
1318 incdep_flush_recorded_instructions (cur);
1319#else
1320 eval_include_dep_file (cur, f, 0);
1321#endif
1322 incdep_free (cur);
1323 cur = next;
1324 }
1325
1326 incdep_lock ();
1327 } /* outer loop */
1328 incdep_unlock ();
1329}
1330
1331
1332/* splits up a list of file names and feeds it to eval_include_dep_file,
1333 employing threads to try speed up the file reading. */
1334void
1335eval_include_dep (const char *names, struct floc *f, enum incdep_op op)
1336{
1337 struct incdep *head = 0;
1338 struct incdep *tail = 0;
1339 struct incdep *cur;
1340 const char *names_iterator = names;
1341 const char *name;
1342 unsigned int name_len;
1343
1344 /* loop through NAMES, creating a todo list out of them. */
1345
1346 while ((name = find_next_token (&names_iterator, &name_len)) != 0)
1347 {
1348 cur = xmalloc (sizeof (*cur) + name_len);
1349 cur->file_base = cur->file_end = NULL;
1350 memcpy (cur->name, name, name_len);
1351 cur->name[name_len] = '\0';
1352 cur->is_worker = 0;
1353#ifdef PARSE_IN_WORKER
1354 cur->err_line_no = 0;
1355 cur->err_msg = NULL;
1356 cur->recorded_variables_in_set_head = NULL;
1357 cur->recorded_variables_in_set_tail = NULL;
1358 cur->recorded_variable_defs_head = NULL;
1359 cur->recorded_variable_defs_tail = NULL;
1360 cur->recorded_files_head = NULL;
1361 cur->recorded_files_tail = NULL;
1362#endif
1363
1364 cur->next = NULL;
1365 if (tail)
1366 tail->next = cur;
1367 else
1368 head = cur;
1369 tail = cur;
1370 }
1371
1372 if (op == incdep_read_it)
1373 {
1374 /* work our way thru the files directly */
1375
1376 cur = head;
1377 while (cur)
1378 {
1379 struct incdep *next = cur->next;
1380 incdep_read_file (cur, f);
1381 eval_include_dep_file (cur, f, 0); /* eats cur */
1382 cur = next;
1383 }
1384 }
1385 else
1386 {
1387 /* initialize the worker threads and related stuff the first time around. */
1388
1389 if (!incdep_initialized)
1390 incdep_init (f);
1391
1392 /* queue the files and notify the worker threads. */
1393
1394 incdep_lock ();
1395
1396 if (incdep_tail_todo)
1397 incdep_tail_todo->next = head;
1398 else
1399 incdep_head_todo = head;
1400 incdep_tail_todo = tail;
1401
1402 incdep_signal_todo ();
1403 incdep_unlock ();
1404
1405 /* flush the todo queue if we're requested to do so. */
1406
1407 if (op == incdep_flush)
1408 incdep_flush_it (f);
1409 }
1410}
1411
1412#endif /* CONFIG_WITH_INCLUDEDEP */
1413
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