blob: 57e4110efac6bd685cd1b3d696a873f4cb11947a [file] [log] [blame]
#!/usr/bin/env python
import argparse
import subprocess
import sys
import os
import re
import shutil
from collections import OrderedDict
DEFAULT_TARGETS_TO_BUILD=["all"]
DEFAULT_GNU_COMPILER_VERSIONS=["4.9", "5", "6", "7"]
DEFAULT_CLANG_COMPILER_VERSIONS=["3.6", "3.8"]
DEFAULT_EASYGL_CONFIGS = ["OFF", "ON"]
DEFAULT_TATUM_PARALLEL_CONFIGS = ["ON", "OFF"]
DEFAULT_VTR_ASSERT_LEVELS= ["2", "3"]#, "1", "0"]
ERROR_WARNING_REGEXES = [
re.compile(r".*warning:.*"),
re.compile(r".*error:.*"),
]
SUPPRESSION_ERROR_WARNING_REGEXES = [
#We compile some .c files as C++, so we don't worry about these warnings from clang
re.compile(r".*clang:.*warning:.*treating.*c.*as.*c\+\+.*"),
]
def parse_args():
parser = argparse.ArgumentParser(description="Test building VTR for multiple different build configurations and compilers")
parser.add_argument("targets",
nargs="*",
default=DEFAULT_TARGETS_TO_BUILD,
help="What targets to build (default: %(default)s)")
parser.add_argument("--gnu_versions",
nargs="*",
default=DEFAULT_GNU_COMPILER_VERSIONS,
metavar="GNU_VERSION",
help="What versions of gcc/g++ to test (default: %(default)s)")
parser.add_argument("--clang_versions",
nargs="*",
metavar="CLANG_VERSION",
default=DEFAULT_CLANG_COMPILER_VERSIONS,
help="What versions of clang/clang++ to test (default: %(default)s)")
parser.add_argument("--easygl_configs",
nargs="*",
default=DEFAULT_EASYGL_CONFIGS,
metavar="EASYGL_CONFIG",
help="What EaysGL configurations to test (default: %(default)s)")
parser.add_argument("--tatum_parallel_configs",
nargs="*",
default=DEFAULT_TATUM_PARALLEL_CONFIGS,
metavar="TATUM_PARALLEL_CONFIG",
help="What parallel tatum configurations to test (default: %(default)s)")
parser.add_argument("--vtr_assert_levels",
nargs="*",
default=DEFAULT_VTR_ASSERT_LEVELS,
metavar="VTR_ASSERT_LEVEL",
help="What VTR assert levels to test (default: %(default)s)")
parser.add_argument("-j",
type=int,
default=1,
help="How many parallel build jobs to allow (passed to make)")
parser.add_argument("--exit_on_failure",
action="store_true",
default=False,
help="Exit on first failure intead of continuing")
return parser.parse_args()
def main():
args = parse_args();
compilers_to_test = []
for gnu_version in args.gnu_versions:
cc = "gcc-" + gnu_version
cxx = "g++-" + gnu_version
compilers_to_test.append((cc, cxx))
for clang_version in args.clang_versions:
cc = "clang-" + clang_version
cxx = "clang++-" + clang_version
compilers_to_test.append((cc, cxx))
#Test all the compilers with the default build config
num_failed = 0
num_configs = 0
for vtr_assert_level in args.vtr_assert_levels:
for easygl_config in args.easygl_configs:
for tatum_parallel_config in args.tatum_parallel_configs:
for cc, cxx in compilers_to_test:
num_configs += 1
config = OrderedDict()
config["EASYGL_ENABLE_GRAPHICS"] = easygl_config
config["TATUM_ENABLE_PARALLEL_ANALYSIS"] = tatum_parallel_config
config["VTR_ASSERT_LEVEL"] = vtr_assert_level
success = build_config(args, cc, cxx, config)
if not success:
num_failed += 1
if args.exit_on_failure:
sys.exit(num_failed)
if num_failed != 0:
print "Failed to build {} of {} configurations".format(num_failed, num_configs)
sys.exit(num_failed)
def build_config(args, cc, cxx, config):
if not compiler_is_found(cc):
print "Failed to find C compiler {}, skipping".format(cc)
return False
if not compiler_is_found(cxx):
print "Failed to find C++ compiler {}, skipping".format(cxx)
return False
config_strs = []
for key, value in config.iteritems():
config_strs += ["{}={}".format(key, value)]
log_file = "build_{}_{}_{}.log".format(cc, cxx, '__'.join(config_strs))
build_successful = True
with open(log_file, 'w') as f:
print "Building with CC={} CXX={}:".format(cc, cxx)
print >>f, "Building with CC={} CXX={}:".format(cc, cxx)
f.flush()
build_dir = "build"
shutil.rmtree(build_dir, ignore_errors=True)
os.mkdir(build_dir)
#Copy the os environment
new_env = {}
new_env.update(os.environ)
#Override CC and CXX
new_env['CC'] = cc
new_env['CXX'] = cxx
#Run CMAKE
cmake_cmd = ["cmake"]
for key, value in config.iteritems():
cmake_cmd += ["-D{}={}".format(key, value)]
cmake_cmd += [".."]
print " " + ' '.join(cmake_cmd)
print >>f, " " + ' '.join(cmake_cmd)
f.flush()
subprocess.check_call(cmake_cmd, cwd=build_dir, stdout=f, stderr=f, env=new_env)
#Run Make
build_cmd = ["make"]
build_cmd += ["-j", "{}".format(args.j)]
build_cmd += args.targets
print " " + ' '.join(build_cmd)
print >>f, " " + ' '.join(build_cmd)
f.flush()
try:
subprocess.check_call(build_cmd, cwd=build_dir, stdout=f, stderr=f, env=new_env)
except subprocess.CalledProcessError as e:
build_successful = False
#Look for errors and warnings in the build log
issue_count = 0
with open(log_file) as f:
for line in f:
if is_valid_warning_error(line):
print " " + line,
issue_count += 1
if not build_successful:
print " ERROR: failed to compile"
else:
print " OK",
if issue_count > 0:
print " ({} warnings)".format(issue_count),
print
return build_successful
def is_valid_warning_error(line):
for issue_regex in ERROR_WARNING_REGEXES:
if issue_regex.match(line):
for suppression_regex in SUPPRESSION_ERROR_WARNING_REGEXES:
if suppression_regex.match(line):
return False #Suppressed
return True #Valid error/warning
return False #Not a problem
def compiler_is_found(execname):
try:
result = subprocess.check_output([execname, "--version"], stderr=subprocess.PIPE) == 0
except OSError as e:
return False
return True
if __name__ == "__main__":
main()