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

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

kmk/output: Basic memory buffered output working.

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