1#!/usr/bin/env python
2
3import argparse
4import os
5import os.path
6import shutil
7import subprocess
8import sys
9
10class BuildError(Exception):
11    def __init__(self,
12                 string=None,
13                 path=None,
14                 inferior_error=None):
15        self.m_string = string
16        self.m_path = path
17        self.m_inferior_error = inferior_error
18    def __str__(self):
19        if self.m_path and self.m_string:
20            return "Build error: %s (referring to %s)" % (self.m_string, self.m_path)
21        if self.m_path:
22            return "Build error (referring to %s)" % (self.m_path)
23        if self.m_string:
24            return "Build error: %s" % (self.m_string)
25        return "Build error"
26
27class LLDBBuildBot:
28    def __init__(self,
29                 build_directory_path,
30                 log_path,
31                 lldb_repository_url="http://llvm.org/svn/llvm-project/lldb/trunk",
32                 llvm_repository_url="http://llvm.org/svn/llvm-project/llvm/trunk",
33                 clang_repository_url="http://llvm.org/svn/llvm-project/cfe/trunk",
34                 revision=None):
35        self.m_build_directory_path = os.path.abspath(build_directory_path)
36        self.m_log_path = os.path.abspath(log_path)
37        self.m_lldb_repository_url = lldb_repository_url
38        self.m_llvm_repository_url = llvm_repository_url
39        self.m_clang_repository_url = clang_repository_url
40        self.m_revision = revision
41        self.m_log_stream = None
42    def Setup(self):
43        if os.path.exists(self.m_build_directory_path):
44            raise BuildError(string="Build directory exists", path=self.m_build_directory_path)
45        if os.path.exists(self.m_log_path):
46            raise BuildError(string="Log file exists", path=self.m_log_path)
47        self.m_log_stream = open(self.m_log_path, 'w')
48        os.mkdir(self.m_build_directory_path)
49    def Checkout(self):
50        os.chdir(self.m_build_directory_path)
51
52        cmdline_prefix = []
53
54        if self.m_revision != None:
55            cmdline_prefix = ["svn", "-r %s" % (self.m_revision), "co"]
56        else:
57            cmdline_prefix = ["svn", "co"]
58
59        returncode = subprocess.call(cmdline_prefix + [self.m_lldb_repository_url, "lldb"],
60                                     stdout=self.m_log_stream,
61                                     stderr=self.m_log_stream)
62        if returncode != 0:
63            raise BuildError(string="Couldn't checkout LLDB")
64
65        os.chdir("lldb")
66
67        returncode = subprocess.call(cmdline_prefix + [self.m_llvm_repository_url, "llvm.checkout"],
68                                     stdout=self.m_log_stream,
69                                     stderr=self.m_log_stream)
70
71        if returncode != 0:
72            raise BuildError(string="Couldn't checkout LLVM")
73
74        os.symlink("llvm.checkout", "llvm")
75
76        os.chdir("llvm/tools")
77
78        returncode = subprocess.call(cmdline_prefix + [self.m_clang_repository_url, "clang"],
79                                     stdout=self.m_log_stream,
80                                     stderr=self.m_log_stream)
81
82        if returncode != 0:
83            raise BuildError(string="Couldn't checkout Clang")
84    def Build(self):
85        os.chdir(self.m_build_directory_path)
86        os.chdir("lldb/llvm")
87
88        returncode = subprocess.call(["./configure", "--disable-optimized", "--enable-assertions", "--enable-targets=x86,x86_64,arm"],
89                                     stdout=self.m_log_stream,
90                                     stderr=self.m_log_stream)
91
92        if returncode != 0:
93            raise BuildError(string="Couldn't configure LLVM/Clang")
94
95        returncode = subprocess.call(["make"],
96                                     stdout=self.m_log_stream,
97                                     stderr=self.m_log_stream)
98
99        if returncode != 0:
100            raise BuildError(string="Couldn't build LLVM/Clang")
101
102        os.chdir(self.m_build_directory_path)
103        os.chdir("lldb")
104
105        returncode = subprocess.call(["xcodebuild",
106                                      "-project", "lldb.xcodeproj",
107                                      "-target", "lldb-tool",
108                                      "-configuration", "Debug",
109                                      "-arch", "x86_64",
110                                      "LLVM_CONFIGURATION=Debug+Asserts",
111                                      "OBJROOT=build"],
112                                      stdout=self.m_log_stream,
113                                      stderr=self.m_log_stream)
114
115        if returncode != 0:
116            raise BuildError(string="Couldn't build LLDB")
117    def Test(self):
118        os.chdir(self.m_build_directory_path)
119        os.chdir("lldb/test")
120
121        returncode = subprocess.call(["./dotest.py", "-t"],
122                                     stdout=self.m_log_stream,
123                                     stderr=self.m_log_stream)
124    def Takedown(self):
125        os.chdir("/tmp")
126        self.m_log_stream.close()
127        shutil.rmtree(self.m_build_directory_path)
128    def Run(self):
129        self.Setup()
130        self.Checkout()
131        self.Build()
132        #self.Test()
133        self.Takedown()
134
135def GetArgParser():
136    parser = argparse.ArgumentParser(description="Try to build LLDB/LLVM/Clang and run the full test suite.")
137    parser.add_argument("--build-path", "-b", required=True, help="A (nonexistent) path to put temporary build products into", metavar="path")
138    parser.add_argument("--log-file", "-l", required=True, help="The name of a (nonexistent) log file", metavar="file")
139    parser.add_argument("--revision", "-r", required=False, help="The LLVM revision to use", metavar="N")
140    return parser
141
142parser = GetArgParser()
143arg_dict = vars(parser.parse_args())
144
145build_bot = LLDBBuildBot(build_directory_path=arg_dict["build_path"],
146                         log_path=arg_dict["log_file"],
147                         revision=arg_dict["revision"])
148
149try:
150    build_bot.Run()
151except BuildError as err:
152    print err
153