]>
git.proxmox.com Git - rustc.git/blob - src/bootstrap/bootstrap.py
1 from __future__
import absolute_import
, division
, print_function
17 def get(url
, path
, verbose
=False):
19 sha_url
= url
+ suffix
20 with tempfile
.NamedTemporaryFile(delete
=False) as temp_file
:
21 temp_path
= temp_file
.name
22 with tempfile
.NamedTemporaryFile(suffix
=suffix
, delete
=False) as sha_file
:
23 sha_path
= sha_file
.name
26 download(sha_path
, sha_url
, False, verbose
)
27 if os
.path
.exists(path
):
28 if verify(path
, sha_path
, False):
30 print("using already-download file", path
)
34 print("ignoring already-download file",
35 path
, "due to failed verification")
37 download(temp_path
, url
, True, verbose
)
38 if not verify(temp_path
, sha_path
, verbose
):
39 raise RuntimeError("failed verification")
41 print("moving {} to {}".format(temp_path
, path
))
42 shutil
.move(temp_path
, path
)
44 delete_if_present(sha_path
, verbose
)
45 delete_if_present(temp_path
, verbose
)
48 def delete_if_present(path
, verbose
):
49 """Remove the given file if present"""
50 if os
.path
.isfile(path
):
52 print("removing", path
)
56 def download(path
, url
, probably_big
, verbose
):
59 _download(path
, url
, probably_big
, verbose
, True)
62 print("\nspurious failure, trying again")
63 _download(path
, url
, probably_big
, verbose
, False)
66 def _download(path
, url
, probably_big
, verbose
, exception
):
67 if probably_big
or verbose
:
68 print("downloading {}".format(url
))
69 # see http://serverfault.com/questions/301128/how-to-download
70 if sys
.platform
== 'win32':
71 run(["PowerShell.exe", "/nologo", "-Command",
72 "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
73 "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url
, path
)],
77 if probably_big
or verbose
:
82 "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds
83 "--connect-timeout", "30", # timeout if cannot connect within 30 seconds
84 "--retry", "3", "-Sf", "-o", path
, url
],
89 def verify(path
, sha_path
, verbose
):
90 """Check if the sha256 sum of the given path is valid"""
92 print("verifying", path
)
93 with
open(path
, "rb") as source
:
94 found
= hashlib
.sha256(source
.read()).hexdigest()
95 with
open(sha_path
, "r") as sha256sum
:
96 expected
= sha256sum
.readline().split()[0]
97 verified
= found
== expected
99 print("invalid checksum:\n"
101 " expected: {}".format(found
, expected
))
105 def unpack(tarball
, dst
, verbose
=False, match
=None):
106 """Unpack the given tarball file"""
107 print("extracting", tarball
)
108 fname
= os
.path
.basename(tarball
).replace(".tar.gz", "")
109 with contextlib
.closing(tarfile
.open(tarball
)) as tar
:
110 for member
in tar
.getnames():
111 if "/" not in member
:
113 name
= member
.replace(fname
+ "/", "", 1)
114 if match
is not None and not name
.startswith(match
):
116 name
= name
[len(match
) + 1:]
118 dst_path
= os
.path
.join(dst
, name
)
120 print(" extracting", member
)
121 tar
.extract(member
, dst
)
122 src_path
= os
.path
.join(dst
, member
)
123 if os
.path
.isdir(src_path
) and os
.path
.exists(dst_path
):
125 shutil
.move(src_path
, dst_path
)
126 shutil
.rmtree(os
.path
.join(dst
, fname
))
129 def run(args
, verbose
=False, exception
=False, **kwargs
):
130 """Run a child program in a new process"""
132 print("running: " + ' '.join(args
))
134 # Use Popen here instead of call() as it apparently allows powershell on
135 # Windows to not lock up waiting for input presumably.
136 ret
= subprocess
.Popen(args
, **kwargs
)
139 err
= "failed to run: " + ' '.join(args
)
140 if verbose
or exception
:
141 raise RuntimeError(err
)
145 def stage0_data(rust_root
):
146 """Build a dictionary from stage0.txt"""
147 nightlies
= os
.path
.join(rust_root
, "src/stage0.txt")
148 with
open(nightlies
, 'r') as nightlies
:
149 lines
= [line
.rstrip() for line
in nightlies
150 if not line
.startswith("#")]
151 return dict([line
.split(": ", 1) for line
in lines
if line
])
154 def format_build_time(duration
):
155 """Return a nicer format for build time
157 >>> format_build_time('300')
160 return str(datetime
.timedelta(seconds
=int(duration
)))
163 def default_build_triple():
164 """Build triple as in LLVM"""
165 default_encoding
= sys
.getdefaultencoding()
167 ostype
= subprocess
.check_output(
168 ['uname', '-s']).strip().decode(default_encoding
)
169 cputype
= subprocess
.check_output(
170 ['uname', '-m']).strip().decode(default_encoding
)
171 except (subprocess
.CalledProcessError
, OSError):
172 if sys
.platform
== 'win32':
173 return 'x86_64-pc-windows-msvc'
174 err
= "uname not found"
177 # The goal here is to come up with the same triple as LLVM would,
178 # at least for the subset of platforms we're willing to target.
180 'Bitrig': 'unknown-bitrig',
181 'Darwin': 'apple-darwin',
182 'DragonFly': 'unknown-dragonfly',
183 'FreeBSD': 'unknown-freebsd',
184 'Haiku': 'unknown-haiku',
185 'NetBSD': 'unknown-netbsd',
186 'OpenBSD': 'unknown-openbsd'
189 # Consider the direct transformation first and then the special cases
190 if ostype
in ostype_mapper
:
191 ostype
= ostype_mapper
[ostype
]
192 elif ostype
== 'Linux':
193 os_from_sp
= subprocess
.check_output(
194 ['uname', '-o']).strip().decode(default_encoding
)
195 if os_from_sp
== 'Android':
196 ostype
= 'linux-android'
198 ostype
= 'unknown-linux-gnu'
199 elif ostype
== 'SunOS':
200 ostype
= 'sun-solaris'
201 # On Solaris, uname -m will return a machine classification instead
202 # of a cpu type, so uname -p is recommended instead. However, the
203 # output from that option is too generic for our purposes (it will
204 # always emit 'i386' on x86/amd64 systems). As such, isainfo -k
205 # must be used instead.
207 cputype
= subprocess
.check_output(
208 ['isainfo', '-k']).strip().decode(default_encoding
)
209 except (subprocess
.CalledProcessError
, OSError):
210 err
= "isainfo not found"
212 elif ostype
.startswith('MINGW'):
213 # msys' `uname` does not print gcc configuration, but prints msys
214 # configuration. so we cannot believe `uname -m`:
215 # msys1 is always i686 and msys2 is always x86_64.
216 # instead, msys defines $MSYSTEM which is MINGW32 on i686 and
218 ostype
= 'pc-windows-gnu'
220 if os
.environ
.get('MSYSTEM') == 'MINGW64':
222 elif ostype
.startswith('MSYS'):
223 ostype
= 'pc-windows-gnu'
224 elif ostype
.startswith('CYGWIN_NT'):
226 if ostype
.endswith('WOW64'):
228 ostype
= 'pc-windows-gnu'
230 err
= "unknown OS type: {}".format(ostype
)
233 if cputype
== 'powerpc' and ostype
== 'unknown-freebsd':
234 cputype
= subprocess
.check_output(
235 ['uname', '-p']).strip().decode(default_encoding
)
238 'aarch64': 'aarch64',
245 'powerpc': 'powerpc',
246 'powerpc64': 'powerpc64',
247 'powerpc64le': 'powerpc64le',
249 'ppc64': 'powerpc64',
250 'ppc64le': 'powerpc64le',
258 # Consider the direct transformation first and then the special cases
259 if cputype
in cputype_mapper
:
260 cputype
= cputype_mapper
[cputype
]
261 elif cputype
in {'xscale', 'arm'}:
263 if ostype
== 'linux-android':
264 ostype
= 'linux-androideabi'
265 elif cputype
== 'armv6l':
267 if ostype
== 'linux-android':
268 ostype
= 'linux-androideabi'
271 elif cputype
in {'armv7l', 'armv8l'}:
273 if ostype
== 'linux-android':
274 ostype
= 'linux-androideabi'
277 elif cputype
== 'mips':
278 if sys
.byteorder
== 'big':
280 elif sys
.byteorder
== 'little':
283 raise ValueError("unknown byteorder: {}".format(sys
.byteorder
))
284 elif cputype
== 'mips64':
285 if sys
.byteorder
== 'big':
287 elif sys
.byteorder
== 'little':
290 raise ValueError('unknown byteorder: {}'.format(sys
.byteorder
))
291 # only the n64 ABI is supported, indicate it
293 elif cputype
== 'sparc' or cputype
== 'sparcv9' or cputype
== 'sparc64':
296 err
= "unknown cpu type: {}".format(cputype
)
299 return "{}-{}".format(cputype
, ostype
)
302 @contextlib.contextmanager
303 def output(filepath
):
304 tmp
= filepath
+ '.tmp'
305 with
open(tmp
, 'w') as f
:
308 os
.remove(filepath
) # PermissionError/OSError on Win32 if in use
309 os
.rename(tmp
, filepath
)
311 shutil
.copy2(tmp
, filepath
)
315 class RustBuild(object):
316 """Provide all the methods required to build Rust"""
318 self
.cargo_channel
= ''
320 self
._download
_url
= 'https://static.rust-lang.org'
321 self
.rustc_channel
= ''
323 self
.build_dir
= os
.path
.join(os
.getcwd(), "build")
325 self
.config_toml
= ''
327 self
.use_locked_deps
= ''
328 self
.use_vendored_sources
= ''
331 def download_stage0(self
):
332 """Fetch the build system for Rust, written in Rust
334 This method will build a cache directory, then it will fetch the
335 tarball which has the stage0 compiler used to then bootstrap the Rust
338 Each downloaded tarball is extracted, after that, the script
339 will move all the content to the right place.
341 rustc_channel
= self
.rustc_channel
342 cargo_channel
= self
.cargo_channel
344 if self
.rustc().startswith(self
.bin_root()) and \
345 (not os
.path
.exists(self
.rustc()) or
346 self
.program_out_of_date(self
.rustc_stamp())):
347 if os
.path
.exists(self
.bin_root()):
348 shutil
.rmtree(self
.bin_root())
349 filename
= "rust-std-{}-{}.tar.gz".format(
350 rustc_channel
, self
.build
)
351 pattern
= "rust-std-{}".format(self
.build
)
352 self
._download
_stage
0_helper
(filename
, pattern
)
354 filename
= "rustc-{}-{}.tar.gz".format(rustc_channel
, self
.build
)
355 self
._download
_stage
0_helper
(filename
, "rustc")
356 self
.fix_executable("{}/bin/rustc".format(self
.bin_root()))
357 self
.fix_executable("{}/bin/rustdoc".format(self
.bin_root()))
358 with
output(self
.rustc_stamp()) as rust_stamp
:
359 rust_stamp
.write(self
.date
)
361 # This is required so that we don't mix incompatible MinGW
362 # libraries/binaries that are included in rust-std with
363 # the system MinGW ones.
364 if "pc-windows-gnu" in self
.build
:
365 filename
= "rust-mingw-{}-{}.tar.gz".format(
366 rustc_channel
, self
.build
)
367 self
._download
_stage
0_helper
(filename
, "rust-mingw")
369 if self
.cargo().startswith(self
.bin_root()) and \
370 (not os
.path
.exists(self
.cargo()) or
371 self
.program_out_of_date(self
.cargo_stamp())):
372 filename
= "cargo-{}-{}.tar.gz".format(cargo_channel
, self
.build
)
373 self
._download
_stage
0_helper
(filename
, "cargo")
374 self
.fix_executable("{}/bin/cargo".format(self
.bin_root()))
375 with
output(self
.cargo_stamp()) as cargo_stamp
:
376 cargo_stamp
.write(self
.date
)
378 def _download_stage0_helper(self
, filename
, pattern
):
379 cache_dst
= os
.path
.join(self
.build_dir
, "cache")
380 rustc_cache
= os
.path
.join(cache_dst
, self
.date
)
381 if not os
.path
.exists(rustc_cache
):
382 os
.makedirs(rustc_cache
)
384 url
= "{}/dist/{}".format(self
._download
_url
, self
.date
)
385 tarball
= os
.path
.join(rustc_cache
, filename
)
386 if not os
.path
.exists(tarball
):
387 get("{}/{}".format(url
, filename
), tarball
, verbose
=self
.verbose
)
388 unpack(tarball
, self
.bin_root(), match
=pattern
, verbose
=self
.verbose
)
391 def fix_executable(fname
):
392 """Modifies the interpreter section of 'fname' to fix the dynamic linker
394 This method is only required on NixOS and uses the PatchELF utility to
395 change the dynamic linker of ELF executables.
397 Please see https://nixos.org/patchelf.html for more information
399 default_encoding
= sys
.getdefaultencoding()
401 ostype
= subprocess
.check_output(
402 ['uname', '-s']).strip().decode(default_encoding
)
403 except subprocess
.CalledProcessError
:
405 except OSError as reason
:
406 if getattr(reason
, 'winerror', None) is not None:
410 if ostype
!= "Linux":
413 if not os
.path
.exists("/etc/NIXOS"):
415 if os
.path
.exists("/lib"):
418 # At this point we're pretty sure the user is running NixOS
419 nix_os_msg
= "info: you seem to be running NixOS. Attempting to patch"
420 print(nix_os_msg
, fname
)
423 interpreter
= subprocess
.check_output(
424 ["patchelf", "--print-interpreter", fname
])
425 interpreter
= interpreter
.strip().decode(default_encoding
)
426 except subprocess
.CalledProcessError
as reason
:
427 print("warning: failed to call patchelf:", reason
)
430 loader
= interpreter
.split("/")[-1]
433 ldd_output
= subprocess
.check_output(
434 ['ldd', '/run/current-system/sw/bin/sh'])
435 ldd_output
= ldd_output
.strip().decode(default_encoding
)
436 except subprocess
.CalledProcessError
as reason
:
437 print("warning: unable to call ldd:", reason
)
440 for line
in ldd_output
.splitlines():
441 libname
= line
.split()[0]
442 if libname
.endswith(loader
):
443 loader_path
= libname
[:len(libname
) - len(loader
)]
446 print("warning: unable to find the path to the dynamic linker")
449 correct_interpreter
= loader_path
+ loader
452 subprocess
.check_output(
453 ["patchelf", "--set-interpreter", correct_interpreter
, fname
])
454 except subprocess
.CalledProcessError
as reason
:
455 print("warning: failed to call patchelf:", reason
)
458 def rustc_stamp(self
):
459 """Return the path for .rustc-stamp
462 >>> rb.build_dir = "build"
463 >>> rb.rustc_stamp() == os.path.join("build", "stage0", ".rustc-stamp")
466 return os
.path
.join(self
.bin_root(), '.rustc-stamp')
468 def cargo_stamp(self
):
469 """Return the path for .cargo-stamp
472 >>> rb.build_dir = "build"
473 >>> rb.cargo_stamp() == os.path.join("build", "stage0", ".cargo-stamp")
476 return os
.path
.join(self
.bin_root(), '.cargo-stamp')
478 def program_out_of_date(self
, stamp_path
):
479 """Check if the given program stamp is out of date"""
480 if not os
.path
.exists(stamp_path
) or self
.clean
:
482 with
open(stamp_path
, 'r') as stamp
:
483 return self
.date
!= stamp
.read()
486 """Return the binary root directory
489 >>> rb.build_dir = "build"
490 >>> rb.bin_root() == os.path.join("build", "stage0")
493 When the 'build' property is given should be a nested directory:
495 >>> rb.build = "devel"
496 >>> rb.bin_root() == os.path.join("build", "devel", "stage0")
499 return os
.path
.join(self
.build_dir
, self
.build
, "stage0")
501 def get_toml(self
, key
, section
=None):
502 """Returns the value of the given key in config.toml, otherwise returns None
505 >>> rb.config_toml = 'key1 = "value1"\\nkey2 = "value2"'
506 >>> rb.get_toml("key2")
509 If the key does not exists, the result is None:
511 >>> rb.get_toml("key3") is None
514 Optionally also matches the section the key appears in
516 >>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"'
517 >>> rb.get_toml('key', 'a')
519 >>> rb.get_toml('key', 'b')
521 >>> rb.get_toml('key', 'c') is None
526 for line
in self
.config_toml
.splitlines():
527 section_match
= re
.match(r
'^\s*\[(.*)\]\s*$', line
)
528 if section_match
is not None:
529 cur_section
= section_match
.group(1)
531 match
= re
.match(r
'^{}\s*=(.*)$'.format(key
), line
)
532 if match
is not None:
533 value
= match
.group(1)
534 if section
is None or section
== cur_section
:
535 return self
.get_string(value
) or value
.strip()
539 """Return config path for cargo"""
540 return self
.program_config('cargo')
543 """Return config path for rustc"""
544 return self
.program_config('rustc')
546 def program_config(self
, program
):
547 """Return config path for the given program
550 >>> rb.config_toml = 'rustc = "rustc"\\n'
551 >>> rb.program_config('rustc')
553 >>> rb.config_toml = ''
554 >>> cargo_path = rb.program_config('cargo')
555 >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(),
559 config
= self
.get_toml(program
)
561 return os
.path
.expanduser(config
)
562 return os
.path
.join(self
.bin_root(), "bin", "{}{}".format(
563 program
, self
.exe_suffix()))
566 def get_string(line
):
567 """Return the value between double quotes
569 >>> RustBuild.get_string(' "devel" ')
572 start
= line
.find('"')
574 end
= start
+ 1 + line
[start
+ 1:].find('"')
575 return line
[start
+ 1:end
]
576 start
= line
.find('\'')
578 end
= start
+ 1 + line
[start
+ 1:].find('\'')
579 return line
[start
+ 1:end
]
584 """Return a suffix for executables"""
585 if sys
.platform
== 'win32':
589 def bootstrap_binary(self
):
590 """Return the path of the bootstrap binary
593 >>> rb.build_dir = "build"
594 >>> rb.bootstrap_binary() == os.path.join("build", "bootstrap",
595 ... "debug", "bootstrap")
598 return os
.path
.join(self
.build_dir
, "bootstrap", "debug", "bootstrap")
600 def build_bootstrap(self
):
601 """Build bootstrap"""
602 build_dir
= os
.path
.join(self
.build_dir
, "bootstrap")
603 if self
.clean
and os
.path
.exists(build_dir
):
604 shutil
.rmtree(build_dir
)
605 env
= os
.environ
.copy()
606 env
["RUSTC_BOOTSTRAP"] = '1'
607 env
["CARGO_TARGET_DIR"] = build_dir
608 env
["RUSTC"] = self
.rustc()
609 env
["LD_LIBRARY_PATH"] = os
.path
.join(self
.bin_root(), "lib") + \
610 (os
.pathsep
+ env
["LD_LIBRARY_PATH"]) \
611 if "LD_LIBRARY_PATH" in env
else ""
612 env
["DYLD_LIBRARY_PATH"] = os
.path
.join(self
.bin_root(), "lib") + \
613 (os
.pathsep
+ env
["DYLD_LIBRARY_PATH"]) \
614 if "DYLD_LIBRARY_PATH" in env
else ""
615 env
["LIBRARY_PATH"] = os
.path
.join(self
.bin_root(), "lib") + \
616 (os
.pathsep
+ env
["LIBRARY_PATH"]) \
617 if "LIBRARY_PATH" in env
else ""
618 env
["RUSTFLAGS"] = "-Cdebuginfo=2 "
620 build_section
= "target.{}".format(self
.build_triple())
622 if self
.get_toml("crt-static", build_section
) == "true":
623 target_features
+= ["+crt-static"]
624 elif self
.get_toml("crt-static", build_section
) == "false":
625 target_features
+= ["-crt-static"]
627 env
["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features
)) + " "
628 target_linker
= self
.get_toml("linker", build_section
)
629 if target_linker
is not None:
630 env
["RUSTFLAGS"] += "-C linker=" + target_linker
+ " "
632 env
["PATH"] = os
.path
.join(self
.bin_root(), "bin") + \
633 os
.pathsep
+ env
["PATH"]
634 if not os
.path
.isfile(self
.cargo()):
635 raise Exception("no cargo executable found at `{}`".format(
637 args
= [self
.cargo(), "build", "--manifest-path",
638 os
.path
.join(self
.rust_root
, "src/bootstrap/Cargo.toml")]
639 for _
in range(1, self
.verbose
):
640 args
.append("--verbose")
641 if self
.use_locked_deps
:
642 args
.append("--locked")
643 if self
.use_vendored_sources
:
644 args
.append("--frozen")
645 run(args
, env
=env
, verbose
=self
.verbose
)
647 def build_triple(self
):
648 """Build triple as in LLVM"""
649 config
= self
.get_toml('build')
652 return default_build_triple()
654 def check_submodule(self
, module
, slow_submodules
):
655 if not slow_submodules
:
656 checked_out
= subprocess
.Popen(["git", "rev-parse", "HEAD"],
657 cwd
=os
.path
.join(self
.rust_root
, module
),
658 stdout
=subprocess
.PIPE
)
663 def update_submodule(self
, module
, checked_out
, recorded_submodules
):
664 module_path
= os
.path
.join(self
.rust_root
, module
)
666 if checked_out
!= None:
667 default_encoding
= sys
.getdefaultencoding()
668 checked_out
= checked_out
.communicate()[0].decode(default_encoding
).strip()
669 if recorded_submodules
[module
] == checked_out
:
672 print("Updating submodule", module
)
674 run(["git", "submodule", "-q", "sync", module
],
675 cwd
=self
.rust_root
, verbose
=self
.verbose
)
676 run(["git", "submodule", "update",
677 "--init", "--recursive", "--progress", module
],
678 cwd
=self
.rust_root
, verbose
=self
.verbose
)
679 run(["git", "reset", "-q", "--hard"],
680 cwd
=module_path
, verbose
=self
.verbose
)
681 run(["git", "clean", "-qdfx"],
682 cwd
=module_path
, verbose
=self
.verbose
)
684 def update_submodules(self
):
685 """Update submodules"""
686 if (not os
.path
.exists(os
.path
.join(self
.rust_root
, ".git"))) or \
687 self
.get_toml('submodules') == "false":
689 slow_submodules
= self
.get_toml('fast-submodules') == "false"
692 print('Unconditionally updating all submodules')
694 print('Updating only changed submodules')
695 default_encoding
= sys
.getdefaultencoding()
696 submodules
= [s
.split(' ', 1)[1] for s
in subprocess
.check_output(
697 ["git", "config", "--file",
698 os
.path
.join(self
.rust_root
, ".gitmodules"),
699 "--get-regexp", "path"]
700 ).decode(default_encoding
).splitlines()]
701 filtered_submodules
= []
702 submodules_names
= []
703 for module
in submodules
:
704 if module
.endswith("llvm-project"):
705 if self
.get_toml('llvm-config') and self
.get_toml('lld') != 'true':
707 if module
.endswith("llvm-emscripten"):
708 backends
= self
.get_toml('codegen-backends')
709 if backends
is None or not 'emscripten' in backends
:
711 check
= self
.check_submodule(module
, slow_submodules
)
712 filtered_submodules
.append((module
, check
))
713 submodules_names
.append(module
)
714 recorded
= subprocess
.Popen(["git", "ls-tree", "HEAD"] + submodules_names
,
715 cwd
=self
.rust_root
, stdout
=subprocess
.PIPE
)
716 recorded
= recorded
.communicate()[0].decode(default_encoding
).strip().splitlines()
717 recorded_submodules
= {}
718 for data
in recorded
:
720 recorded_submodules
[data
[3]] = data
[2]
721 for module
in filtered_submodules
:
722 self
.update_submodule(module
[0], module
[1], recorded_submodules
)
723 print("Submodules updated in %.2f seconds" % (time() - start_time
))
725 def set_dev_environment(self
):
726 """Set download URL for development environment"""
727 self
._download
_url
= 'https://dev-static.rust-lang.org'
730 def bootstrap(help_triggered
):
731 """Configure, fetch, build and run the initial bootstrap"""
733 # If the user is asking for help, let them know that the whole download-and-build
734 # process has to happen before anything is printed out.
736 print("info: Downloading and building bootstrap before processing --help")
737 print(" command. See src/bootstrap/README.md for help with common")
740 parser
= argparse
.ArgumentParser(description
='Build rust')
741 parser
.add_argument('--config')
742 parser
.add_argument('--build')
743 parser
.add_argument('--src')
744 parser
.add_argument('--clean', action
='store_true')
745 parser
.add_argument('-v', '--verbose', action
='count', default
=0)
747 args
= [a
for a
in sys
.argv
if a
!= '-h' and a
!= '--help']
748 args
, _
= parser
.parse_known_args(args
)
750 # Configure initial bootstrap
752 build
.rust_root
= args
.src
or os
.path
.abspath(os
.path
.join(__file__
, '../../..'))
753 build
.verbose
= args
.verbose
754 build
.clean
= args
.clean
757 with
open(args
.config
or 'config.toml') as config
:
758 build
.config_toml
= config
.read()
759 except (OSError, IOError):
762 match
= re
.search(r
'\nverbose = (\d+)', build
.config_toml
)
763 if match
is not None:
764 build
.verbose
= max(build
.verbose
, int(match
.group(1)))
766 build
.use_vendored_sources
= '\nvendor = true' in build
.config_toml
768 build
.use_locked_deps
= '\nlocked-deps = true' in build
.config_toml
770 if 'SUDO_USER' in os
.environ
and not build
.use_vendored_sources
:
771 if os
.environ
.get('USER') != os
.environ
['SUDO_USER']:
772 build
.use_vendored_sources
= True
773 print('info: looks like you are running this command under `sudo`')
774 print(' and so in order to preserve your $HOME this will now')
775 print(' use vendored sources by default. Note that if this')
776 print(' does not work you should run a normal build first')
777 print(' before running a command like `sudo ./x.py install`')
779 if build
.use_vendored_sources
:
780 if not os
.path
.exists('.cargo'):
781 os
.makedirs('.cargo')
782 with
output('.cargo/config') as cargo_config
:
783 cargo_config
.write("""
785 replace-with = 'vendored-sources'
786 registry = 'https://example.com'
788 [source.vendored-sources]
789 directory = '{}/vendor'
790 """.format(build
.rust_root
))
792 if os
.path
.exists('.cargo'):
793 shutil
.rmtree('.cargo')
795 data
= stage0_data(build
.rust_root
)
796 build
.date
= data
['date']
797 build
.rustc_channel
= data
['rustc']
798 build
.cargo_channel
= data
['cargo']
801 build
.set_dev_environment()
803 build
.update_submodules()
805 # Fetch/build the bootstrap
806 build
.build
= args
.build
or build
.build_triple()
807 build
.download_stage0()
809 build
.build_bootstrap()
813 args
= [build
.bootstrap_binary()]
814 args
.extend(sys
.argv
[1:])
815 env
= os
.environ
.copy()
816 env
["BUILD"] = build
.build
817 env
["SRC"] = build
.rust_root
818 env
["BOOTSTRAP_PARENT_ID"] = str(os
.getpid())
819 env
["BOOTSTRAP_PYTHON"] = sys
.executable
820 env
["BUILD_DIR"] = build
.build_dir
821 env
["RUSTC_BOOTSTRAP"] = '1'
822 env
["CARGO"] = build
.cargo()
823 env
["RUSTC"] = build
.rustc()
824 run(args
, env
=env
, verbose
=build
.verbose
)
828 """Entry point for the bootstrap process"""
831 # x.py help <cmd> ...
832 if len(sys
.argv
) > 1 and sys
.argv
[1] == 'help':
833 sys
.argv
= sys
.argv
[:1] + [sys
.argv
[2], '-h'] + sys
.argv
[3:]
836 '-h' in sys
.argv
) or ('--help' in sys
.argv
) or (len(sys
.argv
) == 1)
838 bootstrap(help_triggered
)
839 if not help_triggered
:
840 print("Build completed successfully in {}".format(
841 format_build_time(time() - start_time
)))
842 except (SystemExit, KeyboardInterrupt) as error
:
843 if hasattr(error
, 'code') and isinstance(error
.code
, int):
844 exit_code
= error
.code
848 if not help_triggered
:
849 print("Build completed unsuccessfully in {}".format(
850 format_build_time(time() - start_time
)))
854 if __name__
== '__main__':