1*a54f160bSHarmen Stoppels#!/usr/bin/env python3 29ef81066SDaniel Dunbar##===- utils/llvmbuild - Build the LLVM project ----------------*-python-*-===## 39ef81066SDaniel Dunbar# 42946cd70SChandler Carruth# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 52946cd70SChandler Carruth# See https://llvm.org/LICENSE.txt for license information. 62946cd70SChandler Carruth# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 79ef81066SDaniel Dunbar# 89ef81066SDaniel Dunbar##===----------------------------------------------------------------------===## 99ef81066SDaniel Dunbar# 109ef81066SDaniel Dunbar# This script builds many different flavors of the LLVM ecosystem. It 11c26e5fb8SDavid Greene# will build LLVM, Clang and dragonegg as well as run tests on them. 12c26e5fb8SDavid Greene# This script is convenient to use to check builds and tests before 13c26e5fb8SDavid Greene# committing changes to the upstream repository 149ef81066SDaniel Dunbar# 159ef81066SDaniel Dunbar# A typical source setup uses three trees and looks like this: 169ef81066SDaniel Dunbar# 179ef81066SDaniel Dunbar# official 189ef81066SDaniel Dunbar# dragonegg 199ef81066SDaniel Dunbar# llvm 209ef81066SDaniel Dunbar# tools 219ef81066SDaniel Dunbar# clang 229ef81066SDaniel Dunbar# staging 239ef81066SDaniel Dunbar# dragonegg 249ef81066SDaniel Dunbar# llvm 259ef81066SDaniel Dunbar# tools 269ef81066SDaniel Dunbar# clang 279ef81066SDaniel Dunbar# commit 289ef81066SDaniel Dunbar# dragonegg 299ef81066SDaniel Dunbar# llvm 309ef81066SDaniel Dunbar# tools 319ef81066SDaniel Dunbar# clang 329ef81066SDaniel Dunbar# 339ef81066SDaniel Dunbar# In a typical workflow, the "official" tree always contains unchanged 349ef81066SDaniel Dunbar# sources from the main LLVM project repositories. The "staging" tree 359ef81066SDaniel Dunbar# is where local work is done. A set of changes resides there waiting 369ef81066SDaniel Dunbar# to be moved upstream. The "commit" tree is where changes from 379ef81066SDaniel Dunbar# "staging" make their way upstream. Individual incremental changes 389ef81066SDaniel Dunbar# from "staging" are applied to "commit" and committed upstream after 399ef81066SDaniel Dunbar# a successful build and test run. A successful build is one in which 409ef81066SDaniel Dunbar# testing results in no more failures than seen in the testing of the 419ef81066SDaniel Dunbar# "official" tree. 429ef81066SDaniel Dunbar# 439ef81066SDaniel Dunbar# A build may be invoked as such: 449ef81066SDaniel Dunbar# 45c26e5fb8SDavid Greene# llvmbuild --src=~/llvm/commit --src=~/llvm/staging --src=~/llvm/official 469ef81066SDaniel Dunbar# --build=debug --build=release --build=paranoid 479ef81066SDaniel Dunbar# --prefix=/home/greened/install --builddir=/home/greened/build 489ef81066SDaniel Dunbar# 49c26e5fb8SDavid Greene# This will build the LLVM ecosystem, including LLVM, Clangand 50c26e5fb8SDavid Greene# dragonegg, putting build results in ~/build and installing tools in 51c26e5fb8SDavid Greene# ~/install. llvm-compilers-check creates separate build and install 52c26e5fb8SDavid Greene# directories for each source/build flavor. In the above example, 53c26e5fb8SDavid Greene# llvmbuild will build debug, release and paranoid (debug+checks) 54c26e5fb8SDavid Greene# flavors from each source tree (official, staging and commit) for a 55c26e5fb8SDavid Greene# total of nine builds. All builds will be run in parallel. 569ef81066SDaniel Dunbar# 579ef81066SDaniel Dunbar# The user may control parallelism via the --jobs and --threads 58c100d7baSDavid Green# switches. --jobs tells llvm-compilers-check the maximum total 59c26e5fb8SDavid Greene# number of builds to activate in parallel. The user may think of it 60c26e5fb8SDavid Greene# as equivalent to the GNU make -j switch. --threads tells 61c26e5fb8SDavid Greene# llvm-compilers-check how many worker threads to use to accomplish 62c26e5fb8SDavid Greene# those builds. If --threads is less than --jobs, --threads workers 63c26e5fb8SDavid Greene# will be launched and each one will pick a source/flavor combination 64c26e5fb8SDavid Greene# to build. Then llvm-compilers-check will invoke GNU make with -j 65c26e5fb8SDavid Greene# (--jobs / --threads) to use up the remaining job capacity. Once a 66c26e5fb8SDavid Greene# worker is finished with a build, it will pick another combination 67c26e5fb8SDavid Greene# off the list and start building it. 689ef81066SDaniel Dunbar# 699ef81066SDaniel Dunbar##===----------------------------------------------------------------------===## 709ef81066SDaniel Dunbar 719ef81066SDaniel Dunbarimport optparse 729ef81066SDaniel Dunbarimport os 739ef81066SDaniel Dunbarimport sys 749ef81066SDaniel Dunbarimport threading 759ef81066SDaniel Dunbarimport queue 769ef81066SDaniel Dunbarimport logging 779ef81066SDaniel Dunbarimport traceback 789ef81066SDaniel Dunbarimport subprocess 799ef81066SDaniel Dunbarimport re 809ef81066SDaniel Dunbar 819ef81066SDaniel Dunbar# TODO: Use shutil.which when it is available (3.2 or later) 829ef81066SDaniel Dunbardef find_executable(executable, path=None): 839ef81066SDaniel Dunbar """Try to find 'executable' in the directories listed in 'path' (a 849ef81066SDaniel Dunbar string listing directories separated by 'os.pathsep'; defaults to 859ef81066SDaniel Dunbar os.environ['PATH']). Returns the complete filename or None if not 869ef81066SDaniel Dunbar found 879ef81066SDaniel Dunbar """ 889ef81066SDaniel Dunbar if path is None: 899ef81066SDaniel Dunbar path = os.environ['PATH'] 909ef81066SDaniel Dunbar paths = path.split(os.pathsep) 919ef81066SDaniel Dunbar extlist = [''] 929ef81066SDaniel Dunbar if os.name == 'os2': 939ef81066SDaniel Dunbar (base, ext) = os.path.splitext(executable) 949ef81066SDaniel Dunbar # executable files on OS/2 can have an arbitrary extension, but 959ef81066SDaniel Dunbar # .exe is automatically appended if no dot is present in the name 969ef81066SDaniel Dunbar if not ext: 979ef81066SDaniel Dunbar executable = executable + ".exe" 989ef81066SDaniel Dunbar elif sys.platform == 'win32': 999ef81066SDaniel Dunbar pathext = os.environ['PATHEXT'].lower().split(os.pathsep) 1009ef81066SDaniel Dunbar (base, ext) = os.path.splitext(executable) 1019ef81066SDaniel Dunbar if ext.lower() not in pathext: 1029ef81066SDaniel Dunbar extlist = pathext 1039ef81066SDaniel Dunbar for ext in extlist: 1049ef81066SDaniel Dunbar execname = executable + ext 1059ef81066SDaniel Dunbar if os.path.isfile(execname): 1069ef81066SDaniel Dunbar return execname 1079ef81066SDaniel Dunbar else: 1089ef81066SDaniel Dunbar for p in paths: 1099ef81066SDaniel Dunbar f = os.path.join(p, execname) 1109ef81066SDaniel Dunbar if os.path.isfile(f): 1119ef81066SDaniel Dunbar return f 1129ef81066SDaniel Dunbar else: 1139ef81066SDaniel Dunbar return None 1149ef81066SDaniel Dunbar 1159ef81066SDaniel Dunbardef is_executable(fpath): 1169ef81066SDaniel Dunbar return os.path.exists(fpath) and os.access(fpath, os.X_OK) 1179ef81066SDaniel Dunbar 1189ef81066SDaniel Dunbardef add_options(parser): 1199ef81066SDaniel Dunbar parser.add_option("-v", "--verbose", action="store_true", 1209ef81066SDaniel Dunbar default=False, 1219ef81066SDaniel Dunbar help=("Output informational messages" 1229ef81066SDaniel Dunbar " [default: %default]")) 1239ef81066SDaniel Dunbar parser.add_option("--src", action="append", 1249ef81066SDaniel Dunbar help=("Top-level source directory [default: %default]")) 1259ef81066SDaniel Dunbar parser.add_option("--build", action="append", 1269ef81066SDaniel Dunbar help=("Build types to run [default: %default]")) 1279ef81066SDaniel Dunbar parser.add_option("--cc", default=find_executable("cc"), 1289ef81066SDaniel Dunbar help=("The C compiler to use [default: %default]")) 1299ef81066SDaniel Dunbar parser.add_option("--cxx", default=find_executable("c++"), 1309ef81066SDaniel Dunbar help=("The C++ compiler to use [default: %default]")) 1319ef81066SDaniel Dunbar parser.add_option("--threads", default=4, type="int", 1329ef81066SDaniel Dunbar help=("The number of worker threads to use " 1339ef81066SDaniel Dunbar "[default: %default]")) 1349ef81066SDaniel Dunbar parser.add_option("--jobs", "-j", default=8, type="int", 1359ef81066SDaniel Dunbar help=("The number of simultaneous build jobs " 1369ef81066SDaniel Dunbar "[default: %default]")) 1379ef81066SDaniel Dunbar parser.add_option("--prefix", 1389ef81066SDaniel Dunbar help=("Root install directory [default: %default]")) 1399ef81066SDaniel Dunbar parser.add_option("--builddir", 1409ef81066SDaniel Dunbar help=("Root build directory [default: %default]")) 1419ef81066SDaniel Dunbar parser.add_option("--extra-llvm-config-flags", default="", 1429ef81066SDaniel Dunbar help=("Extra flags to pass to llvm configure [default: %default]")) 1439ef81066SDaniel Dunbar parser.add_option("--force-configure", default=False, action="store_true", 1449ef81066SDaniel Dunbar help=("Force reconfigure of all components")) 145c26e5fb8SDavid Greene parser.add_option("--no-dragonegg", default=False, action="store_true", 146c26e5fb8SDavid Greene help=("Do not build dragonegg")) 1479ef81066SDaniel Dunbar parser.add_option("--no-install", default=False, action="store_true", 1489ef81066SDaniel Dunbar help=("Do not do installs")) 149a15b16f2SDavid Greene parser.add_option("--keep-going", default=False, action="store_true", 150a15b16f2SDavid Greene help=("Keep going after failures")) 15163677389SDavid Greene parser.add_option("--no-flavor-prefix", default=False, action="store_true", 15263677389SDavid Greene help=("Do not append the build flavor to the install path")) 1539ccdb170SDavid Greene parser.add_option("--enable-werror", default=False, action="store_true", 1549ccdb170SDavid Greene help=("Build with -Werror")) 1559ef81066SDaniel Dunbar return 1569ef81066SDaniel Dunbar 1579ef81066SDaniel Dunbardef check_options(parser, options, valid_builds): 1589ef81066SDaniel Dunbar # See if we're building valid flavors. 1599ef81066SDaniel Dunbar for build in options.build: 1609ef81066SDaniel Dunbar if (build not in valid_builds): 1619ef81066SDaniel Dunbar parser.error("'" + build + "' is not a valid build flavor " 1629ef81066SDaniel Dunbar + str(valid_builds)) 1639ef81066SDaniel Dunbar 1649ef81066SDaniel Dunbar # See if we can find source directories. 1659ef81066SDaniel Dunbar for src in options.src: 1669ef81066SDaniel Dunbar for component in components: 1679ef81066SDaniel Dunbar component = component.rstrip("2") 1689ef81066SDaniel Dunbar compsrc = src + "/" + component 1699ef81066SDaniel Dunbar if (not os.path.isdir(compsrc)): 1709ef81066SDaniel Dunbar parser.error("'" + compsrc + "' does not exist") 1719ef81066SDaniel Dunbar 1729ef81066SDaniel Dunbar # See if we can find the compilers 1739ef81066SDaniel Dunbar options.cc = find_executable(options.cc) 1749ef81066SDaniel Dunbar options.cxx = find_executable(options.cxx) 1759ef81066SDaniel Dunbar 1769ef81066SDaniel Dunbar return 1779ef81066SDaniel Dunbar 1789ef81066SDaniel Dunbar# Find a unique short name for the given set of paths. This searches 1799ef81066SDaniel Dunbar# back through path components until it finds unique component names 1809ef81066SDaniel Dunbar# among all given paths. 1819ef81066SDaniel Dunbardef get_path_abbrevs(paths): 1829ef81066SDaniel Dunbar # Find the number of common starting characters in the last component 1839ef81066SDaniel Dunbar # of the paths. 1849ef81066SDaniel Dunbar unique_paths = list(paths) 1859ef81066SDaniel Dunbar 1869ef81066SDaniel Dunbar class NotFoundException(Exception): pass 1879ef81066SDaniel Dunbar 1889ef81066SDaniel Dunbar # Find a unique component of each path. 1899ef81066SDaniel Dunbar unique_bases = unique_paths[:] 1909ef81066SDaniel Dunbar found = 0 1919ef81066SDaniel Dunbar while len(unique_paths) > 0: 1929ef81066SDaniel Dunbar bases = [os.path.basename(src) for src in unique_paths] 1939ef81066SDaniel Dunbar components = { c for c in bases } 1949ef81066SDaniel Dunbar # Account for single entry in paths. 1959ef81066SDaniel Dunbar if len(components) > 1 or len(components) == len(bases): 1969ef81066SDaniel Dunbar # We found something unique. 1979ef81066SDaniel Dunbar for c in components: 1989ef81066SDaniel Dunbar if bases.count(c) == 1: 1999ef81066SDaniel Dunbar index = bases.index(c) 2009ef81066SDaniel Dunbar unique_bases[index] = c 2019ef81066SDaniel Dunbar # Remove the corresponding path from the set under 2029ef81066SDaniel Dunbar # consideration. 2039ef81066SDaniel Dunbar unique_paths[index] = None 2049ef81066SDaniel Dunbar unique_paths = [ p for p in unique_paths if p is not None ] 2059ef81066SDaniel Dunbar unique_paths = [os.path.dirname(src) for src in unique_paths] 2069ef81066SDaniel Dunbar 2079ef81066SDaniel Dunbar if len(unique_paths) > 0: 2089ef81066SDaniel Dunbar raise NotFoundException() 2099ef81066SDaniel Dunbar 2109ef81066SDaniel Dunbar abbrevs = dict(zip(paths, [base for base in unique_bases])) 2119ef81066SDaniel Dunbar 2129ef81066SDaniel Dunbar return abbrevs 2139ef81066SDaniel Dunbar 2149ef81066SDaniel Dunbar# Given a set of unique names, find a short character sequence that 2159ef81066SDaniel Dunbar# uniquely identifies them. 2169ef81066SDaniel Dunbardef get_short_abbrevs(unique_bases): 2179ef81066SDaniel Dunbar # Find a unique start character for each path base. 2189ef81066SDaniel Dunbar my_unique_bases = unique_bases[:] 2199ef81066SDaniel Dunbar unique_char_starts = unique_bases[:] 2209ef81066SDaniel Dunbar while len(my_unique_bases) > 0: 2219ef81066SDaniel Dunbar for start, char_tuple in enumerate(zip(*[base 2229ef81066SDaniel Dunbar for base in my_unique_bases])): 2239ef81066SDaniel Dunbar chars = { c for c in char_tuple } 2249ef81066SDaniel Dunbar # Account for single path. 2259ef81066SDaniel Dunbar if len(chars) > 1 or len(chars) == len(char_tuple): 2269ef81066SDaniel Dunbar # We found something unique. 2279ef81066SDaniel Dunbar for c in chars: 2289ef81066SDaniel Dunbar if char_tuple.count(c) == 1: 2299ef81066SDaniel Dunbar index = char_tuple.index(c) 2309ef81066SDaniel Dunbar unique_char_starts[index] = start 2319ef81066SDaniel Dunbar # Remove the corresponding path from the set under 2329ef81066SDaniel Dunbar # consideration. 2339ef81066SDaniel Dunbar my_unique_bases[index] = None 2349ef81066SDaniel Dunbar my_unique_bases = [ b for b in my_unique_bases 2359ef81066SDaniel Dunbar if b is not None ] 2369ef81066SDaniel Dunbar break 2379ef81066SDaniel Dunbar 2389ef81066SDaniel Dunbar if len(my_unique_bases) > 0: 2399ef81066SDaniel Dunbar raise NotFoundException() 2409ef81066SDaniel Dunbar 2419ef81066SDaniel Dunbar abbrevs = [abbrev[start_index:start_index+3] 2429ef81066SDaniel Dunbar for abbrev, start_index 2439ef81066SDaniel Dunbar in zip([base for base in unique_bases], 2449ef81066SDaniel Dunbar [index for index in unique_char_starts])] 2459ef81066SDaniel Dunbar 2469ef81066SDaniel Dunbar abbrevs = dict(zip(unique_bases, abbrevs)) 2479ef81066SDaniel Dunbar 2489ef81066SDaniel Dunbar return abbrevs 2499ef81066SDaniel Dunbar 2509ef81066SDaniel Dunbarclass Builder(threading.Thread): 2519ef81066SDaniel Dunbar class ExecutableNotFound(Exception): pass 2529ef81066SDaniel Dunbar class FileNotExecutable(Exception): pass 2539ef81066SDaniel Dunbar 2549ef81066SDaniel Dunbar def __init__(self, work_queue, jobs, 255c26e5fb8SDavid Greene build_abbrev, source_abbrev, 2569ef81066SDaniel Dunbar options): 2579ef81066SDaniel Dunbar super().__init__() 2589ef81066SDaniel Dunbar self.work_queue = work_queue 2599ef81066SDaniel Dunbar self.jobs = jobs 2609ef81066SDaniel Dunbar self.cc = options.cc 2619ef81066SDaniel Dunbar self.cxx = options.cxx 2629ef81066SDaniel Dunbar self.build_abbrev = build_abbrev 2639ef81066SDaniel Dunbar self.source_abbrev = source_abbrev 2649ef81066SDaniel Dunbar self.build_prefix = options.builddir 2659ef81066SDaniel Dunbar self.install_prefix = options.prefix 2669ef81066SDaniel Dunbar self.options = options 2679ef81066SDaniel Dunbar self.component_abbrev = dict( 2689ef81066SDaniel Dunbar llvm="llvm", 269c26e5fb8SDavid Greene dragonegg="degg") 2709ef81066SDaniel Dunbar def run(self): 2719ef81066SDaniel Dunbar while True: 2729ef81066SDaniel Dunbar try: 273c26e5fb8SDavid Greene source, build = self.work_queue.get() 274c26e5fb8SDavid Greene self.dobuild(source, build) 2759ef81066SDaniel Dunbar except: 2769ef81066SDaniel Dunbar traceback.print_exc() 2779ef81066SDaniel Dunbar finally: 2789ef81066SDaniel Dunbar self.work_queue.task_done() 2799ef81066SDaniel Dunbar 2809ef81066SDaniel Dunbar def execute(self, command, execdir, env, component): 2819ef81066SDaniel Dunbar prefix = self.component_abbrev[component.replace("-", "_")] 2829ef81066SDaniel Dunbar pwd = os.getcwd() 2839ef81066SDaniel Dunbar if not os.path.exists(execdir): 2849ef81066SDaniel Dunbar os.makedirs(execdir) 2859ef81066SDaniel Dunbar 2869ef81066SDaniel Dunbar execenv = os.environ.copy() 2879ef81066SDaniel Dunbar 2889ef81066SDaniel Dunbar for key, value in env.items(): 2899ef81066SDaniel Dunbar execenv[key] = value 2909ef81066SDaniel Dunbar 2919ef81066SDaniel Dunbar self.logger.debug("[" + prefix + "] " + "env " + str(env) + " " 2929ef81066SDaniel Dunbar + " ".join(command)); 2939ef81066SDaniel Dunbar 2949ef81066SDaniel Dunbar try: 2959ef81066SDaniel Dunbar proc = subprocess.Popen(command, 2969ef81066SDaniel Dunbar cwd=execdir, 2979ef81066SDaniel Dunbar env=execenv, 2989ef81066SDaniel Dunbar stdout=subprocess.PIPE, 2999ef81066SDaniel Dunbar stderr=subprocess.STDOUT) 3009ef81066SDaniel Dunbar 3019ef81066SDaniel Dunbar line = proc.stdout.readline() 3029ef81066SDaniel Dunbar while line: 3039ef81066SDaniel Dunbar self.logger.info("[" + prefix + "] " 3049ef81066SDaniel Dunbar + str(line, "utf-8").rstrip()) 3059ef81066SDaniel Dunbar line = proc.stdout.readline() 3069ef81066SDaniel Dunbar 307a15b16f2SDavid Greene (stdoutdata, stderrdata) = proc.communicate() 308a15b16f2SDavid Greene retcode = proc.wait() 309a15b16f2SDavid Greene 310a15b16f2SDavid Greene return retcode 311a15b16f2SDavid Greene 3129ef81066SDaniel Dunbar except: 3139ef81066SDaniel Dunbar traceback.print_exc() 3149ef81066SDaniel Dunbar 3159ef81066SDaniel Dunbar # Get a list of C++ include directories to pass to clang. 3169ef81066SDaniel Dunbar def get_includes(self): 3179ef81066SDaniel Dunbar # Assume we're building with g++ for now. 3189ef81066SDaniel Dunbar command = [self.cxx] 3199ef81066SDaniel Dunbar command += ["-v", "-x", "c++", "/dev/null", "-fsyntax-only"] 3209ef81066SDaniel Dunbar includes = [] 3219ef81066SDaniel Dunbar self.logger.debug(command) 3229ef81066SDaniel Dunbar try: 3239ef81066SDaniel Dunbar proc = subprocess.Popen(command, 3249ef81066SDaniel Dunbar stdout=subprocess.PIPE, 3259ef81066SDaniel Dunbar stderr=subprocess.STDOUT) 3269ef81066SDaniel Dunbar 3279ef81066SDaniel Dunbar gather = False 3289ef81066SDaniel Dunbar line = proc.stdout.readline() 3299ef81066SDaniel Dunbar while line: 3309ef81066SDaniel Dunbar self.logger.debug(line) 3319ef81066SDaniel Dunbar if re.search("End of search list", str(line)) is not None: 3329ef81066SDaniel Dunbar self.logger.debug("Stop Gather") 3339ef81066SDaniel Dunbar gather = False 3349ef81066SDaniel Dunbar if gather: 3359ef81066SDaniel Dunbar includes.append(str(line, "utf-8").strip()) 3369ef81066SDaniel Dunbar if re.search("#include <...> search starts", str(line)) is not None: 3379ef81066SDaniel Dunbar self.logger.debug("Start Gather") 3389ef81066SDaniel Dunbar gather = True 3399ef81066SDaniel Dunbar line = proc.stdout.readline() 340a15b16f2SDavid Greene 3419ef81066SDaniel Dunbar except: 3429ef81066SDaniel Dunbar traceback.print_exc() 3439ef81066SDaniel Dunbar self.logger.debug(includes) 3449ef81066SDaniel Dunbar return includes 3459ef81066SDaniel Dunbar 346c26e5fb8SDavid Greene def dobuild(self, source, build): 3479ef81066SDaniel Dunbar build_suffix = "" 3489ef81066SDaniel Dunbar 3499ef81066SDaniel Dunbar ssabbrev = get_short_abbrevs([ab for ab in self.source_abbrev.values()]) 3509ef81066SDaniel Dunbar 3519ef81066SDaniel Dunbar prefix = "[" + ssabbrev[self.source_abbrev[source]] + "-" + self.build_abbrev[build] + "]" 35263677389SDavid Greene if (not self.options.no_flavor_prefix): 3539ef81066SDaniel Dunbar self.install_prefix += "/" + self.source_abbrev[source] + "/" + build 35463677389SDavid Greene 3559ef81066SDaniel Dunbar build_suffix += "/" + self.source_abbrev[source] + "/" + build 3569ef81066SDaniel Dunbar 3579ef81066SDaniel Dunbar self.logger = logging.getLogger(prefix) 3589ef81066SDaniel Dunbar 3599ef81066SDaniel Dunbar self.logger.debug(self.install_prefix) 3609ef81066SDaniel Dunbar 3619ef81066SDaniel Dunbar # Assume we're building with gcc for now. 3629ef81066SDaniel Dunbar cxxincludes = self.get_includes() 363ec217f6aSRafael Espindola cxxroot = os.path.dirname(cxxincludes[0]) # Remove the version 364ec217f6aSRafael Espindola cxxroot = os.path.dirname(cxxroot) # Remove the c++ 365ec217f6aSRafael Espindola cxxroot = os.path.dirname(cxxroot) # Remove the include 3669ef81066SDaniel Dunbar 3679ef81066SDaniel Dunbar configure_flags = dict( 3689ef81066SDaniel Dunbar llvm=dict(debug=["--prefix=" + self.install_prefix, 3699ef81066SDaniel Dunbar "--enable-assertions", 3709ef81066SDaniel Dunbar "--disable-optimized", 371ec217f6aSRafael Espindola "--with-gcc-toolchain=" + cxxroot], 3729ef81066SDaniel Dunbar release=["--prefix=" + self.install_prefix, 3739ef81066SDaniel Dunbar "--enable-optimized", 374ec217f6aSRafael Espindola "--with-gcc-toolchain=" + cxxroot], 3759ef81066SDaniel Dunbar paranoid=["--prefix=" + self.install_prefix, 3769ef81066SDaniel Dunbar "--enable-assertions", 3779ef81066SDaniel Dunbar "--enable-expensive-checks", 3789ef81066SDaniel Dunbar "--disable-optimized", 379ec217f6aSRafael Espindola "--with-gcc-toolchain=" + cxxroot]), 3809ef81066SDaniel Dunbar dragonegg=dict(debug=[], 3819ef81066SDaniel Dunbar release=[], 3829ef81066SDaniel Dunbar paranoid=[])) 3839ef81066SDaniel Dunbar 3849ccdb170SDavid Greene if (self.options.enable_werror): 3859ccdb170SDavid Greene configure_flags["llvm"]["debug"].append("--enable-werror") 3869ccdb170SDavid Greene configure_flags["llvm"]["release"].append("--enable-werror") 3879ccdb170SDavid Greene configure_flags["llvm"]["paranoid"].append("--enable-werror") 3889ccdb170SDavid Greene 3899ef81066SDaniel Dunbar configure_env = dict( 3909ef81066SDaniel Dunbar llvm=dict(debug=dict(CC=self.cc, 3919ef81066SDaniel Dunbar CXX=self.cxx), 3929ef81066SDaniel Dunbar release=dict(CC=self.cc, 3939ef81066SDaniel Dunbar CXX=self.cxx), 3949ef81066SDaniel Dunbar paranoid=dict(CC=self.cc, 3959ef81066SDaniel Dunbar CXX=self.cxx)), 3969ef81066SDaniel Dunbar dragonegg=dict(debug=dict(CC=self.cc, 3979ef81066SDaniel Dunbar CXX=self.cxx), 3989ef81066SDaniel Dunbar release=dict(CC=self.cc, 3999ef81066SDaniel Dunbar CXX=self.cxx), 4009ef81066SDaniel Dunbar paranoid=dict(CC=self.cc, 4019ef81066SDaniel Dunbar CXX=self.cxx))) 4029ef81066SDaniel Dunbar 4039ef81066SDaniel Dunbar make_flags = dict( 4049ef81066SDaniel Dunbar llvm=dict(debug=["-j" + str(self.jobs)], 4059ef81066SDaniel Dunbar release=["-j" + str(self.jobs)], 4069ef81066SDaniel Dunbar paranoid=["-j" + str(self.jobs)]), 4079ef81066SDaniel Dunbar dragonegg=dict(debug=["-j" + str(self.jobs)], 4089ef81066SDaniel Dunbar release=["-j" + str(self.jobs)], 4099ef81066SDaniel Dunbar paranoid=["-j" + str(self.jobs)])) 4109ef81066SDaniel Dunbar 4119ef81066SDaniel Dunbar make_env = dict( 4129ef81066SDaniel Dunbar llvm=dict(debug=dict(), 4139ef81066SDaniel Dunbar release=dict(), 4149ef81066SDaniel Dunbar paranoid=dict()), 415c26e5fb8SDavid Greene dragonegg=dict(debug=dict(GCC=self.cc, 4169ef81066SDaniel Dunbar LLVM_CONFIG=self.install_prefix + "/bin/llvm-config"), 417c26e5fb8SDavid Greene release=dict(GCC=self.cc, 4189ef81066SDaniel Dunbar LLVM_CONFIG=self.install_prefix + "/bin/llvm-config"), 419c26e5fb8SDavid Greene paranoid=dict(GCC=self.cc, 4209ef81066SDaniel Dunbar LLVM_CONFIG=self.install_prefix + "/bin/llvm-config"))) 4219ef81066SDaniel Dunbar 4229ef81066SDaniel Dunbar make_install_flags = dict( 4239ef81066SDaniel Dunbar llvm=dict(debug=["install"], 4249ef81066SDaniel Dunbar release=["install"], 4259ef81066SDaniel Dunbar paranoid=["install"]), 4269ef81066SDaniel Dunbar dragonegg=dict(debug=["install"], 4279ef81066SDaniel Dunbar release=["install"], 4289ef81066SDaniel Dunbar paranoid=["install"])) 4299ef81066SDaniel Dunbar 4309ef81066SDaniel Dunbar make_install_env = dict( 4319ef81066SDaniel Dunbar llvm=dict(debug=dict(), 4329ef81066SDaniel Dunbar release=dict(), 4339ef81066SDaniel Dunbar paranoid=dict()), 4349ef81066SDaniel Dunbar dragonegg=dict(debug=dict(), 4359ef81066SDaniel Dunbar release=dict(), 4369ef81066SDaniel Dunbar paranoid=dict())) 4379ef81066SDaniel Dunbar 4389ef81066SDaniel Dunbar make_check_flags = dict( 4399ef81066SDaniel Dunbar llvm=dict(debug=["check"], 4409ef81066SDaniel Dunbar release=["check"], 4419ef81066SDaniel Dunbar paranoid=["check"]), 4429ef81066SDaniel Dunbar dragonegg=dict(debug=["check"], 4439ef81066SDaniel Dunbar release=["check"], 4449ef81066SDaniel Dunbar paranoid=["check"])) 4459ef81066SDaniel Dunbar 4469ef81066SDaniel Dunbar make_check_env = dict( 4479ef81066SDaniel Dunbar llvm=dict(debug=dict(), 4489ef81066SDaniel Dunbar release=dict(), 4499ef81066SDaniel Dunbar paranoid=dict()), 4509ef81066SDaniel Dunbar dragonegg=dict(debug=dict(), 4519ef81066SDaniel Dunbar release=dict(), 4529ef81066SDaniel Dunbar paranoid=dict())) 4539ef81066SDaniel Dunbar 4549ef81066SDaniel Dunbar for component in components: 4559ef81066SDaniel Dunbar comp = component[:] 4569ef81066SDaniel Dunbar 457c26e5fb8SDavid Greene if (self.options.no_dragonegg): 458c26e5fb8SDavid Greene if (comp == 'dragonegg'): 4599ef81066SDaniel Dunbar self.logger.info("Skipping " + component + " in " 4609ef81066SDaniel Dunbar + builddir) 4619ef81066SDaniel Dunbar continue 4629ef81066SDaniel Dunbar 4639ef81066SDaniel Dunbar srcdir = source + "/" + comp.rstrip("2") 4649ef81066SDaniel Dunbar builddir = self.build_prefix + "/" + comp + "/" + build_suffix 4659ef81066SDaniel Dunbar installdir = self.install_prefix 4669ef81066SDaniel Dunbar 4679ef81066SDaniel Dunbar comp_key = comp.replace("-", "_") 4689ef81066SDaniel Dunbar 4699ef81066SDaniel Dunbar config_args = configure_flags[comp_key][build][:] 4709ef81066SDaniel Dunbar config_args.extend(getattr(self.options, 4719ef81066SDaniel Dunbar "extra_" + comp_key.rstrip("2") 472c26e5fb8SDavid Greene + "_config_flags", 473c26e5fb8SDavid Greene "").split()) 4749ef81066SDaniel Dunbar 4759ef81066SDaniel Dunbar self.logger.info("Configuring " + component + " in " + builddir) 476a15b16f2SDavid Greene configrc = self.configure(component, srcdir, builddir, 4779ef81066SDaniel Dunbar config_args, 4789ef81066SDaniel Dunbar configure_env[comp_key][build]) 4799ef81066SDaniel Dunbar 480a15b16f2SDavid Greene if (configrc == None) : 481a15b16f2SDavid Greene self.logger.info("[None] Failed to configure " + component + " in " + installdir) 482a15b16f2SDavid Greene 483a15b16f2SDavid Greene if (configrc == 0 or self.options.keep_going) : 4849ef81066SDaniel Dunbar self.logger.info("Building " + component + " in " + builddir) 4859ef81066SDaniel Dunbar self.logger.info("Build: make " + str(make_flags[comp_key][build])) 486a15b16f2SDavid Greene buildrc = self.make(component, srcdir, builddir, 4879ef81066SDaniel Dunbar make_flags[comp_key][build], 4889ef81066SDaniel Dunbar make_env[comp_key][build]) 4899ef81066SDaniel Dunbar 490a15b16f2SDavid Greene if (buildrc == None) : 491a15b16f2SDavid Greene self.logger.info("[None] Failed to build " + component + " in " + installdir) 492a15b16f2SDavid Greene 493a15b16f2SDavid Greene if (buildrc == 0 or self.options.keep_going) : 494a15b16f2SDavid Greene self.logger.info("Testing " + component + " in " + builddir) 495a15b16f2SDavid Greene self.logger.info("Test: make " 496a15b16f2SDavid Greene + str(make_check_flags[comp_key][build])) 497a15b16f2SDavid Greene testrc = self.make(component, srcdir, builddir, 498a15b16f2SDavid Greene make_check_flags[comp_key][build], 499a15b16f2SDavid Greene make_check_env[comp_key][build]) 500a15b16f2SDavid Greene 501a15b16f2SDavid Greene if (testrc == None) : 502a15b16f2SDavid Greene self.logger.info("[None] Failed to test " + component + " in " + installdir) 503a15b16f2SDavid Greene 504a15b16f2SDavid Greene if ((testrc == 0 or self.options.keep_going) 505a15b16f2SDavid Greene and not self.options.no_install): 5069ef81066SDaniel Dunbar self.logger.info("Installing " + component + " in " + installdir) 5079ef81066SDaniel Dunbar self.make(component, srcdir, builddir, 5089ef81066SDaniel Dunbar make_install_flags[comp_key][build], 5099ef81066SDaniel Dunbar make_install_env[comp_key][build]) 510a15b16f2SDavid Greene else : 511a15b16f2SDavid Greene self.logger.info("Failed testing " + component + " in " + installdir) 5129ef81066SDaniel Dunbar 513a15b16f2SDavid Greene else : 514a15b16f2SDavid Greene self.logger.info("Failed to build " + component + " in " + installdir) 5159ef81066SDaniel Dunbar 516a15b16f2SDavid Greene else : 517a15b16f2SDavid Greene self.logger.info("Failed to configure " + component + " in " + installdir) 5189ef81066SDaniel Dunbar 5199ef81066SDaniel Dunbar def configure(self, component, srcdir, builddir, flags, env): 520a15b16f2SDavid Greene prefix = self.component_abbrev[component.replace("-", "_")] 521a15b16f2SDavid Greene 5229ef81066SDaniel Dunbar self.logger.debug("Configure " + str(flags) + " " + str(srcdir) + " -> " 5239ef81066SDaniel Dunbar + str(builddir)) 5249ef81066SDaniel Dunbar 5259ef81066SDaniel Dunbar configure_files = dict( 5269ef81066SDaniel Dunbar llvm=[(srcdir + "/configure", builddir + "/Makefile")], 527a15b16f2SDavid Greene dragonegg=[(None,None)]) 5289ef81066SDaniel Dunbar 5299ef81066SDaniel Dunbar 5309ef81066SDaniel Dunbar doconfig = False 5319ef81066SDaniel Dunbar for conf, mf in configure_files[component.replace("-", "_")]: 532a15b16f2SDavid Greene if conf is None: 533a15b16f2SDavid Greene # No configure necessary 534a15b16f2SDavid Greene return 0 535a15b16f2SDavid Greene 5369ef81066SDaniel Dunbar if not os.path.exists(conf): 537a15b16f2SDavid Greene self.logger.info("[" + prefix + "] Configure failed, no configure script " + conf) 538a15b16f2SDavid Greene return -1 539a15b16f2SDavid Greene 5409ef81066SDaniel Dunbar if os.path.exists(conf) and os.path.exists(mf): 5419ef81066SDaniel Dunbar confstat = os.stat(conf) 5429ef81066SDaniel Dunbar makestat = os.stat(mf) 5439ef81066SDaniel Dunbar if confstat.st_mtime > makestat.st_mtime: 5449ef81066SDaniel Dunbar doconfig = True 5459ef81066SDaniel Dunbar break 5469ef81066SDaniel Dunbar else: 5479ef81066SDaniel Dunbar doconfig = True 5489ef81066SDaniel Dunbar break 5499ef81066SDaniel Dunbar 5509ef81066SDaniel Dunbar if not doconfig and not self.options.force_configure: 551a15b16f2SDavid Greene return 0 5529ef81066SDaniel Dunbar 5539ef81066SDaniel Dunbar program = srcdir + "/configure" 5549ef81066SDaniel Dunbar if not is_executable(program): 555a15b16f2SDavid Greene self.logger.info("[" + prefix + "] Configure failed, cannot execute " + program) 556a15b16f2SDavid Greene return -1 5579ef81066SDaniel Dunbar 5589ef81066SDaniel Dunbar args = [program] 5599ef81066SDaniel Dunbar args += ["--verbose"] 5609ef81066SDaniel Dunbar args += flags 561a15b16f2SDavid Greene return self.execute(args, builddir, env, component) 5629ef81066SDaniel Dunbar 5639ef81066SDaniel Dunbar def make(self, component, srcdir, builddir, flags, env): 5649ef81066SDaniel Dunbar program = find_executable("make") 5659ef81066SDaniel Dunbar if program is None: 5669ef81066SDaniel Dunbar raise ExecutableNotFound 5679ef81066SDaniel Dunbar 5689ef81066SDaniel Dunbar if not is_executable(program): 5699ef81066SDaniel Dunbar raise FileNotExecutable 5709ef81066SDaniel Dunbar 5719ef81066SDaniel Dunbar args = [program] 5729ef81066SDaniel Dunbar args += flags 573a15b16f2SDavid Greene return self.execute(args, builddir, env, component) 5749ef81066SDaniel Dunbar 5759ef81066SDaniel Dunbar# Global constants 5769ef81066SDaniel Dunbarbuild_abbrev = dict(debug="dbg", release="opt", paranoid="par") 577c26e5fb8SDavid Greenecomponents = ["llvm", "dragonegg"] 5789ef81066SDaniel Dunbar 5799ef81066SDaniel Dunbar# Parse options 5809ef81066SDaniel Dunbarparser = optparse.OptionParser(version="%prog 1.0") 5819ef81066SDaniel Dunbaradd_options(parser) 5829ef81066SDaniel Dunbar(options, args) = parser.parse_args() 5839ef81066SDaniel Dunbarcheck_options(parser, options, build_abbrev.keys()); 5849ef81066SDaniel Dunbar 5859ef81066SDaniel Dunbarif options.verbose: 5869ef81066SDaniel Dunbar logging.basicConfig(level=logging.DEBUG, 5879ef81066SDaniel Dunbar format='%(name)-13s: %(message)s') 5889ef81066SDaniel Dunbarelse: 5899ef81066SDaniel Dunbar logging.basicConfig(level=logging.INFO, 5909ef81066SDaniel Dunbar format='%(name)-13s: %(message)s') 5919ef81066SDaniel Dunbar 5929ef81066SDaniel Dunbarsource_abbrev = get_path_abbrevs(set(options.src)) 5939ef81066SDaniel Dunbar 5949ef81066SDaniel Dunbarwork_queue = queue.Queue() 5959ef81066SDaniel Dunbar 5969ef81066SDaniel Dunbarjobs = options.jobs // options.threads 5979ef81066SDaniel Dunbarif jobs == 0: 5989ef81066SDaniel Dunbar jobs = 1 5999ef81066SDaniel Dunbar 6009ef81066SDaniel Dunbarnumthreads = options.threads 6019ef81066SDaniel Dunbar 6029ef81066SDaniel Dunbarlogging.getLogger().info("Building with " + str(options.jobs) + " jobs and " 6039ef81066SDaniel Dunbar + str(numthreads) + " threads using " + str(jobs) 6049ef81066SDaniel Dunbar + " make jobs") 6059ef81066SDaniel Dunbar 606c26e5fb8SDavid Greenelogging.getLogger().info("CC = " + str(options.cc)) 607c26e5fb8SDavid Greenelogging.getLogger().info("CXX = " + str(options.cxx)) 608c26e5fb8SDavid Greene 6099ef81066SDaniel Dunbarfor t in range(numthreads): 6109ef81066SDaniel Dunbar builder = Builder(work_queue, jobs, 611c26e5fb8SDavid Greene build_abbrev, source_abbrev, 6129ef81066SDaniel Dunbar options) 6139ef81066SDaniel Dunbar builder.daemon = True 6149ef81066SDaniel Dunbar builder.start() 6159ef81066SDaniel Dunbar 6169ef81066SDaniel Dunbarfor build in set(options.build): 6179ef81066SDaniel Dunbar for source in set(options.src): 618c26e5fb8SDavid Greene work_queue.put((source, build)) 6199ef81066SDaniel Dunbar 6209ef81066SDaniel Dunbarwork_queue.join() 621