VirtualBox

source: kBuild/vendor/gnumake/current/output.c

最後變更 在這個檔案是 3138,由 bird 提交於 7 年 前

Imported make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6) from https://git.savannah.gnu.org/git/make.git.

  • 屬性 svn:eol-style 設為 native
檔案大小: 17.3 KB
 
1/* Output to stdout / stderr for GNU make
2Copyright (C) 2013-2016 Free Software Foundation, Inc.
3This file is part of GNU Make.
4
5GNU Make is free software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the Free Software
7Foundation; either version 3 of the License, or (at your option) any later
8version.
9
10GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "makeint.h"
18#include "job.h"
19
20/* GNU make no longer supports pre-ANSI89 environments. */
21
22#include <assert.h>
23#include <stdio.h>
24#include <stdarg.h>
25
26#ifdef HAVE_UNISTD_H
27# include <unistd.h>
28#endif
29
30#ifdef HAVE_FCNTL_H
31# include <fcntl.h>
32#else
33# include <sys/file.h>
34#endif
35
36#ifdef WINDOWS32
37# include <windows.h>
38# include <io.h>
39# include "sub_proc.h"
40#endif /* WINDOWS32 */
41
42struct output *output_context = NULL;
43unsigned int stdio_traced = 0;
44
45#define OUTPUT_NONE (-1)
46
47#define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
48
49#ifdef HAVE_FCNTL_H
50# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
51#else
52# define STREAM_OK(_s) 1
53#endif
54
55/* Write a string to the current STDOUT or STDERR. */
56static void
57_outputs (struct output *out, int is_err, const char *msg)
58{
59 if (! out || ! out->syncout)
60 {
61 FILE *f = is_err ? stderr : stdout;
62 fputs (msg, f);
63 fflush (f);
64 }
65 else
66 {
67 int fd = is_err ? out->err : out->out;
68 int len = strlen (msg);
69 int r;
70
71 EINTRLOOP (r, lseek (fd, 0, SEEK_END));
72 while (1)
73 {
74 EINTRLOOP (r, write (fd, msg, len));
75 if (r == len || r <= 0)
76 break;
77 len -= r;
78 msg += r;
79 }
80 }
81}
82
83
84/* Write a message indicating that we've just entered or
85 left (according to ENTERING) the current directory. */
86
87static int
88log_working_directory (int entering)
89{
90 static char *buf = NULL;
91 static unsigned int len = 0;
92 unsigned int need;
93 const char *fmt;
94 char *p;
95
96 /* Get enough space for the longest possible output. */
97 need = strlen (program) + INTSTR_LENGTH + 2 + 1;
98 if (starting_directory)
99 need += strlen (starting_directory);
100
101 /* Use entire sentences to give the translators a fighting chance. */
102 if (makelevel == 0)
103 if (starting_directory == 0)
104 if (entering)
105 fmt = _("%s: Entering an unknown directory\n");
106 else
107 fmt = _("%s: Leaving an unknown directory\n");
108 else
109 if (entering)
110 fmt = _("%s: Entering directory '%s'\n");
111 else
112 fmt = _("%s: Leaving directory '%s'\n");
113 else
114 if (starting_directory == 0)
115 if (entering)
116 fmt = _("%s[%u]: Entering an unknown directory\n");
117 else
118 fmt = _("%s[%u]: Leaving an unknown directory\n");
119 else
120 if (entering)
121 fmt = _("%s[%u]: Entering directory '%s'\n");
122 else
123 fmt = _("%s[%u]: Leaving directory '%s'\n");
124
125 need += strlen (fmt);
126
127 if (need > len)
128 {
129 buf = xrealloc (buf, need);
130 len = need;
131 }
132
133 p = buf;
134 if (print_data_base_flag)
135 {
136 *(p++) = '#';
137 *(p++) = ' ';
138 }
139
140 if (makelevel == 0)
141 if (starting_directory == 0)
142 sprintf (p, fmt , program);
143 else
144 sprintf (p, fmt, program, starting_directory);
145 else if (starting_directory == 0)
146 sprintf (p, fmt, program, makelevel);
147 else
148 sprintf (p, fmt, program, makelevel, starting_directory);
149
150 _outputs (NULL, 0, buf);
151
152 return 1;
153}
154
155/* Set a file descriptor to be in O_APPEND mode.
156 If it fails, just ignore it. */
157
158static void
159set_append_mode (int fd)
160{
161#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
162 int flags = fcntl (fd, F_GETFL, 0);
163 if (flags >= 0)
164 fcntl (fd, F_SETFL, flags | O_APPEND);
165#endif
166}
167
168
169
170#ifndef NO_OUTPUT_SYNC
171
172/* Semaphore for use in -j mode with output_sync. */
173static sync_handle_t sync_handle = -1;
174
175#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
176
177/* Set up the sync handle. Disables output_sync on error. */
178static int
179sync_init (void)
180{
181 int combined_output = 0;
182
183#ifdef WINDOWS32
184 if ((!STREAM_OK (stdout) && !STREAM_OK (stderr))
185 || (sync_handle = create_mutex ()) == -1)
186 {
187 perror_with_name ("output-sync suppressed: ", "stderr");
188 output_sync = 0;
189 }
190 else
191 {
192 combined_output = same_stream (stdout, stderr);
193 prepare_mutex_handle_string (sync_handle);
194 }
195
196#else
197 if (STREAM_OK (stdout))
198 {
199 struct stat stbuf_o, stbuf_e;
200
201 sync_handle = fileno (stdout);
202 combined_output = (fstat (fileno (stdout), &stbuf_o) == 0
203 && fstat (fileno (stderr), &stbuf_e) == 0
204 && stbuf_o.st_dev == stbuf_e.st_dev
205 && stbuf_o.st_ino == stbuf_e.st_ino);
206 }
207 else if (STREAM_OK (stderr))
208 sync_handle = fileno (stderr);
209 else
210 {
211 perror_with_name ("output-sync suppressed: ", "stderr");
212 output_sync = 0;
213 }
214#endif
215
216 return combined_output;
217}
218
219/* Support routine for output_sync() */
220static void
221pump_from_tmp (int from, FILE *to)
222{
223 static char buffer[8192];
224
225#ifdef WINDOWS32
226 int prev_mode;
227
228 /* "from" is opened by open_tmpfd, which does it in binary mode, so
229 we need the mode of "to" to match that. */
230 prev_mode = _setmode (fileno (to), _O_BINARY);
231#endif
232
233 if (lseek (from, 0, SEEK_SET) == -1)
234 perror ("lseek()");
235
236 while (1)
237 {
238 int len;
239 EINTRLOOP (len, read (from, buffer, sizeof (buffer)));
240 if (len < 0)
241 perror ("read()");
242 if (len <= 0)
243 break;
244 if (fwrite (buffer, len, 1, to) < 1)
245 {
246 perror ("fwrite()");
247 break;
248 }
249 fflush (to);
250 }
251
252#ifdef WINDOWS32
253 /* Switch "to" back to its original mode, so that log messages by
254 Make have the same EOL format as without --output-sync. */
255 _setmode (fileno (to), prev_mode);
256#endif
257}
258
259/* Obtain the lock for writing output. */
260static void *
261acquire_semaphore (void)
262{
263 static struct flock fl;
264
265 fl.l_type = F_WRLCK;
266 fl.l_whence = SEEK_SET;
267 fl.l_start = 0;
268 fl.l_len = 1;
269 if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
270 return &fl;
271 perror ("fcntl()");
272 return NULL;
273}
274
275/* Release the lock for writing output. */
276static void
277release_semaphore (void *sem)
278{
279 struct flock *flp = (struct flock *)sem;
280 flp->l_type = F_UNLCK;
281 if (fcntl (sync_handle, F_SETLKW, flp) == -1)
282 perror ("fcntl()");
283}
284
285/* Returns a file descriptor to a temporary file. The file is automatically
286 closed/deleted on exit. Don't use a FILE* stream. */
287int
288output_tmpfd (void)
289{
290 int fd = -1;
291 FILE *tfile = tmpfile ();
292
293 if (! tfile)
294 pfatal_with_name ("tmpfile");
295
296 /* Create a duplicate so we can close the stream. */
297 fd = dup (fileno (tfile));
298 if (fd < 0)
299 pfatal_with_name ("dup");
300
301 fclose (tfile);
302
303 set_append_mode (fd);
304
305 return fd;
306}
307
308/* Adds file descriptors to the child structure to support output_sync; one
309 for stdout and one for stderr as long as they are open. If stdout and
310 stderr share a device they can share a temp file too.
311 Will reset output_sync on error. */
312static void
313setup_tmpfile (struct output *out)
314{
315 /* Is make's stdout going to the same place as stderr? */
316 static int combined_output = -1;
317
318 if (combined_output < 0)
319 combined_output = sync_init ();
320
321 if (STREAM_OK (stdout))
322 {
323 int fd = output_tmpfd ();
324 if (fd < 0)
325 goto error;
326 CLOSE_ON_EXEC (fd);
327 out->out = fd;
328 }
329
330 if (STREAM_OK (stderr))
331 {
332 if (out->out != OUTPUT_NONE && combined_output)
333 out->err = out->out;
334 else
335 {
336 int fd = output_tmpfd ();
337 if (fd < 0)
338 goto error;
339 CLOSE_ON_EXEC (fd);
340 out->err = fd;
341 }
342 }
343
344 return;
345
346 /* If we failed to create a temp file, disable output sync going forward. */
347 error:
348 output_close (out);
349 output_sync = OUTPUT_SYNC_NONE;
350}
351
352/* Synchronize the output of jobs in -j mode to keep the results of
353 each job together. This is done by holding the results in temp files,
354 one for stdout and potentially another for stderr, and only releasing
355 them to "real" stdout/stderr when a semaphore can be obtained. */
356
357void
358output_dump (struct output *out)
359{
360 int outfd_not_empty = FD_NOT_EMPTY (out->out);
361 int errfd_not_empty = FD_NOT_EMPTY (out->err);
362
363 if (outfd_not_empty || errfd_not_empty)
364 {
365 int traced = 0;
366
367 /* Try to acquire the semaphore. If it fails, dump the output
368 unsynchronized; still better than silently discarding it.
369 We want to keep this lock for as little time as possible. */
370 void *sem = acquire_semaphore ();
371
372 /* Log the working directory for this dump. */
373 if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
374 traced = log_working_directory (1);
375
376 if (outfd_not_empty)
377 pump_from_tmp (out->out, stdout);
378 if (errfd_not_empty && out->err != out->out)
379 pump_from_tmp (out->err, stderr);
380
381 if (traced)
382 log_working_directory (0);
383
384 /* Exit the critical section. */
385 if (sem)
386 release_semaphore (sem);
387
388 /* Truncate and reset the output, in case we use it again. */
389 if (out->out != OUTPUT_NONE)
390 {
391 int e;
392 lseek (out->out, 0, SEEK_SET);
393 EINTRLOOP (e, ftruncate (out->out, 0));
394 }
395 if (out->err != OUTPUT_NONE && out->err != out->out)
396 {
397 int e;
398 lseek (out->err, 0, SEEK_SET);
399 EINTRLOOP (e, ftruncate (out->err, 0));
400 }
401 }
402}
403#endif /* NO_OUTPUT_SYNC */
404
405
406
407/* Provide support for temporary files. */
408
409#ifndef HAVE_STDLIB_H
410# ifdef HAVE_MKSTEMP
411int mkstemp (char *template);
412# else
413char *mktemp (char *template);
414# endif
415#endif
416
417FILE *
418output_tmpfile (char **name, const char *template)
419{
420#ifdef HAVE_FDOPEN
421 int fd;
422#endif
423
424#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
425# define TEMPLATE_LEN strlen (template)
426#else
427# define TEMPLATE_LEN L_tmpnam
428#endif
429 *name = xmalloc (TEMPLATE_LEN + 1);
430 strcpy (*name, template);
431
432#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
433 /* It's safest to use mkstemp(), if we can. */
434 fd = mkstemp (*name);
435 if (fd == -1)
436 return 0;
437 return fdopen (fd, "w");
438#else
439# ifdef HAVE_MKTEMP
440 (void) mktemp (*name);
441# else
442 (void) tmpnam (*name);
443# endif
444
445# ifdef HAVE_FDOPEN
446 /* Can't use mkstemp(), but guard against a race condition. */
447 EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600));
448 if (fd == -1)
449 return 0;
450 return fdopen (fd, "w");
451# else
452 /* Not secure, but what can we do? */
453 return fopen (*name, "w");
454# endif
455#endif
456}
457
458
459
460/* This code is stolen from gnulib.
461 If/when we abandon the requirement to work with K&R compilers, we can
462 remove this (and perhaps other parts of GNU make!) and migrate to using
463 gnulib directly.
464
465 This is called only through atexit(), which means die() has already been
466 invoked. So, call exit() here directly. Apparently that works...?
467*/
468
469/* Close standard output, exiting with status 'exit_failure' on failure.
470 If a program writes *anything* to stdout, that program should close
471 stdout and make sure that it succeeds before exiting. Otherwise,
472 suppose that you go to the extreme of checking the return status
473 of every function that does an explicit write to stdout. The last
474 printf can succeed in writing to the internal stream buffer, and yet
475 the fclose(stdout) could still fail (due e.g., to a disk full error)
476 when it tries to write out that buffered data. Thus, you would be
477 left with an incomplete output file and the offending program would
478 exit successfully. Even calling fflush is not always sufficient,
479 since some file systems (NFS and CODA) buffer written/flushed data
480 until an actual close call.
481
482 Besides, it's wasteful to check the return value from every call
483 that writes to stdout -- just let the internal stream state record
484 the failure. That's what the ferror test is checking below.
485
486 It's important to detect such failures and exit nonzero because many
487 tools (most notably 'make' and other build-management systems) depend
488 on being able to detect failure in other tools via their exit status. */
489
490static void
491close_stdout (void)
492{
493 int prev_fail = ferror (stdout);
494 int fclose_fail = fclose (stdout);
495
496 if (prev_fail || fclose_fail)
497 {
498 if (fclose_fail)
499 perror_with_name (_("write error: stdout"), "");
500 else
501 O (error, NILF, _("write error: stdout"));
502 exit (MAKE_TROUBLE);
503 }
504}
505
506
507
508void
509output_init (struct output *out)
510{
511 if (out)
512 {
513 out->out = out->err = OUTPUT_NONE;
514 out->syncout = !!output_sync;
515 return;
516 }
517
518 /* Configure this instance of make. Be sure stdout is line-buffered. */
519
520#ifdef HAVE_SETVBUF
521# ifdef SETVBUF_REVERSED
522 setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
523# else /* setvbuf not reversed. */
524 /* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
525 setvbuf (stdout, 0, _IOLBF, BUFSIZ);
526# endif /* setvbuf reversed. */
527#elif HAVE_SETLINEBUF
528 setlinebuf (stdout);
529#endif /* setlinebuf missing. */
530
531 /* Force stdout/stderr into append mode. This ensures parallel jobs won't
532 lose output due to overlapping writes. */
533 set_append_mode (fileno (stdout));
534 set_append_mode (fileno (stderr));
535
536#ifdef HAVE_ATEXIT
537 if (STREAM_OK (stdout))
538 atexit (close_stdout);
539#endif
540}
541
542void
543output_close (struct output *out)
544{
545 if (! out)
546 {
547 if (stdio_traced)
548 log_working_directory (0);
549 return;
550 }
551
552#ifndef NO_OUTPUT_SYNC
553 output_dump (out);
554#endif
555
556 if (out->out >= 0)
557 close (out->out);
558 if (out->err >= 0 && out->err != out->out)
559 close (out->err);
560
561 output_init (out);
562}
563
564/* We're about to generate output: be sure it's set up. */
565void
566output_start (void)
567{
568#ifndef NO_OUTPUT_SYNC
569 /* If we're syncing output make sure the temporary file is set up. */
570 if (output_context && output_context->syncout)
571 if (! OUTPUT_ISSET(output_context))
572 setup_tmpfile (output_context);
573#endif
574
575 /* If we're not syncing this output per-line or per-target, make sure we emit
576 the "Entering..." message where appropriate. */
577 if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
578 if (! stdio_traced && print_directory_flag)
579 stdio_traced = log_working_directory (1);
580}
581
582void
583outputs (int is_err, const char *msg)
584{
585 if (! msg || *msg == '\0')
586 return;
587
588 output_start ();
589
590 _outputs (output_context, is_err, msg);
591}
592
593
594
595static struct fmtstring
596 {
597 char *buffer;
598 size_t size;
599 } fmtbuf = { NULL, 0 };
600
601static char *
602get_buffer (size_t need)
603{
604 /* Make sure we have room. NEED includes space for \0. */
605 if (need > fmtbuf.size)
606 {
607 fmtbuf.size += need * 2;
608 fmtbuf.buffer = xrealloc (fmtbuf.buffer, fmtbuf.size);
609 }
610
611 fmtbuf.buffer[need-1] = '\0';
612
613 return fmtbuf.buffer;
614}
615
616/* Print a message on stdout. */
617
618void
619message (int prefix, size_t len, const char *fmt, ...)
620{
621 va_list args;
622 char *p;
623
624 len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
625 p = get_buffer (len);
626
627 if (prefix)
628 {
629 if (makelevel == 0)
630 sprintf (p, "%s: ", program);
631 else
632 sprintf (p, "%s[%u]: ", program, makelevel);
633 p += strlen (p);
634 }
635
636 va_start (args, fmt);
637 vsprintf (p, fmt, args);
638 va_end (args);
639
640 strcat (p, "\n");
641
642 assert (fmtbuf.buffer[len-1] == '\0');
643 outputs (0, fmtbuf.buffer);
644}
645
646/* Print an error message. */
647
648void
649error (const floc *flocp, size_t len, const char *fmt, ...)
650{
651 va_list args;
652 char *p;
653
654 len += (strlen (fmt) + strlen (program)
655 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
656 + INTSTR_LENGTH + 4 + 1 + 1);
657 p = get_buffer (len);
658
659 if (flocp && flocp->filenm)
660 sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
661 else if (makelevel == 0)
662 sprintf (p, "%s: ", program);
663 else
664 sprintf (p, "%s[%u]: ", program, makelevel);
665 p += strlen (p);
666
667 va_start (args, fmt);
668 vsprintf (p, fmt, args);
669 va_end (args);
670
671 strcat (p, "\n");
672
673 assert (fmtbuf.buffer[len-1] == '\0');
674 outputs (1, fmtbuf.buffer);
675}
676
677/* Print an error message and exit. */
678
679void
680fatal (const floc *flocp, size_t len, const char *fmt, ...)
681{
682 va_list args;
683 const char *stop = _(". Stop.\n");
684 char *p;
685
686 len += (strlen (fmt) + strlen (program)
687 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
688 + INTSTR_LENGTH + 8 + strlen (stop) + 1);
689 p = get_buffer (len);
690
691 if (flocp && flocp->filenm)
692 sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
693 else if (makelevel == 0)
694 sprintf (p, "%s: *** ", program);
695 else
696 sprintf (p, "%s[%u]: *** ", program, makelevel);
697 p += strlen (p);
698
699 va_start (args, fmt);
700 vsprintf (p, fmt, args);
701 va_end (args);
702
703 strcat (p, stop);
704
705 assert (fmtbuf.buffer[len-1] == '\0');
706 outputs (1, fmtbuf.buffer);
707
708 die (MAKE_FAILURE);
709}
710
711/* Print an error message from errno. */
712
713void
714perror_with_name (const char *str, const char *name)
715{
716 const char *err = strerror (errno);
717 OSSS (error, NILF, _("%s%s: %s"), str, name, err);
718}
719
720/* Print an error message from errno and exit. */
721
722void
723pfatal_with_name (const char *name)
724{
725 const char *err = strerror (errno);
726 OSS (fatal, NILF, _("%s: %s"), name, err);
727
728 /* NOTREACHED */
729}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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