Hi,
As you know, running parallel builds with '-jX' makes the shell output
difficult to read, since output from parallel jobs are mixed. To remedy
this, the use of a buffering shell wrapper has been suggested:
http://cmcrossroads.com/cm-basics/12838-descrambling-parallel-build-logs
I liked the idea, but implementation was lacking so I rewrote the
wrapper.
To further descramble output, upgrade to make 3.82 and use .ONESHELL:
directive. For doing this with the wrapper, a simple patch needs to be
applied to make so it treats the wrapper as a normal shell. I also
strongly encourage applying this patch for 3.82 which fixes a nasty
memory leak/corruption:
http://savannah.gnu.org/bugs/download.php?file_id=23275
If I have time and interest, I will look into implementing the wrapper
functionality into make itself. Don't hold your breath, though.
--
Atte Peltomäki
atte.peltom...@iki.fi http://kameli.org
Your effort to remain what you are is what limits you
/*
* Shell wrapper for GNU Make
*
* Takes a bash command line as arguments, passes it to shell,
* reads output into a buffer and when shell finishes, outputs
* buffer contents to corresponding stdout/stderr streams.
*
* Use by setting SHELL := mwrap
*
* If MWRAP_DEBUG environment variable is set, echo all executed
* commands to stderr.
*
*/
#include sys/types.h
#include sys/file.h
#include sys/wait.h
#include sys/select.h
#include stdlib.h
#include stdio.h
#include unistd.h
#include string.h
const char *SHELL = /bin/bash;
const char *LOCK = .mwrap.lock;
#define BUFSIZE 65536
/* This is where output is temporarily stored. One struct per line
* with corresponding output file descriptor number. */
struct linebuf {
int fd;
char *buffer;
};
/* Populate shell argument array pointer */
char** setargv(int argc, char *argv[])
{
int i;
char **shargv = calloc(1, (argc + 1) * sizeof(char *));
shargv[0] = (char *) SHELL;
for(i = 1; i argc; i++)
shargv[i] = argv[i];
return shargv;
}
int main(int argc, char *argv[])
{
pid_t child;
int outfd[2], errfd[2], lockfd = -1;
int status, retval, line = 0, buflen = 128, i = 0;
char buffer[BUFSIZE];
ssize_t bytesread;
struct linebuf *outbuf = calloc(1, buflen * sizeof(struct linebuf));
fd_set rset;
char **shargv = setargv(argc, argv);
pipe(outfd);
pipe(errfd);
/* Redirect stdout/stderr and execute */
child = fork();
if(child == (pid_t) 0) {
close(1); close(2);
close(outfd[0]); close(errfd[0]);
dup2(outfd[1], 1); dup2(errfd[1], 2);
execvp(SHELL, shargv);
return 1; /* should never happen */
} else if(child == (pid_t) -1)
return 2; /* fork() failed */
close(outfd[1]);
close(errfd[1]);
/*
* Run select() on child stdout and stederr file descriptors
*/
read:
retval = 0;
FD_ZERO(rset);
FD_SET(outfd[0], rset);
FD_SET(errfd[0], rset);
retval = select(20, rset, NULL, NULL, NULL);
/* Data ready in stdout */
if(retval FD_ISSET(outfd[0], rset)) {
if((bytesread = read(outfd[0], buffer, sizeof(buffer))) 0) {
if(line = buflen) {
buflen += buflen;
outbuf = realloc(outbuf, sizeof(struct linebuf) * (buflen + line + 1));
}
outbuf[line].fd = 1;
outbuf[line].buffer = calloc(1, bytesread+1);
strncpy(outbuf[line].buffer, buffer, bytesread);
line++;
}
}
if(retval FD_ISSET(errfd[0], rset)) {
if((bytesread = read(errfd[0], buffer, sizeof(buffer))) 0) {
if(line = buflen) {
buflen += buflen;
outbuf = realloc(outbuf, sizeof(struct linebuf) * (buflen + line + 1));
}
outbuf[line].fd = 2;
outbuf[line].buffer = calloc(1, bytesread+1);
strncpy(outbuf[line].buffer, buffer, bytesread);
line++;
}
}
/* If child hasn't exited yet, select() again */
while(waitpid(child, status, WNOHANG) == 0) {
i = 0;
goto read;
}
/* Check once more for any data, just in case */
if(i == 0) { i = 1; goto read; }
/* Grab a lock */
lockfd = open(LOCK, O_WRONLY|O_CREAT, 0600);
flock(lockfd, LOCK_EX);
/* Print the original command line if MWRAP_DEBUG env var is set */
if(getenv(MWRAP_DEBUG) != NULL) {
for(i = 2; i argc; i++)
fprintf(stderr, %s , argv[i]);
fprintf(stderr, \n);
}
/* Print out the buffered lines */
for(i = 0; i line; i++) {
write(outbuf[i].fd, outbuf[i].buffer, strlen(outbuf[i].buffer));
free(outbuf[i].buffer);
}
free(outbuf);
free(shargv);
unlink(LOCK);
flock(lockfd, LOCK_UN);
close(lockfd);
if(WIFEXITED(status))
return WEXITSTATUS(status);
else
return 127;
}
--- a/make-3.82/job.c 2011-11-07 10:57:05.108693420 +0200
+++ b/make-3.82/job.c 2011-11-07