Using shell wrapper for descrambling parallel make output

2011-11-11 Thread Atte Peltomäki
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 

Re: [bug #33034] Makefile:23: *** mixed implicit and normal rules. Stop. for Linux kernel out of source builds

2011-11-11 Thread Paul Smith
On Thu, 2011-11-10 at 14:51 -0500, tz wrote:
 On Nov 10, 2011 2:32 PM, Paul Smith psm...@gnu.org wrote:
  On Thu, 2011-11-10 at 10:36 -0500, tz wrote:
 
  You don't need to cross-compile: you can compile natively.  What you
  can't do is rely on your upstream vendor to provide you the toolchain
  you are going to use.  You need to build it yourself, using known
  versions, and install the results in a separate location (not your
  distro's /usr/bin).
 
 That doesn't work if you don't have space on the embedded device.
 Some don't have resources to network mount, and builds take days
 (literally).

??? So OK, you ARE using a cross-compiler.  I thought you said earlier
that you didn't want to.  Anyway it doesn't matter whether you're
building natively or cross; what matters is that you use an archived,
known version of your toolchain to build your target code and not
whatever version of the toolchain is delivered with your desktop du
jour.


___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make


Re: [rfc] Colorized output for GNU make?

2011-11-11 Thread Sebastian Pipping
Hello,


the copyright assignment form reached the FSF more than a week ago.

Would be great to get some more review on my patch now.
I don't mind if on-list, off-list, half-half...

Paul?

Thanks,




Sebastian

___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make


[bug #34806] target-specific variable with conditional assignment generates garbage

2011-11-11 Thread anonymous
URL:
  http://savannah.gnu.org/bugs/?34806

 Summary: target-specific variable with conditional assignment
generates garbage
 Project: make
Submitted by: None
Submitted on: Sat 12 Nov 2011 12:06:18 AM UTC
Severity: 3 - Normal
  Item Group: Bug
  Status: None
 Privacy: Public
 Assigned to: None
 Open/Closed: Open
 Discussion Lock: Any
   Component Version: 3.81
Operating System: POSIX-Based
   Fixed Release: None
   Triage Status: None

___

Details:

Target-specific variable conditional assignment is broken.

The following Makefile:

DEFAULT=1234  
  
   
  
  
   
all:VAR ?= $(DEFAULT) 
  
   
all:  
  
   
@echo VAR=$(VAR)

prints '1234' when invoked as 'make' but when invoked as 'make VAR=5678' will
print garbage characters.




___

Reply to this item at:

  http://savannah.gnu.org/bugs/?34806

___
  Message sent via/by Savannah
  http://savannah.gnu.org/


___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make