views:

303

answers:

5

Some compilers let you set warnings as errors, so that you'll never leave any compiler warnings behind, because if you do, the code won't build. This is a Good Thing.

Unfortunately, some compilers don't have a flag for warnings-as-errors.

I need to write a shell script or wrapper that provides the feature.

Presumably it parses the compilation console output and returns failure if there were any compiler warnings (or errors), and success otherwise. "Failure" also means (I think) that object code should not be produced.

What's the shortest, simplest UNIX/Linux shell script you can write that meets the explicit requirements above, as well as the following implicit requirements of otherwise behaving just like the compiler: - accepts all flags, options, arguments - supports redirection of stdout and stderr - produces object code and links as directed

Key words: elegant, meets all requirements.

Extra credit: easy to incorporate into a GNU make file.

Thanks for your help.

=== Clues === This solution to a different problem, using shell functions (?), Append text to stderr redirects in bash, might figure in. Wonder how to invite litb's friend "who knows bash quite well" to address my question?

=== Answer status ===

Thanks to Charlie Martin for the short answer, but that, unfortunately, is what I started out with. A while back I used that, released it for office use, and, within a few hours, had its most severe drawback pointed out to me: it will PASS a compilation with no warnings, but only errors. That's really bad because then we're delivering object code that the compiler is sure won't work. The simple solution also doesn't meet the other requirements listed.

Thanks to Adam Rosenfield for the shorthand, and Chris Dodd for introducing pipefail to the solution. Chris' answer looks closest, because I think the pipefail should ensure that if compilation actually fails on error, that we'll get failure as we should. Chris, does pipefail work in all shells? And have any ideas on the rest of the implicit requirements listed above?

A: 

Hmmm.

$ (compile-command 2>&1 | grep 'Warning') && exit 1

This isn't a very helpful one but you specififed "shortest". Of course the 'Warning' string would have to be modified to match the compiler.

A better version would be to pipe the output through grep, look for warnings, and set a flag, then afterwards if the flag is set print a message about warnings found and exit with return code set to something other than 0.

Charlie Martin
A: 

This should do the trick:

$ if compile-command |& tee /dev/tty | grep -q 'Warning'; then false; else true; fi

The |& construct is shorthand for 2>&1 | (that is, it redirects both stdout and stderr into the pipeline). Putting tee /dev/tty in the pipeline ensures that you'll still see the compiler's output on the console, and piping it to grep -q 'Warning' will make the exit status 1 if no warnings were found, or 0 if any warnings were found. Finally, wrapping that in an if ...; then false; else true; fi inverts the exit status, so the exit status is 0 if no warnings were found (success), or 1 if any warnings were found (failure).

Adam Rosenfield
A: 

As long as you're using bash, something like:

set -o pipefail; compile-command 2>&1 | if grep -q -i warning; then exit 1; fi

should do the trick

Chris Dodd
A: 

How about replacing the make command with a "make" function that swaps the stdout and stderr streams:

# cf. http://codesnippets.joyent.com/posts/show/8769
unset -f make
function make() { 
   command make "${@}" 3>&2 2>&1 1>&3 3>&- | tee /dev/stderr | \
        grep -E -i --line-buffered 'error|warning' | \
        head -n 1 > stderr_make.log && { echo; return 1; }
   return 0 
}
bashfu
A: 

Here's yet another version of a "make" function (for Bash) that can log stdout as well:

# cf. http://wiki.bash-hackers.org/howto/redirection_tutorial
unset -f make
function make() {    # logs stdout & stderr
  { 
     { 
        command make "${@}" 3>&- | 
           tee stdout_make.log 2>&3 3>&- 
     } 2>&1 >&4 4>&- | 
        grep -E -i --line-buffered 'error|warning' 2>&3 3>&- | 
           head -n 1 > stderr_make.log && 
              { echo; cat stderr_make.log; echo; return 1; }
  } 3>&2 4>&1 

  return 0 
}
bashfu