#! /usr/bin/env perl
# -*- Mode: perl; -*-
#
# Set Defaults
$debug = 0;
$debugDir = 0;
$gDebugOther = 0;
$summaryOutput = 0;
$terseOutput = 1;
$rootSrcDir = "";
# Define the known commands, along with known make noise (results of
# echo)
# We include /bin/rm and /bin/mv because some Makefile authors prefer
# to get the full path for these routines
@commands = ( "cc", "pgcc", "gcc", "icc", "acc",
"rm", "mv", "cp", "ar", "ranlib", "perl", "for",
"/bin/rm", "/bin/mv", "/bin/cp", "/bin/chmod",
"rm", "mv", "cp", "chmod",
"if", "make", "gnumake",
"[A-Za-z0-9_\/\.-]*\/mpicc",
"[A-Za-z0-9_\/\.-]*\/mpifort",
"[A-Za-z0-9_\/\.-]*\/mpicxx",
"cleaning", "sleep", "date", "g77", "f77", "f90", "f95", "pgCC",
"pgf77", "pgf90", "CC", "g95", "g\\+\\+", "c\\+\\+",
"acc\\+\\+", "xlc", "xlf", "xlC", "xlf90", "gfortran",
"ifort", "ifc", "test",
"true", "false", "/[A-Za-z0-9_\/\.-]*createshlib",
"/bin/sh\\s+[A-Za-z0-9_\/\.-]*libtool\\s+\(--tag=\\w+\)*\\s+--mode=\\w+",
"/bin/bash\\s+[A-Za-z0-9_\/\.-]*libtool\\s+--mode=\\w+",
"/bin/sh\\s+[A-Za-z0-9_\/\.-]*libtool\\s+--finish",
"/bin/bash\\s+[A-Za-z0-9_\/\.-]*libtool\\s+--finish",
"libtool:\\s+compile:",
"libtool:\\s+link:",
"libtool:\\s+install:",
"libtool:\\s+finish:",
"[A-Za-z0-9_\/-]*\/icc",
"[A-Za-z0-9_\/-]*\/install-sh",
"/usr/bin/ar", "mkdir",
"/bin/mkdir",
"/.*bin/mkdir",
"/usr/ucb/ld",
"mpicc", "mpicxx",
"compiling ROMIO in",
"Make completed",
"echo", "cat",
"CC", "CCLD", "AR", "RANLIB", "LIBTOOL", "MV",
"MOD", "GEN", "F77", "FC", "CXXLD", "CXX", "FCLD",
"CP", # "terse" make versions
"\\(?cd",
"\\(\\s*cd",
"creating\s+lib.*",
"cd\\s+\&\&\\s+make",
"sed -e",
"PATH=\"\\\$PATH.*\\sldconfig\\s",
"building profiling interface in directory",
"/usr/bin/install",
"/.*bin/install",
".*confdb/install-sh",
"Copying Upshot",
"Cleaning directory",
"[*][*][*][*] Making .*\.\.\.\.",
"Making .* in .*",
"Making upshot", "\\s*\$",
"ld: warning: directory not found for option '-L\\S*src/mpl'",
"ld: warning: directory not found for option '-L\\S*src/openpa/src'",
);
# OtherNoise is an array of patterns that describe blocks of
# text that we'd like to skip. The initial use it to handle
# libtool install output.
# The PG entries are work-arounds for bugs in the PG header files that have
# small incompatibilities with the system header file /usr/include/unistd.h
#
@OtherNoise = ( 'Libraries have been installed in:<SEP>more information, such as the ld\(1\) and ld.so\(8\) manual pages.<SEP>20',
'^\s*-+\s*$<SEP><SEP>1',
'^In directory:<SEP><SEP>1',
'^creating\s<SEP><SEP>1',
# '^PGC-W-0114-More than one type.*/usr/include/unistd.h: 189<SEP>^PGC-W-0143-Useless typedef.*/usr/include/unistd.h: 189<SEP>2',
# '^PGC-W-0114-More than one type.*/usr/include/unistd.h: 243<SEP>^PGC-W-0143-Useless typedef.*/usr/include/unistd.h: 243<SEP>2',
'^PGC.*: compilation completed with warnings<SEP><SEP>1',
# This next is a general version to handle all of these mistakes
'^PGC-W-0114-More than one type specified.*/usr/include<SEP>^PGC-W-0143-Useless typedef declaration \(no declarators present\).*/usr/include<SEP>2',
'copying python',
'LOOP WAS VECTORIZED',
'Using variables ',
);
# In the past, we also needed
# WARNING 84.*not used for resolving any symbol
# Info: File not optimized
$trimCompileLine = 1;
# Create the variables that keep track of state
# dirstack keeps the directory name that gnumake and similar make
# implementations echo as a directory is entered or exited (this can generate
# a great deal of output noise that can obscure important data. However, when
# a problem *does* occur, this directory information is valuable.
# dirprinted is a parallel array that indicates whether the corresponding
# directory entry has been printed.
@dirstack = ();
@dirprinted = ();
# Process arguments to select options
foreach $_ (@ARGV) {
if (/^--?debug/) { $debug = 1; }
elsif (/^--?showdir/) { $debugDir = 1; }
elsif (/^--?summary/) { $summaryOutput = 1; }
elsif (/^--?notrimcompileline/) { $trimCompileLine = 0; }
elsif (/^-/) {
print STDERR "Unrecognized argument $_\n";
print STDERR "clmake [ -debug ] [ -showdir ] [ -summary ]\n";
exit(1);
}
else { last; }
shift @ARGV;
}
# Read lines. Categorize lines as commands and output. This
# script suppresses commands that generate no extra output.
# The approach is to read a line and then read the next line.
# While the line is a command and the next line is not, output the
# line.
#
# We use eof() (see man perlfun) so that we can accept filenames on the
# commandline.
#
$cmdline = "";
T:
while ($line = <>) {
if (eof()) { next; }
$line =~ s/\r//; # remove returns from line (de DOSify)
# Read the next line, including handling any continuation lines
while ($line =~ /\\$/) {
print "Read continuation line (cmd) ... \n" if $debug;
$line .= <>;
}
# Check for noise
foreach my $pat (@OtherNoise) {
# maxlines is the maximum number of lines to match
my ($beginpat,$endpat,$maxlines) = split( '<SEP>', $pat );
print "Trying to match $beginpat\n" if $gDebugOther;
if ($line =~ /$beginpat/) {
$maxlines --;
print "Found match to $beginpat\n" if $gDebugOther;
# Found the beginning. Look for the end (if one requested)
if ($endpat =~ /\S/) {
print "Trying to match endpat $endpat\n" if $gDebugOther;
while ($line = <>) {
if (eof()) { last; }
print "Trying to match to $line" if $gDebugOther;
if ($line =~ /$endpat/) { last; }
if ($maxlines-- <= 0) {
print STDOUT "Failed to match $endpat; last line was $line";
last;
}
}
}
next T;
}
}
# Is the line a command (including a directory change?)
# Check first for a directory change
if ($line =~ /^\s*make.* Entering directory \`([^\']*)\'/) {
my $dirname = $1;
$dirstack[$#dirstack+1] = $dirname;
$dirprinted[$#dirprinted+1] = 0;
print ">>entering $dirname\n" if $debugDir;
$cmdline = "";
next;
}
elsif ($line =~ /^\s*make.* Leaving directory \`([^\']*)\'/) {
# We should check that the directory names match
my $dirname = $1;
print ">>leaving $dirname\n" if $debugDir;
if ($dirname ne $dirstack[$#dirstack]) {
print STDERR "Warning: leaving directory $dirname but expected to leave directory " . $dirstack[$#dirstack] . "\n";
}
$#dirstack--;
$#dirprinted--;
$cmdline = "";
next;
}
else {
$is_command = 0;
foreach $cmdname (@commands) {
if ($line =~ /^\s*$cmdname\W/) {
$is_command = 1;
$cmdline = $line;
last;
}
}
if ($is_command) {
if ($summaryOutput) {
# FIXME: Summarize the command
if ($terseOutput) {
if ($rootSrcDir eq "") {
if ($line =~ /\s(\/\S+\/src\/)/) {
$rootSrcDir = $1;
print "rootSrcDir = $rootSrcDir\n";
}
}
else {
$line =~ s/$rootSrcDir//g;
}
# Compiler options to remove
$line =~ s/-I\S+\s+//g;
$line =~ s/-W\S+\s+//g;
$line =~ s/-D\S+\s+//g;
}
print $line;
}
next;
}
}
# If we got to this point, the line was not a recognized command or
# ignorable output. Output the line, including the command if this
# is the first time. We can then forget the command
if ($#dirstack >= 0 && $dirprinted[$#dirstack] == 0) {
print "In directory: ". $dirstack[$#dirstack] . "\n";
$dirprinted[$#dirstack] = 1;
}
if ($cmdline ne "") {
if ($trimCompileLine) {
# Simplify the command line before printing
$cmdline =~ s/-I\S*\s+//g;
$cmdline =~ s/-ansi//g;
$cmdline =~ s/-W\S*\s+//g;
$cmdline =~ s/-DHAVE_CONFIG_H//g;
$cmdline =~ s/-DGCC_WALL//g;
}
# We could print a newline here to separate commands
print $cmdline;
$cmdline = "";
}
print $line;
}
#
# ToDo:
# Handle lines containing just ----, e.g., patterns of the form
# -*