2010-02-12 00:03:44 +00:00
#!/usr/bin/env perl
2008-02-09 01:55:31 +00:00
2009-01-24 13:31:09 +00:00
# +------------------------------------+
# | Inspire Internet Relay Chat Daemon |
# +------------------------------------+
#
2010-01-11 03:07:32 +00:00
# InspIRCd: (C) 2002-2010 InspIRCd Development Team
2009-03-15 12:42:35 +00:00
# See: http://wiki.inspircd.org/Credits
2009-01-24 13:31:09 +00:00
#
# This program is free but copyrighted software; see
# the file COPYING for details.
#
# ---------------------------------------------------
2008-02-09 01:55:31 +00:00
### THIS IS DESIGNED TO BE RUN BY MAKE! DO NOT RUN FROM THE SHELL (because it MIGHT sigterm the shell)! ###
use strict ;
use warnings FATAL = > qw( all ) ;
use POSIX ( ) ;
# Runs the compiler, passing it the given arguments.
# Filters select output from the compiler's standard error channel and
# can take different actions as a result.
# NOTE: this is *NOT* a hash (sadly: a hash would stringize all the regexes and thus render them useless, plus you can't index a hash based on regexes anyway)
# even though we use the => in it.
# The subs are passed the message, and anything the regex captured.
2008-02-10 17:22:36 +00:00
my $ cc = shift ( @ ARGV ) ;
2008-02-11 01:39:09 +00:00
my $ showncmdline = 0 ;
# GCC's "location of error stuff", which accumulates the "In file included from" include stack
my $ location = "" ;
2008-02-09 01:55:31 +00:00
my @ msgfilters = (
[ qr/^(.*) warning: cannot pass objects of non-POD type `(.*)' through `\.\.\.'; call will abort at runtime/ = > sub {
my ( $ msg , $ where , $ type ) = @ _ ;
2008-04-13 19:28:46 +00:00
my $ errstr = $ location . "$where error: cannot pass objects of non-POD type `$type' through `...'\n" ;
2008-02-15 13:30:46 +00:00
$ location = "" ;
if ( $ type =~ m/::(basic_)?string/ ) {
2008-02-09 01:55:31 +00:00
$ errstr . = "$where (Did you forget to call c_str()?)\n" ;
}
die $ errstr ;
} ] ,
2008-02-09 20:44:25 +00:00
2008-02-11 01:39:09 +00:00
# Start of an include stack.
[ qr/^In file included from .*[,:]$/ = > sub {
my ( $ msg ) = @ _ ;
$ location = "$msg\n" ;
2008-04-13 18:26:18 +00:00
return undef ;
2008-02-11 01:39:09 +00:00
} ] ,
# Continuation of an include stack.
[ qr/^ from .*[,:]$/ = > sub {
my ( $ msg ) = @ _ ;
$ location . = "$msg\n" ;
2008-04-13 18:26:18 +00:00
return undef ;
2008-02-11 01:39:09 +00:00
} ] ,
# A function, method, constructor, or destructor is the site of a problem
[ qr/In ((con|de)structor|(member )?function)/ = > sub {
my ( $ msg ) = @ _ ;
# If a complete location string is waiting then probably we dropped an error, so drop the location for a new one.
if ( $ location =~ m/In ((con|de)structor|(member )?function)/ ) {
$ location = "$msg\n" ;
} else {
$ location . = "$msg\n" ;
}
2008-04-13 18:26:18 +00:00
return undef ;
2008-02-11 01:39:09 +00:00
} ] ,
2008-02-09 20:44:25 +00:00
[ qr/^.* warning: / = > sub {
my ( $ msg ) = @ _ ;
2008-04-13 18:26:18 +00:00
my $ str = $ location . "\e[33;1m$msg\e[0m\n" ;
2008-04-22 12:26:05 +00:00
$ showncmdline = 1 ;
2008-02-11 01:39:09 +00:00
$ location = "" ;
2008-04-13 18:26:18 +00:00
return $ str ;
2008-02-09 20:44:25 +00:00
} ] ,
[ qr/^.* error: / = > sub {
my ( $ msg ) = @ _ ;
2008-04-13 18:26:18 +00:00
my $ str = "" ;
$ str = "An error occured when executing:\e[37;1m $cc " . join ( ' ' , @ ARGV ) . "\n" unless $ showncmdline ;
2008-02-11 01:39:09 +00:00
$ showncmdline = 1 ;
2008-04-13 18:26:18 +00:00
$ str . = $ location . "\e[31;1m$msg\e[0m\n" ;
$ location = "" ;
return $ str ;
} ] ,
[ qr/./ = > sub {
my ( $ msg ) = @ _ ;
$ msg = $ location . $ msg ;
2008-02-11 01:39:09 +00:00
$ location = "" ;
2008-04-13 18:26:18 +00:00
$ msg =~ s/std::basic_string\<char\, std\:\:char_traits\<char\>, std::allocator\<char\> \>(\s+|)/std::string/g ;
for my $ stl ( qw( deque vector list ) ) {
2008-04-13 19:28:46 +00:00
$ msg =~ s/std::$stl\<(\S+), std::allocator\<\1\> \>/std::$stl\<$1\>/g ;
$ msg =~ s/std::$stl\<(std::pair\<\S+, \S+\>), std::allocator\<\1 \> \>/std::$stl<$1 >/g ;
2008-04-13 18:26:18 +00:00
}
2008-04-13 19:28:46 +00:00
$ msg =~ s/std::map\<(\S+), (\S+), std::less\<\1\>, std::allocator\<std::pair\<const \1, \2\> \> \>/std::map<$1, $2>/g ;
# Warning: These filters are GNU C++ specific!
$ msg =~ s/__gnu_cxx::__normal_iterator\<(\S+)\*, std::vector\<\1\> \>/std::vector<$1>::iterator/g ;
$ msg =~ s/__gnu_cxx::__normal_iterator\<(std::pair\<\S+, \S+\>)\*, std::vector\<\1 \> \>/std::vector<$1 >::iterator/g ;
$ msg =~ s/__gnu_cxx::__normal_iterator\<char\*, std::string\>/std::string::iterator/g ;
2008-04-13 18:26:18 +00:00
return $ msg ;
2008-02-09 20:44:25 +00:00
} ] ,
2008-02-09 01:55:31 +00:00
) ;
my $ pid ;
my ( $ r_stderr , $ w_stderr ) ;
2008-02-10 17:22:36 +00:00
my $ name = "" ;
2008-02-10 21:57:42 +00:00
my $ action = "" ;
2008-02-10 17:22:36 +00:00
2008-02-24 20:30:17 +00:00
if ( $ cc eq "ar" ) {
$ name = $ ARGV [ 1 ] ;
$ action = "ARCHIVE" ;
} else {
foreach my $ n ( @ ARGV )
2008-02-10 17:22:36 +00:00
{
2008-02-24 20:30:17 +00:00
if ( $ n =~ /\.cpp$/ )
2008-02-24 14:07:25 +00:00
{
2009-09-16 20:00:15 +00:00
my $ f = $ n ;
if ( defined $ ENV { SOURCEPATH } ) {
$ f =~ s #^$ENV{SOURCEPATH}/src/##;
}
2008-02-24 20:30:17 +00:00
if ( $ action eq "BUILD" )
{
2009-09-16 20:00:15 +00:00
$ name . = " " . $ f ;
2008-02-24 20:30:17 +00:00
}
else
{
$ action = "BUILD" ;
2009-09-16 20:00:15 +00:00
$ name = $ f ;
2008-02-24 20:30:17 +00:00
}
2008-02-24 14:07:25 +00:00
}
2008-02-24 20:30:17 +00:00
elsif ( $ action eq "BUILD" ) # .cpp has priority.
2008-02-24 14:07:25 +00:00
{
2008-02-24 20:30:17 +00:00
next ;
}
elsif ( $ n eq "-o" )
{
$ action = $ name = $ n ;
}
elsif ( $ name eq "-o" )
{
$ action = "LINK" ;
2008-02-24 14:07:25 +00:00
$ name = $ n ;
}
}
2008-02-10 17:22:36 +00:00
}
2008-02-09 01:55:31 +00:00
if ( ! defined ( $ cc ) || $ cc eq "" ) {
die "Compiler not specified!\n" ;
}
pipe ( $ r_stderr , $ w_stderr ) or die "pipe stderr: $!\n" ;
$ pid = fork ;
2008-02-24 20:30:17 +00:00
die "Cannot fork to start $cc! $!\n" unless defined ( $ pid ) ;
2008-02-09 01:55:31 +00:00
if ( $ pid ) {
2008-02-10 17:22:36 +00:00
2008-02-24 20:30:17 +00:00
printf "\t\e[1;32m%-20s\e[0m%s\n" , $ action . ":" , $ name unless $ name eq "" ;
2008-02-10 17:22:36 +00:00
2008-02-09 01:55:31 +00:00
my $ fail = 0 ;
# Parent - Close child-side pipes.
close $ w_stderr ;
# Close STDIN to ensure no conflicts with child.
close STDIN ;
# Now read each line of stderr
LINE: while ( defined ( my $ line = <$r_stderr> ) ) {
chomp $ line ;
2008-03-17 17:02:47 +00:00
2008-02-09 01:55:31 +00:00
for my $ filter ( @ msgfilters ) {
my @ caps ;
if ( @ caps = ( $ line =~ $ filter - > [ 0 ] ) ) {
$@ = "" ;
2008-04-13 18:26:18 +00:00
$ line = eval {
2008-02-09 01:55:31 +00:00
$ filter - > [ 1 ] - > ( $ line , @ caps ) ;
} ;
if ( $@ ) {
2008-04-13 18:26:18 +00:00
# Note that $line is undef now.
2008-02-09 01:55:31 +00:00
$ fail = 1 ;
print STDERR $@ ;
}
2008-04-13 18:26:18 +00:00
next LINE unless defined ( $ line ) ;
2008-02-09 01:55:31 +00:00
}
}
2008-04-13 18:26:18 +00:00
# Chomp off newlines again, in case the filters put some back in.
chomp $ line ;
2008-02-09 01:55:31 +00:00
print STDERR "$line\n" ;
}
waitpid $ pid , 0 ;
close $ r_stderr ;
my $ exit = $? ;
# Simulate the same exit, so make gets the right termination info.
if ( POSIX:: WIFSIGNALED ( $ exit ) ) {
# Make won't get the right termination info (it gets ours, not the compiler's), so we must tell the user what really happened ourselves!
print STDERR "$cc killed by signal " . POSIX:: WTERMSIGN ( $ exit ) . "\n" ;
kill "TERM" , getppid ( ) ; # Needed for bsd make.
kill "TERM" , $$ ;
}
else {
if ( POSIX:: WEXITSTATUS ( $ exit ) == 0 ) {
if ( $ fail ) {
kill "TERM" , getppid ( ) ; # Needed for bsd make.
kill "TERM" , $$ ;
}
exit 0 ;
} else {
exit POSIX:: WEXITSTATUS ( $ exit ) ;
}
}
} else {
# Child - Close parent-side pipes.
close $ r_stderr ;
# Divert stderr
open STDERR , ">&" , $ w_stderr or die "Cannot divert STDERR: $!\n" ;
# Run the compiler!
exec { $ cc } $ cc , @ ARGV ;
die "exec $cc: $!\n" ;
}