source: trunk/src/kmk/output.c@ 3189

Last change on this file since 3189 was 3189, checked in by bird, 7 years ago

kmk/output: working on memory buffering rather than file buffering of job output.

  • Property svn:eol-style set to native
File size: 27.8 KB
Line 
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# ifndef CONFIG_NEW_WIN_CHILDREN
40# include "sub_proc.h"
41# else
42# include "w32/winchildren.h"
43# endif
44#endif /* WINDOWS32 */
45#ifdef KBUILD_OS_WINDOWS
46# include "console.h"
47#endif
48
49struct output *output_context = NULL;
50unsigned int stdio_traced = 0;
51
52#define OUTPUT_NONE (-1)
53
54#define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
55
56#ifdef HAVE_FCNTL_H
57# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
58#else
59# define STREAM_OK(_s) 1
60#endif
61
62
63#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
64# define MEMBUF_MIN_SEG_SIZE 4096
65# define MEMBUF_MAX_SEG_SIZE (512*1024)
66# define MEMBUF_MAX_MOVE_LEN ( MEMBUF_MIN_SEG_SIZE \
67 - offsetof (struct output_segment, runs) \
68 - sizeof (struct output_run))
69
70static void *acquire_semaphore (void);
71static void release_semaphore (void *);
72static int log_working_directory (int);
73
74/* Internal worker for output_dump and membuf_dump_most. */
75static void membuf_dump (struct output *out)
76{
77 if (out->out.total || out->err.total)
78 {
79 int traced = 0;
80 struct output_run *err_run;
81 struct output_run *out_run;
82 struct output_segment *seg;
83 FILE *prevdst;
84
85 /* Try to acquire the semaphore. If it fails, dump the output
86 unsynchronized; still better than silently discarding it.
87 We want to keep this lock for as little time as possible. */
88 void *sem = acquire_semaphore ();
89
90 /* Log the working directory for this dump. */
91 if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
92 traced = log_working_directory (1);
93
94 /* Work the out and err sequences in parallel. */
95 out_run = out->out.head_run;
96 err_run = out->err.head_run;
97 prevdst = NULL;
98 while (err_run || out_run)
99 {
100 FILE *dst;
101 const void *src;
102 size_t len;
103 if (out_run && (!err_run || out_run->seqno <= err_run->seqno))
104 {
105 src = out_run + 1;
106 len = out_run->len;
107 dst = stdout;
108 out_run = out_run->next;
109 }
110 else
111 {
112 src = err_run + 1;
113 len = err_run->len;
114 dst = stderr;
115 err_run = err_run->next;
116 }
117 if (dst != prevdst)
118 fflush(prevdst);
119 prevdst = dst;
120#ifdef KBUILD_OS_WINDOWS
121 maybe_con_fwrite (src, len, 1, dst);
122#else
123 fwrite (src, len, 1, dst);
124#endif
125 }
126 if (prevdst)
127 fflush (prevdst);
128
129 if (traced)
130 log_working_directory (0);
131
132 /* Exit the critical section. */
133 if (sem)
134 release_semaphore (sem);
135
136 /* Free the segments and reset the state. */
137 while ((seg = out->out.head_seg))
138 {
139 out->out.head_seg = seg->next;
140 free (seg);
141 }
142 out->out.tail_seg = NULL;
143 out->out.tail_run = NULL;
144 out->out.head_run = NULL;
145 out->out.left = 0;
146 out->out.total = 0;
147
148 while ((seg = out->err.head_seg))
149 {
150 out->err.head_seg = seg->next;
151 free (seg);
152 }
153 out->err.tail_seg = NULL;
154 out->err.tail_run = NULL;
155 out->err.head_run = NULL;
156 out->err.left = 0;
157 out->err.total = 0;
158
159 out->seqno = 0;
160 }
161 else
162 assert (out->out.head_seg == NULL && out->err.head_seg == NULL);
163}
164
165/* Writes up to LEN bytes to the given segment.
166 Returns how much was actually written. */
167static size_t
168membuf_write_segment (struct output_membuf *membuf, struct output_segment *seg,
169 const char *src, size_t len, unsigned int *pseqno)
170{
171 size_t written = 0;
172 if (seg && membuf->left > 0)
173 {
174 struct output_run *run = membuf->tail_run;
175 char *dst = (char *)(run + 1) + run->len;
176 assert ((uintptr_t)run - (uintptr_t)seg < seg->size);
177
178 /* If the sequence number didn't change, then we can append
179 to the current run without further considerations. */
180 if (run->seqno == *pseqno)
181 written = len;
182 /* If the current run does not end with a newline, don't start a new
183 run till we encounter one. */
184 else if (dst[-1] != '\n')
185 {
186 char const *srcnl = (const char *)memchr (src, '\n', len);
187 written = srcnl ? srcnl - src + 1 : len;
188 }
189 /* Try create a new empty run and append to it. */
190 else
191 {
192 size_t const offnextrun = ( (uintptr_t)dst - (uintptr_t)(seg)
193 + sizeof(void *) - 1)
194 & ~(sizeof(void *) - 1);
195 if (offnextrun > seg->size - sizeof (struct output_run) * 2)
196 return 0; /* need new segment */
197
198 run = run->next = (struct output_run *)((char *)seg + offnextrun);
199 run->next = NULL;
200 run->seqno = ++(*pseqno);
201 run->len = 0;
202 membuf->tail_run = run;
203 membuf->left = seg->size - (offnextrun + sizeof (*run));
204 dst = (char *)(run + 1);
205 written = len;
206 }
207
208 /* Append to the current run. */
209 if (written > membuf->left)
210 written = membuf->left;
211 memcpy (dst, src, written);
212 run->len += written;
213 membuf->left -= written;
214 }
215 return written;
216}
217
218/* Helper for membuf_new_segment_write that figures out now much data needs to
219 be moved from the previous run in order to make it end with a newline. */
220static size_t membuf_calc_move_len (struct output_run *tail_run)
221{
222 size_t to_move = 0;
223 if (tail_run)
224 {
225 const char *data = (const char *)(tail_run + 1);
226 size_t off = tail_run->len;
227 while (off > 0 && data[off - 1] != '\n')
228 off--;
229 to_move = tail_run->len - off;
230 if (to_move >= MEMBUF_MAX_MOVE_LEN)
231 to_move = 0;
232 }
233 return to_move;
234}
235
236/* Allocates a new segment and writes to it.
237 This will take care to make sure the previous run terminates with
238 a newline so that we pass whole lines to fwrite when dumping. */
239static size_t
240membuf_new_segment_write (struct output_membuf *membuf, const char *src,
241 size_t len, unsigned int *pseqno)
242{
243 struct output_run *prev_run = membuf->tail_run;
244 struct output_segment *prev_seg = membuf->tail_seg;
245 size_t const to_move = membuf_calc_move_len (prev_run);
246 struct output_segment *new_seg;
247 size_t written;
248 char *dst;
249
250 /* Figure the the segment size. We start with MEMBUF_MIN_SEG_SIZE and double
251 it each time till we reach MEMBUF_MAX_SEG_SIZE. */
252 size_t const offset_runs = offsetof (struct output_segment, runs);
253 size_t segsize = !prev_seg ? MEMBUF_MIN_SEG_SIZE
254 : prev_seg->size >= MEMBUF_MAX_SEG_SIZE ? MEMBUF_MAX_SEG_SIZE
255 : prev_seg->size * 2;
256 while ( segsize < to_move + len + offset_runs + sizeof (struct output_run) * 2
257 && segsize < MEMBUF_MAX_SEG_SIZE)
258 segsize *= 2;
259
260 /* Allocate the segment and link it and the first run. */
261 new_seg = (struct output_segment *)xmalloc (segsize);
262 new_seg->size = segsize;
263 new_seg->next = NULL;
264 new_seg->runs[0].next = NULL;
265 if (!prev_seg)
266 {
267 membuf->head_seg = new_seg;
268 membuf->head_run = &new_seg->runs[0];
269 }
270 else
271 {
272 prev_seg->next = new_seg;
273 prev_run->next = &new_seg->runs[0];
274 }
275 membuf->tail_seg = new_seg;
276 membuf->tail_run = &new_seg->runs[0];
277 membuf->total += segsize;
278 membuf->left = segsize - sizeof (struct output_run);
279
280 /* Initialize and write data to the first run. */
281 dst = (char *)&new_seg->runs[0]; /* Try bypass gcc array size cleverness. */
282 dst += sizeof (struct output_run);
283 assert (MEMBUF_MAX_MOVE_LEN < MEMBUF_MIN_SEG_SIZE);
284 if (to_move > 0)
285 {
286 /* Move to_move bytes from the previous run in hope that we'll get a
287 newline to soon. Afterwards call membuf_segment_write to work SRC. */
288 assert (prev_run != NULL);
289 assert (membuf->left >= to_move);
290 prev_run->len -= to_move;
291 new_seg->runs[0].len = to_move;
292 new_seg->runs[0].seqno = prev_run->seqno;
293 memcpy (dst, (const char *)(prev_run + 1) + prev_run->len, to_move);
294 membuf->left -= to_move;
295
296 written = membuf_write_segment (membuf, new_seg, src, len, pseqno);
297 }
298 else
299 {
300 /* Create a run with up to LEN from SRC. */
301 written = len;
302 if (written > membuf->left)
303 written = membuf->left;
304 new_seg->runs[0].len = written;
305 new_seg->runs[0].seqno = ++(*pseqno);
306 memcpy (dst, src, written);
307 membuf->left -= written;
308 }
309 return written;
310}
311
312/* Worker for output_write that will try dump as much as possible of the
313 output, but making sure to try leave unfinished lines. */
314static void
315membuf_dump_most (struct output *out)
316{
317 /** @todo check last segment and make local copies. */
318 membuf_dump (out);
319}
320
321/* write/fwrite like function. */
322void
323output_write (struct output *out, int is_err, const char *src, size_t len)
324{
325 if (!out || !out->syncout)
326 {
327 FILE *f = is_err ? stderr : stdout;
328#ifdef KBUILD_OS_WINDOWS
329 maybe_con_fwrite (src, len, 1, f);
330#else
331 fwrite (src, len, 1, f);
332#endif
333 fflush (f);
334 }
335 else
336 {
337 struct output_membuf *membuf = is_err ? &out->err : &out->out;
338 while (len > 0)
339 {
340 size_t runlen = membuf_write_segment (membuf, membuf->tail_seg, src, len, &out->seqno);
341 if (!runlen)
342 {
343 size_t max_total = sizeof (membuf) <= 4 ? 512*1024 : 16*1024*1024;
344 if (membuf->total < max_total)
345 runlen = membuf_new_segment_write (membuf, src, len, &out->seqno);
346 else
347 membuf_dump_most (out);
348 }
349 /* advance */
350 len -= runlen;
351 src += runlen;
352 }
353 }
354}
355
356#endif /* CONFIG_WITH_OUTPUT_IN_MEMORY */
357
358
359/* Write a string to the current STDOUT or STDERR. */
360static void
361_outputs (struct output *out, int is_err, const char *msg)
362{
363#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
364 output_write (out, is_err, msg, strlen (msg));
365#else /* !CONFIG_WITH_OUTPUT_IN_MEMORY */
366 if (! out || ! out->syncout)
367 {
368 FILE *f = is_err ? stderr : stdout;
369# ifdef KBUILD_OS_WINDOWS
370 maybe_con_fwrite(msg, strlen(msg), 1, f);
371# else
372 fputs (msg, f);
373# endif
374 fflush (f);
375 }
376 else
377 {
378 int fd = is_err ? out->err : out->out;
379 int len = strlen (msg);
380 int r;
381
382 EINTRLOOP (r, lseek (fd, 0, SEEK_END));
383 while (1)
384 {
385 EINTRLOOP (r, write (fd, msg, len));
386 if (r == len || r <= 0)
387 break;
388 len -= r;
389 msg += r;
390 }
391 }
392#endif /* !CONFIG_WITH_OUTPUT_IN_MEMORY */
393}
394
395
396/* Write a message indicating that we've just entered or
397 left (according to ENTERING) the current directory. */
398
399static int
400log_working_directory (int entering)
401{
402 static char *buf = NULL;
403 static unsigned int len = 0;
404 unsigned int need;
405 const char *fmt;
406 char *p;
407
408 /* Get enough space for the longest possible output. */
409 need = strlen (program) + INTSTR_LENGTH + 2 + 1;
410 if (starting_directory)
411 need += strlen (starting_directory);
412
413 /* Use entire sentences to give the translators a fighting chance. */
414 if (makelevel == 0)
415 if (starting_directory == 0)
416 if (entering)
417 fmt = _("%s: Entering an unknown directory\n");
418 else
419 fmt = _("%s: Leaving an unknown directory\n");
420 else
421 if (entering)
422 fmt = _("%s: Entering directory '%s'\n");
423 else
424 fmt = _("%s: Leaving directory '%s'\n");
425 else
426 if (starting_directory == 0)
427 if (entering)
428 fmt = _("%s[%u]: Entering an unknown directory\n");
429 else
430 fmt = _("%s[%u]: Leaving an unknown directory\n");
431 else
432 if (entering)
433 fmt = _("%s[%u]: Entering directory '%s'\n");
434 else
435 fmt = _("%s[%u]: Leaving directory '%s'\n");
436
437 need += strlen (fmt);
438
439 if (need > len)
440 {
441 buf = xrealloc (buf, need);
442 len = need;
443 }
444
445 p = buf;
446 if (print_data_base_flag)
447 {
448 *(p++) = '#';
449 *(p++) = ' ';
450 }
451
452 if (makelevel == 0)
453 if (starting_directory == 0)
454 sprintf (p, fmt , program);
455 else
456 sprintf (p, fmt, program, starting_directory);
457 else if (starting_directory == 0)
458 sprintf (p, fmt, program, makelevel);
459 else
460 sprintf (p, fmt, program, makelevel, starting_directory);
461
462 _outputs (NULL, 0, buf);
463
464 return 1;
465}
466
467/* Set a file descriptor to be in O_APPEND mode.
468 If it fails, just ignore it. */
469
470static void
471set_append_mode (int fd)
472{
473#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
474 int flags = fcntl (fd, F_GETFL, 0);
475 if (flags >= 0)
476 fcntl (fd, F_SETFL, flags | O_APPEND);
477#endif
478}
479
480
481
482#ifndef NO_OUTPUT_SYNC
483
484/* Semaphore for use in -j mode with output_sync. */
485static sync_handle_t sync_handle = -1;
486
487#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
488
489/* Set up the sync handle. Disables output_sync on error. */
490static int
491sync_init (void)
492{
493 int combined_output = 0;
494
495#ifdef WINDOWS32
496 if ((!STREAM_OK (stdout) && !STREAM_OK (stderr))
497 || (sync_handle = create_mutex ()) == -1)
498 {
499 perror_with_name ("output-sync suppressed: ", "stderr");
500 output_sync = 0;
501 }
502 else
503 {
504 combined_output = same_stream (stdout, stderr);
505 prepare_mutex_handle_string (sync_handle);
506 }
507
508#else
509 if (STREAM_OK (stdout))
510 {
511 struct stat stbuf_o, stbuf_e;
512
513 sync_handle = fileno (stdout);
514 combined_output = (fstat (fileno (stdout), &stbuf_o) == 0
515 && fstat (fileno (stderr), &stbuf_e) == 0
516 && stbuf_o.st_dev == stbuf_e.st_dev
517 && stbuf_o.st_ino == stbuf_e.st_ino);
518 }
519 else if (STREAM_OK (stderr))
520 sync_handle = fileno (stderr);
521 else
522 {
523 perror_with_name ("output-sync suppressed: ", "stderr");
524 output_sync = 0;
525 }
526#endif
527
528 return combined_output;
529}
530
531#ifndef CONFIG_WITH_OUTPUT_IN_MEMORY
532/* Support routine for output_sync() */
533static void
534pump_from_tmp (int from, FILE *to)
535{
536# ifdef KMK
537 char buffer[8192];
538# else
539 static char buffer[8192];
540#endif
541
542#ifdef WINDOWS32
543 int prev_mode;
544
545 /* "from" is opened by open_tmpfd, which does it in binary mode, so
546 we need the mode of "to" to match that. */
547 prev_mode = _setmode (fileno (to), _O_BINARY);
548#endif
549
550 if (lseek (from, 0, SEEK_SET) == -1)
551 perror ("lseek()");
552
553 while (1)
554 {
555 int len;
556 EINTRLOOP (len, read (from, buffer, sizeof (buffer)));
557 if (len < 0)
558 perror ("read()");
559 if (len <= 0)
560 break;
561 if (fwrite (buffer, len, 1, to) < 1)
562 {
563 perror ("fwrite()");
564 break;
565 }
566 fflush (to);
567 }
568
569#ifdef WINDOWS32
570 /* Switch "to" back to its original mode, so that log messages by
571 Make have the same EOL format as without --output-sync. */
572 _setmode (fileno (to), prev_mode);
573#endif
574}
575#endif /* CONFIG_WITH_OUTPUT_IN_MEMORY */
576
577/* Obtain the lock for writing output. */
578static void *
579acquire_semaphore (void)
580{
581 static struct flock fl;
582
583 fl.l_type = F_WRLCK;
584 fl.l_whence = SEEK_SET;
585 fl.l_start = 0;
586 fl.l_len = 1;
587 if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
588 return &fl;
589 perror ("fcntl()");
590 return NULL;
591}
592
593/* Release the lock for writing output. */
594static void
595release_semaphore (void *sem)
596{
597 struct flock *flp = (struct flock *)sem;
598 flp->l_type = F_UNLCK;
599 if (fcntl (sync_handle, F_SETLKW, flp) == -1)
600 perror ("fcntl()");
601}
602
603#ifndef CONFIG_WITH_OUTPUT_IN_MEMORY
604
605/* Returns a file descriptor to a temporary file. The file is automatically
606 closed/deleted on exit. Don't use a FILE* stream. */
607int
608output_tmpfd (void)
609{
610 int fd = -1;
611 FILE *tfile = tmpfile ();
612
613 if (! tfile)
614 pfatal_with_name ("tmpfile");
615
616 /* Create a duplicate so we can close the stream. */
617 fd = dup (fileno (tfile));
618 if (fd < 0)
619 pfatal_with_name ("dup");
620
621 fclose (tfile);
622
623 set_append_mode (fd);
624
625 return fd;
626}
627
628/* Adds file descriptors to the child structure to support output_sync; one
629 for stdout and one for stderr as long as they are open. If stdout and
630 stderr share a device they can share a temp file too.
631 Will reset output_sync on error. */
632static void
633setup_tmpfile (struct output *out)
634{
635 /* Is make's stdout going to the same place as stderr? */
636 static int combined_output = -1;
637
638 if (combined_output < 0)
639 combined_output = sync_init ();
640
641 if (STREAM_OK (stdout))
642 {
643 int fd = output_tmpfd ();
644 if (fd < 0)
645 goto error;
646 CLOSE_ON_EXEC (fd);
647 out->out = fd;
648 }
649
650 if (STREAM_OK (stderr))
651 {
652 if (out->out != OUTPUT_NONE && combined_output)
653 out->err = out->out;
654 else
655 {
656 int fd = output_tmpfd ();
657 if (fd < 0)
658 goto error;
659 CLOSE_ON_EXEC (fd);
660 out->err = fd;
661 }
662 }
663
664 return;
665
666 /* If we failed to create a temp file, disable output sync going forward. */
667 error:
668 output_close (out);
669 output_sync = OUTPUT_SYNC_NONE;
670}
671
672#endif /* CONFIG_WITH_OUTPUT_IN_MEMORY */
673
674/* Synchronize the output of jobs in -j mode to keep the results of
675 each job together. This is done by holding the results in temp files,
676 one for stdout and potentially another for stderr, and only releasing
677 them to "real" stdout/stderr when a semaphore can be obtained. */
678
679void
680output_dump (struct output *out)
681{
682#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
683 membuf_dump (out);
684#else
685 int outfd_not_empty = FD_NOT_EMPTY (out->out);
686 int errfd_not_empty = FD_NOT_EMPTY (out->err);
687
688 if (outfd_not_empty || errfd_not_empty)
689 {
690 int traced = 0;
691
692 /* Try to acquire the semaphore. If it fails, dump the output
693 unsynchronized; still better than silently discarding it.
694 We want to keep this lock for as little time as possible. */
695 void *sem = acquire_semaphore ();
696
697 /* Log the working directory for this dump. */
698 if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
699 traced = log_working_directory (1);
700
701 if (outfd_not_empty)
702 pump_from_tmp (out->out, stdout);
703 if (errfd_not_empty && out->err != out->out)
704 pump_from_tmp (out->err, stderr);
705
706 if (traced)
707 log_working_directory (0);
708
709 /* Exit the critical section. */
710 if (sem)
711 release_semaphore (sem);
712
713 /* Truncate and reset the output, in case we use it again. */
714 if (out->out != OUTPUT_NONE)
715 {
716 int e;
717 lseek (out->out, 0, SEEK_SET);
718 EINTRLOOP (e, ftruncate (out->out, 0));
719 }
720 if (out->err != OUTPUT_NONE && out->err != out->out)
721 {
722 int e;
723 lseek (out->err, 0, SEEK_SET);
724 EINTRLOOP (e, ftruncate (out->err, 0));
725 }
726 }
727#endif
728}
729#endif /* NO_OUTPUT_SYNC */
730
731
732
733/* Provide support for temporary files. */
734
735#ifndef HAVE_STDLIB_H
736# ifdef HAVE_MKSTEMP
737int mkstemp (char *template);
738# else
739char *mktemp (char *template);
740# endif
741#endif
742
743FILE *
744output_tmpfile (char **name, const char *template)
745{
746#ifdef HAVE_FDOPEN
747 int fd;
748#endif
749
750#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
751# define TEMPLATE_LEN strlen (template)
752#else
753# define TEMPLATE_LEN L_tmpnam
754#endif
755 *name = xmalloc (TEMPLATE_LEN + 1);
756 strcpy (*name, template);
757
758#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
759 /* It's safest to use mkstemp(), if we can. */
760 fd = mkstemp (*name);
761 if (fd == -1)
762 return 0;
763 return fdopen (fd, "w");
764#else
765# ifdef HAVE_MKTEMP
766 (void) mktemp (*name);
767# else
768 (void) tmpnam (*name);
769# endif
770
771# ifdef HAVE_FDOPEN
772 /* Can't use mkstemp(), but guard against a race condition. */
773 EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600));
774 if (fd == -1)
775 return 0;
776 return fdopen (fd, "w");
777# else
778 /* Not secure, but what can we do? */
779 return fopen (*name, "w");
780# endif
781#endif
782}
783
784
785
786/* This code is stolen from gnulib.
787 If/when we abandon the requirement to work with K&R compilers, we can
788 remove this (and perhaps other parts of GNU make!) and migrate to using
789 gnulib directly.
790
791 This is called only through atexit(), which means die() has already been
792 invoked. So, call exit() here directly. Apparently that works...?
793*/
794
795/* Close standard output, exiting with status 'exit_failure' on failure.
796 If a program writes *anything* to stdout, that program should close
797 stdout and make sure that it succeeds before exiting. Otherwise,
798 suppose that you go to the extreme of checking the return status
799 of every function that does an explicit write to stdout. The last
800 printf can succeed in writing to the internal stream buffer, and yet
801 the fclose(stdout) could still fail (due e.g., to a disk full error)
802 when it tries to write out that buffered data. Thus, you would be
803 left with an incomplete output file and the offending program would
804 exit successfully. Even calling fflush is not always sufficient,
805 since some file systems (NFS and CODA) buffer written/flushed data
806 until an actual close call.
807
808 Besides, it's wasteful to check the return value from every call
809 that writes to stdout -- just let the internal stream state record
810 the failure. That's what the ferror test is checking below.
811
812 It's important to detect such failures and exit nonzero because many
813 tools (most notably 'make' and other build-management systems) depend
814 on being able to detect failure in other tools via their exit status. */
815
816static void
817close_stdout (void)
818{
819 int prev_fail = ferror (stdout);
820 int fclose_fail = fclose (stdout);
821
822 if (prev_fail || fclose_fail)
823 {
824 if (fclose_fail)
825 perror_with_name (_("write error: stdout"), "");
826 else
827 O (error, NILF, _("write error: stdout"));
828 exit (MAKE_TROUBLE);
829 }
830}
831
832
833
834void
835output_init (struct output *out)
836{
837 if (out)
838 {
839#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
840 out->out.head_seg = NULL;
841 out->out.tail_seg = NULL;
842 out->out.head_run = NULL;
843 out->out.tail_run = NULL;
844 out->err.head_seg = NULL;
845 out->err.tail_seg = NULL;
846 out->err.head_run = NULL;
847 out->err.tail_run = NULL;
848 out->err.total = 0;
849 out->out.total = 0;
850 out->seqno = 0;
851#else
852 out->out = out->err = OUTPUT_NONE;
853#endif
854 out->syncout = !!output_sync;
855 return;
856 }
857
858 /* Configure this instance of make. Be sure stdout is line-buffered. */
859
860#ifdef HAVE_SETVBUF
861# ifdef SETVBUF_REVERSED
862 setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
863# else /* setvbuf not reversed. */
864 /* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
865 setvbuf (stdout, 0, _IOLBF, BUFSIZ);
866# endif /* setvbuf reversed. */
867#elif HAVE_SETLINEBUF
868 setlinebuf (stdout);
869#endif /* setlinebuf missing. */
870
871 /* Force stdout/stderr into append mode. This ensures parallel jobs won't
872 lose output due to overlapping writes. */
873 set_append_mode (fileno (stdout));
874 set_append_mode (fileno (stderr));
875
876#ifdef HAVE_ATEXIT
877 if (STREAM_OK (stdout))
878 atexit (close_stdout);
879#endif
880}
881
882void
883output_close (struct output *out)
884{
885 if (! out)
886 {
887 if (stdio_traced)
888 log_working_directory (0);
889 return;
890 }
891
892#ifndef NO_OUTPUT_SYNC
893 output_dump (out);
894#endif
895
896#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
897 assert (out->out.total == 0);
898 assert (out->out.head_seg == NULL);
899 assert (out->err.total == 0);
900 assert (out->err.head_seg == NULL);
901#else
902 if (out->out >= 0)
903 close (out->out);
904 if (out->err >= 0 && out->err != out->out)
905 close (out->err);
906#endif
907
908 output_init (out);
909}
910
911/* We're about to generate output: be sure it's set up. */
912void
913output_start (void)
914{
915#ifndef CONFIG_WITH_OUTPUT_IN_MEMORY
916#ifndef NO_OUTPUT_SYNC
917 /* If we're syncing output make sure the temporary file is set up. */
918 if (output_context && output_context->syncout)
919 if (! OUTPUT_ISSET(output_context))
920 setup_tmpfile (output_context);
921#endif
922#endif
923
924 /* If we're not syncing this output per-line or per-target, make sure we emit
925 the "Entering..." message where appropriate. */
926 if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
927 if (! stdio_traced && print_directory_flag)
928 stdio_traced = log_working_directory (1);
929}
930
931void
932outputs (int is_err, const char *msg)
933{
934 if (! msg || *msg == '\0')
935 return;
936
937 output_start ();
938
939 _outputs (output_context, is_err, msg);
940}
941
942
943
944static struct fmtstring
945 {
946 char *buffer;
947 size_t size;
948 } fmtbuf = { NULL, 0 };
949
950static char *
951get_buffer (size_t need)
952{
953 /* Make sure we have room. NEED includes space for \0. */
954 if (need > fmtbuf.size)
955 {
956 fmtbuf.size += need * 2;
957 fmtbuf.buffer = xrealloc (fmtbuf.buffer, fmtbuf.size);
958 }
959
960 fmtbuf.buffer[need-1] = '\0';
961
962 return fmtbuf.buffer;
963}
964
965/* Print a message on stdout. */
966
967void
968message (int prefix, size_t len, const char *fmt, ...)
969{
970 va_list args;
971 char *p;
972
973 len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
974 p = get_buffer (len);
975
976 if (prefix)
977 {
978 if (makelevel == 0)
979 sprintf (p, "%s: ", program);
980 else
981 sprintf (p, "%s[%u]: ", program, makelevel);
982 p += strlen (p);
983 }
984
985 va_start (args, fmt);
986 vsprintf (p, fmt, args);
987 va_end (args);
988
989 strcat (p, "\n");
990
991 assert (fmtbuf.buffer[len-1] == '\0');
992 outputs (0, fmtbuf.buffer);
993}
994
995/* Print an error message. */
996
997void
998error (const floc *flocp, size_t len, const char *fmt, ...)
999{
1000 va_list args;
1001 char *p;
1002
1003 len += (strlen (fmt) + strlen (program)
1004 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
1005 + INTSTR_LENGTH + 4 + 1 + 1);
1006 p = get_buffer (len);
1007
1008 if (flocp && flocp->filenm)
1009 sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
1010 else if (makelevel == 0)
1011 sprintf (p, "%s: ", program);
1012 else
1013 sprintf (p, "%s[%u]: ", program, makelevel);
1014 p += strlen (p);
1015
1016 va_start (args, fmt);
1017 vsprintf (p, fmt, args);
1018 va_end (args);
1019
1020 strcat (p, "\n");
1021
1022 assert (fmtbuf.buffer[len-1] == '\0');
1023 outputs (1, fmtbuf.buffer);
1024}
1025
1026/* Print an error message and exit. */
1027
1028void
1029fatal (const floc *flocp, size_t len, const char *fmt, ...)
1030{
1031 va_list args;
1032 const char *stop = _(". Stop.\n");
1033 char *p;
1034
1035 len += (strlen (fmt) + strlen (program)
1036 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
1037 + INTSTR_LENGTH + 8 + strlen (stop) + 1);
1038 p = get_buffer (len);
1039
1040 if (flocp && flocp->filenm)
1041 sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
1042 else if (makelevel == 0)
1043 sprintf (p, "%s: *** ", program);
1044 else
1045 sprintf (p, "%s[%u]: *** ", program, makelevel);
1046 p += strlen (p);
1047
1048 va_start (args, fmt);
1049 vsprintf (p, fmt, args);
1050 va_end (args);
1051
1052 strcat (p, stop);
1053
1054 assert (fmtbuf.buffer[len-1] == '\0');
1055 outputs (1, fmtbuf.buffer);
1056
1057 die (MAKE_FAILURE);
1058}
1059
1060/* Print an error message from errno. */
1061
1062void
1063perror_with_name (const char *str, const char *name)
1064{
1065 const char *err = strerror (errno);
1066 OSSS (error, NILF, _("%s%s: %s"), str, name, err);
1067}
1068
1069/* Print an error message from errno and exit. */
1070
1071void
1072pfatal_with_name (const char *name)
1073{
1074 const char *err = strerror (errno);
1075 OSS (fatal, NILF, _("%s: %s"), name, err);
1076
1077 /* NOTREACHED */
1078}
Note: See TracBrowser for help on using the repository browser.