Update CMake library dependencies.
[oota-llvm.git] / utils / llvmbuild
1 #!/usr/bin/python3
2 ##===- utils/llvmbuild - Build the LLVM project ----------------*-python-*-===##
3
4 #                     The LLVM Compiler Infrastructure
5 #
6 # This file is distributed under the University of Illinois Open Source
7 # License. See LICENSE.TXT for details.
8
9 ##===----------------------------------------------------------------------===##
10 #
11 # This script builds many different flavors of the LLVM ecosystem.  It
12 # will build LLVM, Clang, llvm-gcc, and dragonegg as well as run tests
13 # on them.  This script is convenient to use to check builds and tests
14 # before committing changes to the upstream repository
15 #
16 # A typical source setup uses three trees and looks like this:
17 #
18 # official
19 #   dragonegg
20 #     trunk
21 #   gcc
22 #     trunk
23 #   llvm
24 #     trunk
25 #       tools
26 #         clang
27 #     tags
28 #       RELEASE_28
29 #         tools
30 #           clang
31 #   llvm-gcc
32 #     trunk
33 #     tags
34 #       RELEASE_28
35 # staging
36 #   dragonegg
37 #     trunk
38 #   gcc
39 #     trunk
40 #   llvm
41 #     trunk
42 #       tools
43 #         clang
44 #     tags
45 #       RELEASE_28
46 #         tools
47 #           clang
48 #   llvm-gcc
49 #     trunk
50 #     tags
51 #       RELEASE_28
52 # commit
53 #   dragonegg
54 #     trunk
55 #   gcc
56 #     trunk
57 #   llvm
58 #     trunk
59 #       tools
60 #         clang
61 #     tags
62 #       RELEASE_28
63 #         tools
64 #           clang
65 #   llvm-gcc
66 #     trunk
67 #     tags
68 #       RELEASE_28
69 #
70 # "gcc" above is the upstream FSF gcc and "gcc/trunk" refers to the
71 # 4.5 branch as discussed in the dragonegg build guide.
72 #
73 # In a typical workflow, the "official" tree always contains unchanged
74 # sources from the main LLVM project repositories.  The "staging" tree
75 # is where local work is done.  A set of changes resides there waiting
76 # to be moved upstream.  The "commit" tree is where changes from
77 # "staging" make their way upstream.  Individual incremental changes
78 # from "staging" are applied to "commit" and committed upstream after
79 # a successful build and test run.  A successful build is one in which
80 # testing results in no more failures than seen in the testing of the
81 # "official" tree.
82
83 # A build may be invoked as such:
84 #
85 # llvmbuild --src=~/llvm/commit --src=~/llvm/staging
86 #   --src=~/llvm/official --branch=trunk --branch=tags/RELEASE_28
87 #   --build=debug --build=release --build=paranoid
88 #   --prefix=/home/greened/install --builddir=/home/greened/build
89 #
90 # This will build the LLVM ecosystem, including LLVM, Clang, llvm-gcc,
91 # gcc 4.5 and dragonegg, putting build results in ~/build and
92 # installing tools in ~/install.  llvmbuild creates separate build and
93 # install directories for each source/branch/build flavor.  In the
94 # above example, llvmbuild will build debug, release and paranoid
95 # (debug+checks) flavors of the trunk and RELEASE_28 branches from
96 # each source tree (official, staging and commit) for a total of
97 # eighteen builds.  All builds will be run in parallel.
98 #
99 # The user may control parallelism via the --jobs and --threads
100 # switches.  --jobs tells llvmbuild the maximum total number of builds
101 # to activate in parallel.  The user may think of it as equivalent to
102 # the GNU make -j switch.  --threads tells llvmbuild how many worker
103 # threads to use to accomplish those builds.  If --threads is less
104 # than --jobs, --threads workers will be launched and each one will
105 # pick a source/branch/flavor combination to build.  Then llvmbuild
106 # will invoke GNU make with -j (--jobs / --threads) to use up the
107 # remaining job capacity.  Once a worker is finished with a build, it
108 # will pick another combination off the list and start building it.
109 #
110 ##===----------------------------------------------------------------------===##
111
112 import optparse
113 import os
114 import sys
115 import threading
116 import queue
117 import logging
118 import traceback
119 import subprocess
120 import re
121
122 # TODO: Use shutil.which when it is available (3.2 or later)
123 def find_executable(executable, path=None):
124     """Try to find 'executable' in the directories listed in 'path' (a
125     string listing directories separated by 'os.pathsep'; defaults to
126     os.environ['PATH']).  Returns the complete filename or None if not
127     found
128     """
129     if path is None:
130         path = os.environ['PATH']
131     paths = path.split(os.pathsep)
132     extlist = ['']
133     if os.name == 'os2':
134         (base, ext) = os.path.splitext(executable)
135         # executable files on OS/2 can have an arbitrary extension, but
136         # .exe is automatically appended if no dot is present in the name
137         if not ext:
138             executable = executable + ".exe"
139     elif sys.platform == 'win32':
140         pathext = os.environ['PATHEXT'].lower().split(os.pathsep)
141         (base, ext) = os.path.splitext(executable)
142         if ext.lower() not in pathext:
143             extlist = pathext
144     for ext in extlist:
145         execname = executable + ext
146         if os.path.isfile(execname):
147             return execname
148         else:
149             for p in paths:
150                 f = os.path.join(p, execname)
151                 if os.path.isfile(f):
152                     return f
153     else:
154         return None
155
156 def is_executable(fpath):
157     return os.path.exists(fpath) and os.access(fpath, os.X_OK)
158
159 def add_options(parser):
160     parser.add_option("-v", "--verbose", action="store_true",
161                       default=False,
162                       help=("Output informational messages"
163                             " [default: %default]"))
164     parser.add_option("--src", action="append",
165                       help=("Top-level source directory [default: %default]"))
166     parser.add_option("--build", action="append",
167                       help=("Build types to run [default: %default]"))
168     parser.add_option("--branch", action="append",
169                       help=("Source branch to build [default: %default]"))
170     parser.add_option("--cc", default=find_executable("cc"),
171                       help=("The C compiler to use [default: %default]"))
172     parser.add_option("--cxx", default=find_executable("c++"),
173                       help=("The C++ compiler to use [default: %default]"))
174     parser.add_option("--threads", default=4, type="int",
175                       help=("The number of worker threads to use "
176                             "[default: %default]"))
177     parser.add_option("--jobs", "-j", default=8, type="int",
178                       help=("The number of simultaneous build jobs "
179                             "[default: %default]"))
180     parser.add_option("--prefix",
181                       help=("Root install directory [default: %default]"))
182     parser.add_option("--builddir",
183                       help=("Root build directory [default: %default]"))
184     parser.add_option("--extra-llvm-config-flags", default="",
185                       help=("Extra flags to pass to llvm configure [default: %default]"))
186     parser.add_option("--extra-llvm-gcc-config-flags", default="",
187                       help=("Extra flags to pass to llvm-gcc configure [default: %default]"))
188     parser.add_option("--extra-gcc-config-flags", default="",
189                       help=("Extra flags to pass to gcc configure [default: %default]"))
190     parser.add_option("--force-configure", default=False, action="store_true",
191                       help=("Force reconfigure of all components"))
192     return
193
194 def check_options(parser, options, valid_builds):
195     # See if we're building valid flavors.
196     for build in options.build:
197         if (build not in valid_builds):
198             parser.error("'" + build + "' is not a valid build flavor "
199                          + str(valid_builds))
200
201     # See if we can find source directories.
202     for src in options.src:
203         for component in ["llvm", "llvm-gcc", "gcc", "dragonegg"]:
204             compsrc = src + "/" + component
205             if (not os.path.isdir(compsrc)):
206                 parser.error("'" + compsrc + "' does not exist")
207                 if (options.branch is not None):
208                     for branch in options.branch:
209                         if (not os.path.isdir(os.path.join(compsrc, branch))):
210                             parser.error("'" + os.path.join(compsrc, branch)
211                                          + "' does not exist")
212
213     # See if we can find the compilers
214     options.cc = find_executable(options.cc)
215     options.cxx = find_executable(options.cxx)
216
217     return
218
219 # Find a unique short name for the given set of paths.  This searches
220 # back through path components until it finds unique component names
221 # among all given paths.
222 def get_path_abbrevs(paths):
223     # Find the number of common starting characters in the last component
224     # of the paths.
225     unique_paths = list(paths)
226
227     class NotFoundException(Exception): pass
228
229     # Find a unique component of each path.
230     unique_bases = unique_paths[:]
231     found = 0
232     while len(unique_paths) > 0:
233         bases = [os.path.basename(src) for src in unique_paths]
234         components = { c for c in bases }
235         # Account for single entry in paths.
236         if len(components) > 1 or len(components) == len(bases):
237             # We found something unique.
238             for c in components:
239                 if bases.count(c) == 1:
240                    index = bases.index(c)
241                    unique_bases[index] = c
242                    # Remove the corresponding path from the set under
243                    # consideration.
244                    unique_paths[index] = None
245             unique_paths = [ p for p in unique_paths if p is not None ]
246         unique_paths = [os.path.dirname(src) for src in unique_paths]
247
248     if len(unique_paths) > 0:
249         raise NotFoundException()
250
251     abbrevs = dict(zip(paths, [base for base in unique_bases]))
252
253     return abbrevs
254
255 # Given a set of unique names, find a short character sequence that
256 # uniquely identifies them.
257 def get_short_abbrevs(unique_bases):
258     # Find a unique start character for each path base.
259     my_unique_bases = unique_bases[:]
260     unique_char_starts = unique_bases[:]
261     while len(my_unique_bases) > 0:
262         for start, char_tuple in enumerate(zip(*[base
263                                                  for base in my_unique_bases])):
264             chars = { c for c in char_tuple }
265             # Account for single path.
266             if len(chars) > 1 or len(chars) == len(char_tuple):
267                 # We found something unique.
268                 for c in chars:
269                     if char_tuple.count(c) == 1:
270                         index = char_tuple.index(c)
271                         unique_char_starts[index] = start
272                         # Remove the corresponding path from the set under
273                         # consideration.
274                         my_unique_bases[index] = None
275                 my_unique_bases = [ b for b in my_unique_bases
276                                     if b is not None ]
277                 break
278
279     if len(my_unique_bases) > 0:
280         raise NotFoundException()
281
282     abbrevs = [abbrev[start_index:start_index+3]
283                for abbrev, start_index
284                in zip([base for base in unique_bases],
285                       [index for index in unique_char_starts])]
286
287     abbrevs = dict(zip(unique_bases, abbrevs))
288
289     return abbrevs
290
291 class Builder(threading.Thread):
292     class ExecutableNotFound(Exception): pass
293     class FileNotExecutable(Exception): pass
294
295     def __init__(self, work_queue, jobs,
296                  build_abbrev, source_abbrev, branch_abbrev,
297                  options):
298         super().__init__()
299         self.work_queue = work_queue
300         self.jobs = jobs
301         self.cc = options.cc
302         self.cxx = options.cxx
303         self.build_abbrev = build_abbrev
304         self.source_abbrev = source_abbrev
305         self.branch_abbrev = branch_abbrev
306         self.build_prefix = options.builddir
307         self.install_prefix = options.prefix
308         self.options = options
309         self.component_abbrev = dict(
310             llvm="llvm",
311             llvm_gcc="lgcc",
312             llvm2="llv2",
313             gcc="ugcc",
314             dagonegg="degg")
315     def run(self):
316         while True:
317             try:
318                 source, branch, build = self.work_queue.get()
319                 self.dobuild(source, branch, build)
320             except:
321                 traceback.print_exc()
322             finally:
323                 self.work_queue.task_done()
324
325     def execute(self, command, execdir, env, component):
326         prefix = self.component_abbrev[component.replace("-", "_")]
327         pwd = os.getcwd()
328         if not os.path.exists(execdir):
329             os.makedirs(execdir)
330
331         execenv = os.environ.copy()
332
333         for key, value in env.items():
334             execenv[key] = value
335  
336         self.logger.debug("[" + prefix + "] " + "env " + str(env) + " "
337                           + " ".join(command));
338
339         try:
340             proc = subprocess.Popen(command,
341                                     cwd=execdir,
342                                     env=execenv,
343                                     stdout=subprocess.PIPE,
344                                     stderr=subprocess.STDOUT)
345
346             line = proc.stdout.readline()
347             while line:
348                 self.logger.info("[" + prefix + "] "
349                                  + str(line, "utf-8").rstrip())
350                 line = proc.stdout.readline()
351
352         except:
353             traceback.print_exc()
354
355     # Get a list of C++ include directories to pass to clang.
356     def get_includes(self):
357         # Assume we're building with g++ for now.
358         command = [self.cxx]
359         command += ["-v", "-x", "c++", "/dev/null", "-fsyntax-only"]
360         includes = []
361         self.logger.debug(command)
362         try:
363             proc = subprocess.Popen(command,
364                                     stdout=subprocess.PIPE,
365                                     stderr=subprocess.STDOUT)
366
367             gather = False
368             line = proc.stdout.readline()
369             while line:
370                 self.logger.debug(line)
371                 if re.search("End of search list", str(line)) is not None:
372                     self.logger.debug("Stop Gather")
373                     gather = False
374                 if gather:
375                     includes.append(str(line, "utf-8").strip())
376                 if re.search("#include <...> search starts", str(line)) is not None:
377                     self.logger.debug("Start Gather")
378                     gather = True
379                 line = proc.stdout.readline()
380         except:
381             traceback.print_exc()
382         self.logger.debug(includes)
383         return includes
384
385     def dobuild(self, source, branch, build):
386         build_suffix = ""
387
388         ssabbrev = get_short_abbrevs([ab for ab in self.source_abbrev.values()])
389
390         if branch is not None:
391             sbabbrev = get_short_abbrevs([ab for ab in self.branch_abbrev.values()])
392
393             prefix = "[" + ssabbrev[self.source_abbrev[source]] + "-" + sbabbrev[self.branch_abbrev[branch]] + "-" + self.build_abbrev[build] + "]"
394             self.install_prefix += "/" + self.source_abbrev[source] + "/" + branch + "/" + build
395             build_suffix += self.source_abbrev[source] + "/" + branch + "/" + build
396         else:
397             prefix = "[" + ssabbrev[self.source_abbrev[source]] + "-" + self.build_abbrev[build] + "]"
398             self.install_prefix += "/" + self.source_abbrev[source] + "/" + build
399             build_suffix += "/" + self.source_abbrev[source] + "/" + build
400
401         self.logger = logging.getLogger(prefix)
402
403         self.logger.debug(self.install_prefix)
404
405         # Assume we're building with gcc for now.
406         cxxincludes = self.get_includes()
407         cxxroot = cxxincludes[0]
408         cxxarch = os.path.basename(cxxincludes[1])
409
410         configure_flags = dict(
411             llvm=dict(debug=["--prefix=" + self.install_prefix,
412                              "--with-extra-options=-Werror",
413                              "--with-cxx-include-root=" + cxxroot,
414                              "--with-cxx-include-arch=" + cxxarch],
415                       release=["--prefix=" + self.install_prefix,
416                                "--with-extra-options=-Werror",
417                                "--enable-optimized",
418                                "--with-cxx-include-root=" + cxxroot,
419                                "--with-cxx-include-arch=" + cxxarch],
420                       paranoid=["--prefix=" + self.install_prefix,
421                                 "--with-extra-options=-Werror",
422                                 "--enable-expensive-checks",
423                                 "--with-cxx-include-root=" + cxxroot,
424                                 "--with-cxx-include-arch=" + cxxarch]),
425             llvm_gcc=dict(debug=["--prefix=" + self.install_prefix,
426                                  "--enable-checking",
427                                  "--program-prefix=llvm-",
428                                  "--enable-llvm=" + self.build_prefix + "/llvm/" + build_suffix,
429 # Fortran install seems to be broken.
430 #                                 "--enable-languages=c,c++,fortran"],
431                                  "--enable-languages=c,c++"],
432                           release=["--prefix=" + self.install_prefix,
433                                    "--program-prefix=llvm-",
434                                    "--enable-llvm=" + self.build_prefix + "/llvm/" + build_suffix,
435 # Fortran install seems to be broken.
436 #                                   "--enable-languages=c,c++,fortran"],
437                                    "--enable-languages=c,c++"],
438                           paranoid=["--prefix=" + self.install_prefix,
439                                     "--enable-checking",
440                                     "--program-prefix=llvm-",
441                                     "--enable-llvm=" + self.build_prefix + "/llvm/" + build_suffix,
442 # Fortran install seems to be broken.
443 #                                    "--enable-languages=c,c++,fortran"]),
444                                     "--enable-languages=c,c++"]),
445             llvm2=dict(debug=["--prefix=" + self.install_prefix,
446                               "--with-extra-options=-Werror",
447                               "--with-llvmgccdir=" + self.install_prefix + "/bin",
448                               "--with-cxx-include-root=" + cxxroot,
449                               "--with-cxx-include-arch=" + cxxarch],
450                        release=["--prefix=" + self.install_prefix,
451                                 "--with-extra-options=-Werror",
452                                 "--enable-optimized",
453                                 "--with-llvmgccdir=" + self.install_prefix + "/bin",
454                                 "--with-cxx-include-root=" + cxxroot,
455                                 "--with-cxx-include-arch=" + cxxarch],
456                        paranoid=["--prefix=" + self.install_prefix,
457                                  "--with-extra-options=-Werror",
458                                  "--enable-expensive-checks",
459                                  "--with-llvmgccdir=" + self.install_prefix + "/bin",
460                                  "--with-cxx-include-root=" + cxxroot,
461                                  "--with-cxx-include-arch=" + cxxarch]),
462             gcc=dict(debug=["--prefix=" + self.install_prefix,
463                             "--enable-checking"],
464                      release=["--prefix=" + self.install_prefix],
465                      paranoid=["--prefix=" + self.install_prefix,
466                                "--enable-checking"]),
467             dragonegg=dict(debug=[],
468                            release=[],
469                            paranoid=[]))
470
471         configure_env = dict(
472             llvm=dict(debug=dict(CC=self.cc,
473                                  CXX=self.cxx),
474                       release=dict(CC=self.cc,
475                                    CXX=self.cxx),
476                       paranoid=dict(CC=self.cc,
477                                     CXX=self.cxx)),
478             llvm_gcc=dict(debug=dict(CC=self.cc,
479                                      CXX=self.cxx),
480                           release=dict(CC=self.cc,
481                                        CXX=self.cxx),
482                           paranoid=dict(CC=self.cc,
483                                         CXX=self.cxx)),
484             llvm2=dict(debug=dict(CC=self.cc,
485                                   CXX=self.cxx),
486                        release=dict(CC=self.cc,
487                                     CXX=self.cxx),
488                        paranoid=dict(CC=self.cc,
489                                      CXX=self.cxx)),
490             gcc=dict(debug=dict(CC=self.cc,
491                                 CXX=self.cxx),
492                      release=dict(CC=self.cc,
493                                   CXX=self.cxx),
494                      paranoid=dict(CC=self.cc,
495                                    CXX=self.cxx)),
496             dragonegg=dict(debug=dict(CC=self.cc,
497                                       CXX=self.cxx),
498                            release=dict(CC=self.cc,
499                                         CXX=self.cxx),
500                            paranoid=dict(CC=self.cc,
501                                          CXX=self.cxx)))
502
503         make_flags = dict(
504             llvm=dict(debug=["-j" + str(self.jobs)],
505                       release=["-j" + str(self.jobs)],
506                       paranoid=["-j" + str(self.jobs)]),
507             llvm_gcc=dict(debug=["-j" + str(self.jobs),
508                                  "bootstrap"],
509                           release=["-j" + str(self.jobs),
510                                    "bootstrap"],
511                           paranoid=["-j" + str(self.jobs),
512                                     "bootstrap"]),
513             llvm2=dict(debug=["-j" + str(self.jobs)],
514                        release=["-j" + str(self.jobs)],
515                        paranoid=["-j" + str(self.jobs)]),
516             gcc=dict(debug=["-j" + str(self.jobs),
517                             "bootstrap"],
518                      release=["-j" + str(self.jobs),
519                               "bootstrap"],
520                      paranoid=["-j" + str(self.jobs),
521                                "bootstrap"]),
522             dragonegg=dict(debug=["-j" + str(self.jobs)],
523                            release=["-j" + str(self.jobs)],
524                            paranoid=["-j" + str(self.jobs)]))
525
526         make_env = dict(
527             llvm=dict(debug=dict(),
528                       release=dict(),
529                       paranoid=dict()),
530             llvm_gcc=dict(debug=dict(),
531                           release=dict(),
532                           paranoid=dict()),
533             llvm2=dict(debug=dict(),
534                        release=dict(),
535                        paranoid=dict()),
536             gcc=dict(debug=dict(),
537                      release=dict(),
538                      paranoid=dict()),
539             dragonegg=dict(debug=dict(GCC=self.install_prefix + "/bin/gcc",
540                                       LLVM_CONFIG=self.install_prefix + "/bin/llvm-config"),
541                            release=dict(GCC=self.install_prefix + "/bin/gcc",
542                                         LLVM_CONFIG=self.install_prefix + "/bin/llvm-config"),
543                            paranoid=dict(GCC=self.install_prefix + "/bin/gcc",
544                                          LLVM_CONFIG=self.install_prefix + "/bin/llvm-config")))
545
546         make_install_flags = dict(
547             llvm=dict(debug=["install"],
548                       release=["install"],
549                       paranoid=["install"]),
550             llvm_gcc=dict(debug=["install"],
551                           release=["install"],
552                           paranoid=["install"]),
553             llvm2=dict(debug=["install"],
554                        release=["install"],
555                        paranoid=["install"]),
556             gcc=dict(debug=["install"],
557                      release=["install"],
558                      paranoid=["install"]),
559             dragonegg=dict(debug=["install"],
560                            release=["install"],
561                            paranoid=["install"]))
562
563         make_install_env = dict(
564             llvm=dict(debug=dict(),
565                       release=dict(),
566                       paranoid=dict()),
567             llvm_gcc=dict(debug=dict(),
568                           release=dict(),
569                           paranoid=dict()),
570             llvm2=dict(debug=dict(),
571                        release=dict(),
572                        paranoid=dict()),
573             gcc=dict(debug=dict(),
574                      release=dict(),
575                      paranoid=dict()),
576             dragonegg=dict(debug=dict(),
577                            release=dict(),
578                            paranoid=dict()))
579
580         make_check_flags = dict(
581             llvm=dict(debug=["check"],
582                       release=["check"],
583                       paranoid=["check"]),
584             llvm_gcc=dict(debug=["check"],
585                           release=["check"],
586                           paranoid=["check"]),
587             llvm2=dict(debug=["check"],
588                        release=["check"],
589                        paranoid=["check"]),
590             gcc=dict(debug=["check"],
591                      release=["check"],
592                      paranoid=["check"]),
593             dragonegg=dict(debug=["check"],
594                            release=["check"],
595                            paranoid=["check"]))
596
597         make_check_env = dict(
598             llvm=dict(debug=dict(),
599                       release=dict(),
600                       paranoid=dict()),
601             llvm_gcc=dict(debug=dict(),
602                           release=dict(),
603                           paranoid=dict()),
604             llvm2=dict(debug=dict(),
605                        release=dict(),
606                        paranoid=dict()),
607             gcc=dict(debug=dict(),
608                      release=dict(),
609                      paranoid=dict()),
610             dragonegg=dict(debug=dict(),
611                            release=dict(),
612                            paranoid=dict()))
613
614         for component in ["llvm", "llvm-gcc", "llvm2", "gcc", "dragonegg"]:
615             comp = component[:]
616
617             srcdir = source + "/" + comp.rstrip("2")
618             builddir = self.build_prefix + "/" + comp + "/" + build_suffix
619             installdir = self.install_prefix
620
621             if (branch is not None):
622                 srcdir += "/" + branch
623
624             comp_key = comp.replace("-", "_")
625
626             config_args = configure_flags[comp_key][build][:]
627             config_args.extend(getattr(self.options,
628                                        "extra_" + comp_key
629                                        + "_config_flags").split())
630
631             self.logger.info("Configuring " + component + " in " + builddir)
632             self.configure(component, srcdir, builddir,
633                            config_args,
634                            configure_env[comp_key][build])
635
636             self.logger.info("Building " + component + " in " + builddir)
637             self.make(component, srcdir, builddir,
638                       make_flags[comp_key][build],
639                       make_env[comp_key][build])
640
641             self.logger.info("Installing " + component + " in " + installdir)
642             self.make(component, srcdir, builddir,
643                       make_install_flags[comp_key][build],
644                       make_install_env[comp_key][build])
645
646             self.logger.info("Testing " + component + " in " + builddir)
647             self.make(component, srcdir, builddir,
648                       make_check_flags[comp_key][build],
649                       make_check_env[comp_key][build])
650
651
652     def configure(self, component, srcdir, builddir, flags, env):
653         self.logger.debug("Configure " + str(flags) + " " + str(srcdir) + " -> "
654                           + str(builddir))
655
656         configure_files = dict(
657             llvm=[(srcdir + "/configure", builddir + "/Makefile")],
658             llvm_gcc=[(srcdir + "/configure", builddir + "/Makefile"),
659                       (srcdir + "/gcc/configure", builddir + "/gcc/Makefile")],
660             llvm2=[(srcdir + "/configure", builddir + "/Makefile")],
661             gcc=[(srcdir + "/configure", builddir + "/Makefile"),
662                  (srcdir + "/gcc/configure", builddir + "/gcc/Makefile")],
663             dragonegg=[()])
664
665
666         doconfig = False
667         for conf, mf in configure_files[component.replace("-", "_")]:
668             if not os.path.exists(conf):
669                 return
670             if os.path.exists(conf) and os.path.exists(mf):
671                 confstat = os.stat(conf)
672                 makestat = os.stat(mf)
673                 if confstat.st_mtime > makestat.st_mtime:
674                     doconfig = True
675                     break
676             else:
677                 doconfig = True
678                 break
679
680         if not doconfig and not self.options.force_configure:
681             return
682
683         program = srcdir + "/configure"
684         if not is_executable(program):
685             return
686
687         args = [program]
688         args += ["--verbose"]
689         args += flags
690         self.execute(args, builddir, env, component)
691
692     def make(self, component, srcdir, builddir, flags, env):
693         program = find_executable("make")
694         if program is None:
695             raise ExecutableNotFound
696
697         if not is_executable(program):
698             raise FileNotExecutable
699
700         args = [program]
701         args += flags
702         self.execute(args, builddir, env, component)
703
704 # Global constants
705 build_abbrev = dict(debug="dbg", release="opt", paranoid="par")
706
707 # Parse options
708 parser = optparse.OptionParser(version="%prog 1.0")
709 add_options(parser)
710 (options, args) = parser.parse_args()
711 check_options(parser, options, build_abbrev.keys());
712
713 if options.verbose:
714     logging.basicConfig(level=logging.DEBUG,
715                         format='%(name)-13s: %(message)s')
716 else:
717     logging.basicConfig(level=logging.INFO,
718                         format='%(name)-13s: %(message)s')
719
720 source_abbrev = get_path_abbrevs(set(options.src))
721 branch_abbrev = get_path_abbrevs(set(options.branch))
722
723 work_queue = queue.Queue()
724
725 jobs = options.jobs // options.threads
726 if jobs == 0:
727     jobs = 1
728
729 numthreads = options.threads
730 if jobs < numthreads:
731     numthreads = jobs
732     jobs = 1
733
734 for t in range(numthreads):
735     builder = Builder(work_queue, jobs,
736                       build_abbrev, source_abbrev, branch_abbrev,
737                       options)
738     builder.daemon = True
739     builder.start()
740
741 for build in set(options.build):
742     for source in set(options.src):
743         if options.branch is not None:
744             for branch in set(options.branch):
745                 work_queue.put((source, branch, build))
746         else:
747             work_queue.put((source, None, build))
748
749 work_queue.join()