What you suggest is a workaround, but I can still try it. Could you please write here that filter you talk about?
OK; I'd create a shell script to do the hard work. There are two ways to handle it. One is to call the script gcc-filter
and then instead of running:
gcc -g -O3 -Wall -Wextra -Werror -I/where/ever -c source.c
you would run:
gcc-filter gcc -g -O3 -Wall -Wextra -Werror -I/where/ever -c source.c
Using make, you can achieve that by specifying CC="gcc-filter gcc"
or equivalent.
The alternative is to run the script after redirecting output:
gcc -g -O3 -Wall -Wextra -Werror -I/where/ever -c source.c 2>&1 | gcc-filter
I'm going to assume the first technique.
gcc-filter.sh
"$@" 2>&1 |
sed '/^In file /,/^ *^/d' >&2
The first line runs gcc
(or whatever command is specified by the arguments; it doesn't have to be gcc
) with the arguments as specified on the command line. It redirects both standard output and standard error to a pipe (I'll come back to this), which goes to sed
.
The sed
line looks for the pattern In file
at the start of a line, and deletes from there up to the first line that starts with a caret after optional spaces. The redirection sends the information that it passes through to standard error.
There are two prime defects with the script as it stands:
- It assumes that standard output and standard error can be merged (or, more succinctly, that
gcc
doesn't write much to standard output).
- It works off one pattern of error reporting. If there are other sequences that should be filtered, you will need to add to the
sed
script.
You can deal with the standard output vs standard error issue, but it is mildly mind blowing (maybe 'mind puffing').
(
"$@" 2>&1 1>&3 |
sed '/^In file /,/^ *^/d' >&2
) 3>&1
The sub-shell ( ... ) 3>&1
sends data written to file descriptor 3 so it goes to standard output.
Inside the sub-shell 2>&1 1>&3 |
arranges for:
- Standard output to go to the pipe.
- Standard error to go where standard output is going (the pipe).
- Standard output to go to file descriptor 3 (without changing where standard error is going, the pipe).
The sed
command therefore gets the standard error output from gcc
as its standard input, filters it, and the >&2
sends its standard output to standard error.
The net result is that standard error is filtered while standard output is not. However, be aware that you can end up with different interleaving of output from the two streams as a result of the buffering going on.
One other problem: exit status. The exit status of the script as written is the exit status of the sed
command, which will be 0 under most circumstances. If we need to relay the exit status from gcc
, we have to work with the Bash set -o pipefail
, I think. Or you can poke at the PIPESTATUS
array; exit ${PIPESTATUS[0]}
should exit with the same exit status that gcc
exited with.
Demonstrating the code working on Linux
The system is running an Ubuntu 14.04 LTS derivative with GCC 4.9.2.
Test code b.c
(I'd used up x.c
, y.c
, z.c
, and a.c
on other programs.)
#include <stdio.h>
int main(void)
{
char array[512];
char *buffer = array;
sprintf(&buffer, "file.txt");
printf("%s\n", buffer);
return 0;
}
Compilation without gcc-filter.sh
:
$ make b.o WFLAG3= WFLAG4= WFLAG5= WFLAG6= IFLAGS= LDFLAGS= LDLIBS= cc -g -O3 -std=c11 -Wall -Wextra -Werror -c -o b.o b.c
b.c: In function ‘main’:
b.c:8:3: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
sprintf(&buffer, "file.txt");
^
In file included from /usr/include/features.h:374:0,
from /usr/include/stdio.h:27,
from b.c:1:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:31:1: note: expected ‘char * restrict’ but argument is of type ‘char **’
__NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
^
cc1: all warnings being treated as errors
<builtin>: recipe for target 'b.o' failed
make: *** [b.o] Error 1
$
Compilation with gcc-filter.sh
$ make b.o CC="./gcc-filter.sh gcc"
./gcc-filter.sh gcc -g -O3 -std=c11 -Wall -Wextra -Werror -c -o b.o b.c
b.c: In function ‘main’:
b.c:8:11: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
sprintf(&buffer, "file.txt");
^
cc1: all warnings being treated as errors
<builtin>: recipe for target 'b.o' failed
make: *** [b.o] Error 1
$
gcc-filter.sh
#!/bin/bash
set -o pipefail
(
"$@" 2>&1 1>&3 |
sed '/^In file /,/^ *^/d' >&2
) 3>&1
exit ${PIPESTATUS[0]}
And another test
I also created c.c
which contained three sprintf()
lines and three printf()
lines, and the filtered output was:
$ ./gcc-filter.sh gcc -g -O3 -std=c11 -Wall -Wextra -Werror -c c.c
c.c: In function ‘main’:
c.c:8:11: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
sprintf(&buffer, "file1.txt");
^
c.c:10:11: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
sprintf(&buffer, "file2.txt");
^
c.c:12:11: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
sprintf(&buffer, "file3.txt");
^
cc1: all warnings being treated as errors
$
So multiple errors are handled properly (but in times past, more than one similar script has appeared to work on a single instance of an error message but when tested on multiple error messages, it was too enthusiastic about discarding output).