]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/bootstrap.py
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / bootstrap / bootstrap.py
CommitLineData
7453a54e
SL
1# Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
2# file at the top-level directory of this distribution and at
3# http://rust-lang.org/COPYRIGHT.
4#
5# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8# option. This file may not be copied, modified, or distributed
9# except according to those terms.
10
11import argparse
12import contextlib
13import os
14import shutil
15import subprocess
16import sys
17import tarfile
18
19def get(url, path, verbose=False):
20 print("downloading " + url)
21 # see http://serverfault.com/questions/301128/how-to-download
22 if sys.platform == 'win32':
23 run(["PowerShell.exe", "/nologo", "-Command",
24 "(New-Object System.Net.WebClient).DownloadFile('" + url +
25 "', '" + path + "')"], verbose=verbose)
26 else:
27 run(["curl", "-o", path, url], verbose=verbose)
28
29def unpack(tarball, dst, verbose=False, match=None):
30 print("extracting " + tarball)
31 fname = os.path.basename(tarball).replace(".tar.gz", "")
32 with contextlib.closing(tarfile.open(tarball)) as tar:
33 for p in tar.getnames():
34 if "/" not in p:
35 continue
36 name = p.replace(fname + "/", "", 1)
37 if match is not None and not name.startswith(match):
38 continue
39 name = name[len(match) + 1:]
40
41 fp = os.path.join(dst, name)
42 if verbose:
43 print(" extracting " + p)
44 tar.extract(p, dst)
45 tp = os.path.join(dst, p)
46 if os.path.isdir(tp) and os.path.exists(fp):
47 continue
48 shutil.move(tp, fp)
49 shutil.rmtree(os.path.join(dst, fname))
50
51def run(args, verbose=False):
52 if verbose:
53 print("running: " + ' '.join(args))
54 sys.stdout.flush()
55 # Use Popen here instead of call() as it apparently allows powershell on
56 # Windows to not lock up waiting for input presumably.
57 ret = subprocess.Popen(args)
58 code = ret.wait()
59 if code != 0:
60 if not verbose:
61 print("failed to run: " + ' '.join(args))
62 raise RuntimeError("failed to run command")
63
64class RustBuild:
65 def download_rust_nightly(self):
66 cache_dst = os.path.join(self.build_dir, "cache")
67 rustc_cache = os.path.join(cache_dst, self.snap_rustc_date())
68 cargo_cache = os.path.join(cache_dst, self.snap_cargo_date())
69 if not os.path.exists(rustc_cache):
70 os.makedirs(rustc_cache)
71 if not os.path.exists(cargo_cache):
72 os.makedirs(cargo_cache)
73
74 if self.rustc().startswith(self.bin_root()) and \
75 (not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
54a0048b
SL
76 if os.path.exists(self.bin_root()):
77 shutil.rmtree(self.bin_root())
7453a54e
SL
78 filename = "rust-std-nightly-" + self.build + ".tar.gz"
79 url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date()
80 tarball = os.path.join(rustc_cache, filename)
81 if not os.path.exists(tarball):
82 get(url + "/" + filename, tarball, verbose=self.verbose)
83 unpack(tarball, self.bin_root(),
84 match="rust-std-" + self.build,
85 verbose=self.verbose)
86
87 filename = "rustc-nightly-" + self.build + ".tar.gz"
88 url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date()
89 tarball = os.path.join(rustc_cache, filename)
90 if not os.path.exists(tarball):
91 get(url + "/" + filename, tarball, verbose=self.verbose)
92 unpack(tarball, self.bin_root(), match="rustc", verbose=self.verbose)
93 with open(self.rustc_stamp(), 'w') as f:
94 f.write(self.snap_rustc_date())
95
96 if self.cargo().startswith(self.bin_root()) and \
97 (not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
98 filename = "cargo-nightly-" + self.build + ".tar.gz"
99 url = "https://static.rust-lang.org/cargo-dist/" + self.snap_cargo_date()
100 tarball = os.path.join(cargo_cache, filename)
101 if not os.path.exists(tarball):
102 get(url + "/" + filename, tarball, verbose=self.verbose)
103 unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose)
104 with open(self.cargo_stamp(), 'w') as f:
105 f.write(self.snap_cargo_date())
106
107 def snap_cargo_date(self):
108 return self._cargo_date
109
110 def snap_rustc_date(self):
111 return self._rustc_date
112
113 def rustc_stamp(self):
114 return os.path.join(self.bin_root(), '.rustc-stamp')
115
116 def cargo_stamp(self):
117 return os.path.join(self.bin_root(), '.cargo-stamp')
118
119 def rustc_out_of_date(self):
120 if not os.path.exists(self.rustc_stamp()):
121 return True
122 with open(self.rustc_stamp(), 'r') as f:
123 return self.snap_rustc_date() != f.read()
124
125 def cargo_out_of_date(self):
126 if not os.path.exists(self.cargo_stamp()):
127 return True
128 with open(self.cargo_stamp(), 'r') as f:
129 return self.snap_cargo_date() != f.read()
130
131 def bin_root(self):
132 return os.path.join(self.build_dir, self.build, "stage0")
133
134 def get_toml(self, key):
135 for line in self.config_toml.splitlines():
136 if line.startswith(key + ' ='):
137 return self.get_string(line)
138 return None
139
140 def get_mk(self, key):
141 for line in iter(self.config_mk.splitlines()):
142 if line.startswith(key):
143 return line[line.find(':=') + 2:].strip()
144 return None
145
146 def cargo(self):
147 config = self.get_toml('cargo')
148 if config:
149 return config
150 return os.path.join(self.bin_root(), "bin/cargo" + self.exe_suffix())
151
152 def rustc(self):
153 config = self.get_toml('rustc')
154 if config:
155 return config
156 config = self.get_mk('CFG_LOCAL_RUST')
157 if config:
158 return config + '/bin/rustc' + self.exe_suffix()
159 return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix())
160
161 def get_string(self, line):
162 start = line.find('"')
163 end = start + 1 + line[start+1:].find('"')
164 return line[start+1:end]
165
166 def exe_suffix(self):
167 if sys.platform == 'win32':
168 return '.exe'
169 else:
170 return ''
171
172 def parse_nightly_dates(self):
173 nightlies = os.path.join(self.rust_root, "src/nightlies.txt")
174 with open(nightlies, 'r') as nightlies:
175 rustc, cargo = nightlies.read().split("\n")[:2]
176 assert rustc.startswith("rustc: ")
177 assert cargo.startswith("cargo: ")
178 self._rustc_date = rustc[len("rustc: "):]
179 self._cargo_date = cargo[len("cargo: "):]
180
181 def build_bootstrap(self):
182 env = os.environ.copy()
183 env["CARGO_TARGET_DIR"] = os.path.join(self.build_dir, "bootstrap")
184 env["RUSTC"] = self.rustc()
185 env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
186 env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
187 env["PATH"] = os.path.join(self.bin_root(), "bin") + \
188 os.pathsep + env["PATH"]
189 self.run([self.cargo(), "build", "--manifest-path",
190 os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")],
191 env)
192
193 def run(self, args, env):
194 proc = subprocess.Popen(args, env = env)
195 ret = proc.wait()
196 if ret != 0:
197 sys.exit(ret)
198
199 def build_triple(self):
200 config = self.get_toml('build')
201 if config:
202 return config
203 config = self.get_mk('CFG_BUILD')
204 if config:
205 return config
206 try:
207 ostype = subprocess.check_output(['uname', '-s']).strip()
208 cputype = subprocess.check_output(['uname', '-m']).strip()
209 except FileNotFoundError:
210 if sys.platform == 'win32':
211 return 'x86_64-pc-windows-msvc'
212 else:
213 raise
214
215 # Darwin's `uname -s` lies and always returns i386. We have to use
216 # sysctl instead.
217 if ostype == 'Darwin' and cputype == 'i686':
218 sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64'])
219 if sysctl.contains(': 1'):
220 cputype = 'x86_64'
221
222 # The goal here is to come up with the same triple as LLVM would,
223 # at least for the subset of platforms we're willing to target.
224 if ostype == 'Linux':
225 ostype = 'unknown-linux-gnu'
226 elif ostype == 'FreeBSD':
227 ostype = 'unknown-freebsd'
228 elif ostype == 'DragonFly':
229 ostype = 'unknown-dragonfly'
230 elif ostype == 'Bitrig':
231 ostype = 'unknown-bitrig'
232 elif ostype == 'OpenBSD':
233 ostype = 'unknown-openbsd'
234 elif ostype == 'NetBSD':
235 ostype = 'unknown-netbsd'
236 elif ostype == 'Darwin':
237 ostype = 'apple-darwin'
238 elif ostype.startswith('MINGW'):
239 # msys' `uname` does not print gcc configuration, but prints msys
240 # configuration. so we cannot believe `uname -m`:
241 # msys1 is always i686 and msys2 is always x86_64.
242 # instead, msys defines $MSYSTEM which is MINGW32 on i686 and
243 # MINGW64 on x86_64.
244 ostype = 'pc-windows-gnu'
245 cputype = 'i686'
246 if os.environ.get('MSYSTEM') == 'MINGW64':
247 cputype = 'x86_64'
248 elif ostype.startswith('MSYS'):
249 ostype = 'pc-windows-gnu'
250 elif ostype.startswith('CYGWIN_NT'):
251 cputype = 'i686'
252 if ostype.endswith('WOW64'):
253 cputype = 'x86_64'
254 ostype = 'pc-windows-gnu'
255 else:
256 raise ValueError("unknown OS type: " + ostype)
257
258 if cputype in {'i386', 'i486', 'i686', 'i786', 'x86'}:
259 cputype = 'i686'
260 elif cputype in {'xscale', 'arm'}:
261 cputype = 'arm'
262 elif cputype == 'armv7l':
263 cputype = 'arm'
264 ostype += 'eabihf'
265 elif cputype == 'aarch64':
266 cputype = 'aarch64'
267 elif cputype in {'powerpc', 'ppc', 'ppc64'}:
268 cputype = 'powerpc'
269 elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}:
270 cputype = 'x86_64'
271 else:
272 raise ValueError("unknown cpu type: " + cputype)
273
274 return cputype + '-' + ostype
275
276parser = argparse.ArgumentParser(description='Build rust')
277parser.add_argument('--config')
278parser.add_argument('-v', '--verbose', action='store_true')
279
280args = [a for a in sys.argv if a != '-h']
281args, _ = parser.parse_known_args(args)
282
283# Configure initial bootstrap
284rb = RustBuild()
285rb.config_toml = ''
286rb.config_mk = ''
287rb.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
288rb.build_dir = os.path.join(os.getcwd(), "build")
289rb.verbose = args.verbose
290
291try:
292 with open(args.config or 'config.toml') as config:
293 rb.config_toml = config.read()
294except:
295 pass
296try:
297 rb.config_mk = open('config.mk').read()
298except:
299 pass
300
301# Fetch/build the bootstrap
302rb.build = rb.build_triple()
303rb.parse_nightly_dates()
304rb.download_rust_nightly()
305sys.stdout.flush()
306rb.build_bootstrap()
307sys.stdout.flush()
308
309# Run the bootstrap
310args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")]
311args.extend(sys.argv[1:])
312args.append('--src')
313args.append(rb.rust_root)
314args.append('--build')
315args.append(rb.build)
316env = os.environ.copy()
317env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
318rb.run(args, env)