[LWN Logo]
[LWN.net]
From:	 Rob Landley <landley@trommello.org>
To:	 linux-kernel@vger.kernel.org
Subject: [RFC] [PATCH] Intelligible build progress
Date:	 Thu, 10 Jan 2002 06:11:20 -0500

I got bored.  I wrote a toy.  It's an output filter you pipe a build into 
that actually explains what's going on.  It cuts the output down enough that 
you can actually see warnings (wow!), but not so much you don't know what 
it's doing or have some kind of progress indicator.

It's evil, it's nasty, it's ugly, it's vicious.  It currently requires python 
2.x (because I intend to put a curses front end on it, that's why).  But it 
also seems to be working, so I'm releasing what I've got so far under the GPL 
so people can flame me now and avoid the rush. :)

At the moment, you just copy "blueberry.py" onto your system (the "scripts" 
directory makes sense) and then use it like this (cut and paste and you've 
got a shell script):

### Start of script

# "Entering directory" messages are just clutter in make dep

make dep | scripts/blueberry.py e

# This is short enough we don't need to see progress

echo "Cleaning out old temporary files."
echo " "
make clean > /dev/null

# Okay, build.

make bzImage | scripts/blueberry.py
make modules | scripts/blueberry.py

# make install/modules install require root access, not handling this yet.

### End of script

As I said, later I want to make it part of a curses front-end showing you 
what directory you're currently in, what action is being taken, and with 
stderr (warnings, etc) scrolling by in its own little box.  Oh, and not 
having to run make dep and make clean all the time would be nice too, but 
that waits on Kieth Owens' new makefiles.

Yeah it's a big evil mess of heuristics.  I know.  And the above script will 
still try to build modules if bzImage bombs with an error.  And you've got to 
ctrl-c twice to kill it...

I've tested it (if you can use that word) against 2.4.17, I don't know if 
there's new stuff in 2.5 it can't deal with yet.  (Shouldn't be, but...)

Here's the file.

You may cringe now.
#!/usr/bin/python2

# Kernel build cleaner version 0.00000000001, or less.
# Copyright 2002 Rob Landley
# Released under the GNU General Public License version 2 or higher,
# (the GPL is available from www.gnu.org/copyleft/gpl.html)

import sys, string

noenter=0

def mangle(input, output):

  dir="."
  shutup=0
  leftovers=None

  # Repeat until spanked:

  while 1 {
    result=None
    line=input.readline()
    if not line: break
    if shutup {
      output.write(".\n")
      continue

    # Reassemble split lines

    if leftovers {
      line="%s %s" % (leftovers,line)
    words=line.split()
    if words[-1]=='\\' {
      leftovers=line
      continue
    else: leftovers=None

    # Stuff to just completely skip:

    #   make: When one make file calls another, it announces the fact.
    #   rm: Build explicitly deletes old .o file before calling linker (ld)

    if words[0] in ("make", "rm"): continue

    if words[0]=="gcc" {
      if words[-1].endswith(".c") {
        result="Compiling %s/%s" % (dir,words[-1])
      } else {
        for i in range(len(words)):
          if words[i].endswith(".S") {
            result="Preprocessing %s/%s" % (dir,words[i])
            break
    elif words[0]=="ld":
      for i in range(len(words)):
        if words[i]=="-o" {
          result="Linking %s/%s" % (dir,words[i+1])
          break
    elif words[0]=="as":
      result="Assembling %s/%s" % (dir,words[-1])
    elif words[0].startswith("make["):
      if words[2]=="directory" {
        if words[1]=="Entering" {
          dir=words[3][1:-1]
          if noenter: continue
          result="Entering %s" % dir
        else: continue  # Leaving directory is not interesting.
      if words[1]=="Nothing": continue # Pointless error message
    elif words[0].endswith("/mkdep"):
      result="Finding dependencies in %s" % dir
    elif words[0]=="nm":
      result="Extracting symbols to %s" % words[-1]
    elif words[0].startswith("tmppiggy="):
      result="Creating compressed kernel image"
      shutup=1
    elif words[0]=="ar":  # So linker dependencies don't have to change
      result="Creating empty object %s" % words[2]
    elif words[0]=="sh" or words[0]=='.' or words[0].find("/")!=-1:
      if words[0]=="sh" {
        while words[1].startswith("-"): words[1:2]=[]
        words[0:1]=[]
      if words[0].find("/")!=-1 {
        while words[0].startswith("./"): words[0]=words[0][2:]
        temp=["Running %s/%s" % (dir,words[0])]
      else: temp=["Running %s" % words[0]]
      temp.extend(words[1:])
      result=" ".join(temp)

    # That's all we understand.  Now do something with it.

    if not result {
      output.write("Unknown line: %s\n" % line)
    } else {
      output.write(result)
      if not shutup: output.write("\n")

endofline="\r"
if len(sys.argv)>1 {
  if sys.argv[1].find("n")!=-1: endofline="\n"
  if sys.argv[1].find("c")!=-1: showcount=1
  else: showcount=0
  if sys.argv[1].find("e")!=-1: noenter=1

mangle(sys.stdin, sys.stdout)
print