|
1 #!/usr/bin/python |
|
2 # This Source Code Form is subject to the terms of the Mozilla Public |
|
3 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
5 |
|
6 import os |
|
7 import os.path |
|
8 import shutil |
|
9 import subprocess |
|
10 import platform |
|
11 import sys |
|
12 import json |
|
13 import collections |
|
14 import argparse |
|
15 |
|
16 |
|
17 def check_run(args): |
|
18 r = subprocess.call(args) |
|
19 assert r == 0 |
|
20 |
|
21 |
|
22 def run_in(path, args): |
|
23 d = os.getcwd() |
|
24 os.chdir(path) |
|
25 check_run(args) |
|
26 os.chdir(d) |
|
27 |
|
28 |
|
29 def patch(patch, srcdir): |
|
30 patch = os.path.realpath(patch) |
|
31 check_run(['patch', '-d', srcdir, '-p1', '-i', patch, '--fuzz=0', |
|
32 '-s']) |
|
33 |
|
34 |
|
35 def build_package(package_source_dir, package_build_dir, configure_args, |
|
36 make_args): |
|
37 if not os.path.exists(package_build_dir): |
|
38 os.mkdir(package_build_dir) |
|
39 run_in(package_build_dir, |
|
40 ["%s/configure" % package_source_dir] + configure_args) |
|
41 run_in(package_build_dir, ["make", "-j4"] + make_args) |
|
42 run_in(package_build_dir, ["make", "install"]) |
|
43 |
|
44 |
|
45 def with_env(env, f): |
|
46 old_env = os.environ.copy() |
|
47 os.environ.update(env) |
|
48 f() |
|
49 os.environ.clear() |
|
50 os.environ.update(old_env) |
|
51 |
|
52 |
|
53 def build_tar_package(tar, name, base, directory): |
|
54 name = os.path.realpath(name) |
|
55 run_in(base, [tar, "-cjf", name, directory]) |
|
56 |
|
57 |
|
58 def svn_co(url, directory, revision): |
|
59 check_run(["svn", "co", "-r", revision, url, directory]) |
|
60 |
|
61 |
|
62 def build_one_stage(env, stage_dir, llvm_source_dir, gcc_toolchain_dir): |
|
63 def f(): |
|
64 build_one_stage_aux(stage_dir, llvm_source_dir, gcc_toolchain_dir) |
|
65 with_env(env, f) |
|
66 |
|
67 |
|
68 def build_tooltool_manifest(llvm_revision): |
|
69 basedir = os.path.split(os.path.realpath(sys.argv[0]))[0] |
|
70 tooltool = basedir + '/tooltool.py' |
|
71 setup = basedir + '/setup.sh' |
|
72 manifest = 'clang.manifest' |
|
73 check_run(['python', tooltool, '-m', manifest, 'add', |
|
74 setup, 'clang.tar.bz2']) |
|
75 data = json.load(file(manifest), object_pairs_hook=collections.OrderedDict) |
|
76 data = [{'clang_version': 'r%s' % llvm_revision}] + data |
|
77 out = file(manifest, 'w') |
|
78 json.dump(data, out, indent=0) |
|
79 out.write('\n') |
|
80 |
|
81 assert data[2]['filename'] == 'clang.tar.bz2' |
|
82 os.rename('clang.tar.bz2', data[2]['digest']) |
|
83 |
|
84 |
|
85 def get_platform(): |
|
86 p = platform.system() |
|
87 if p == "Darwin": |
|
88 return "macosx64" |
|
89 elif p == "Linux": |
|
90 if platform.processor() == "x86_64": |
|
91 return "linux64" |
|
92 else: |
|
93 return "linux32" |
|
94 else: |
|
95 raise NotImplementedError("Not supported platform") |
|
96 |
|
97 |
|
98 def is_darwin(): |
|
99 return platform.system() == "Darwin" |
|
100 |
|
101 |
|
102 def build_one_stage_aux(stage_dir, llvm_source_dir, gcc_toolchain_dir): |
|
103 os.mkdir(stage_dir) |
|
104 |
|
105 build_dir = stage_dir + "/build" |
|
106 inst_dir = stage_dir + "/clang" |
|
107 |
|
108 targets = ["x86", "x86_64"] |
|
109 # The Darwin equivalents of binutils appear to have intermittent problems |
|
110 # with objects in compiler-rt that are compiled for arm. Since the arm |
|
111 # support is only necessary for iOS (which we don't support), only enable |
|
112 # arm support on Linux. |
|
113 if not is_darwin(): |
|
114 targets.append("arm") |
|
115 |
|
116 configure_opts = ["--enable-optimized", |
|
117 "--enable-targets=" + ",".join(targets), |
|
118 "--disable-assertions", |
|
119 "--prefix=%s" % inst_dir, |
|
120 "--with-gcc-toolchain=%s" % gcc_toolchain_dir, |
|
121 "--disable-compiler-version-checks"] |
|
122 build_package(llvm_source_dir, build_dir, configure_opts, []) |
|
123 |
|
124 if __name__ == "__main__": |
|
125 # The directories end up in the debug info, so the easy way of getting |
|
126 # a reproducible build is to run it in a know absolute directory. |
|
127 # We use a directory in /builds/slave because the mozilla infrastructure |
|
128 # cleans it up automatically. |
|
129 base_dir = "/builds/slave/moz-toolchain" |
|
130 |
|
131 source_dir = base_dir + "/src" |
|
132 build_dir = base_dir + "/build" |
|
133 |
|
134 llvm_source_dir = source_dir + "/llvm" |
|
135 clang_source_dir = source_dir + "/clang" |
|
136 compiler_rt_source_dir = source_dir + "/compiler-rt" |
|
137 |
|
138 gcc_dir = "/tools/gcc-4.7.3-0moz1" |
|
139 |
|
140 if is_darwin(): |
|
141 os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.7' |
|
142 |
|
143 parser = argparse.ArgumentParser() |
|
144 parser.add_argument('-c', '--config', required=True, |
|
145 type=argparse.FileType('r'), |
|
146 help="Clang configuration file") |
|
147 |
|
148 args = parser.parse_args() |
|
149 config = json.load(args.config) |
|
150 llvm_revision = config["llvm_revision"] |
|
151 llvm_repo = config["llvm_repo"] |
|
152 clang_repo = config["clang_repo"] |
|
153 compiler_repo = config["compiler_repo"] |
|
154 |
|
155 if not os.path.exists(source_dir): |
|
156 os.makedirs(source_dir) |
|
157 svn_co(llvm_repo, llvm_source_dir, llvm_revision) |
|
158 svn_co(clang_repo, clang_source_dir, llvm_revision) |
|
159 svn_co(compiler_repo, compiler_rt_source_dir, llvm_revision) |
|
160 os.symlink("../../clang", llvm_source_dir + "/tools/clang") |
|
161 os.symlink("../../compiler-rt", |
|
162 llvm_source_dir + "/projects/compiler-rt") |
|
163 for p in config.get("patches", {}).get(get_platform(), []): |
|
164 patch(p, source_dir) |
|
165 |
|
166 if os.path.exists(build_dir): |
|
167 shutil.rmtree(build_dir) |
|
168 os.makedirs(build_dir) |
|
169 |
|
170 stage1_dir = build_dir + '/stage1' |
|
171 stage1_inst_dir = stage1_dir + '/clang' |
|
172 |
|
173 if is_darwin(): |
|
174 extra_cflags = "" |
|
175 extra_cxxflags = "" |
|
176 cc = "/usr/bin/clang" |
|
177 cxx = "/usr/bin/clang++" |
|
178 else: |
|
179 extra_cflags = "-static-libgcc" |
|
180 extra_cxxflags = "-static-libgcc -static-libstdc++" |
|
181 cc = gcc_dir + "/bin/gcc" |
|
182 cxx = gcc_dir + "/bin/g++" |
|
183 |
|
184 if os.environ.has_key('LD_LIBRARY_PATH'): |
|
185 os.environ['LD_LIBRARY_PATH'] = '%s/lib64/:%s' % (gcc_dir, os.environ['LD_LIBRARY_PATH']); |
|
186 else: |
|
187 os.environ['LD_LIBRARY_PATH'] = '%s/lib64/' % gcc_dir |
|
188 |
|
189 build_one_stage({"CC": cc, "CXX": cxx}, stage1_dir, llvm_source_dir, gcc_dir) |
|
190 |
|
191 stage2_dir = build_dir + '/stage2' |
|
192 build_one_stage( |
|
193 {"CC": stage1_inst_dir + "/bin/clang %s" % extra_cflags, |
|
194 "CXX": stage1_inst_dir + "/bin/clang++ %s" % extra_cxxflags}, |
|
195 stage2_dir, llvm_source_dir, gcc_dir) |
|
196 |
|
197 build_tar_package("tar", "clang.tar.bz2", stage2_dir, "clang") |
|
198 build_tooltool_manifest(llvm_revision) |