diff options
Diffstat (limited to 'src/bootstrap/bootstrap.py')
-rw-r--r-- | src/bootstrap/bootstrap.py | 172 |
1 files changed, 103 insertions, 69 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 58d1926ad..149350e62 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -323,6 +323,7 @@ def default_build_triple(verbose): cputype_mapper = { 'BePC': 'i686', 'aarch64': 'aarch64', + 'aarch64eb': 'aarch64', 'amd64': 'x86_64', 'arm64': 'aarch64', 'i386': 'i686', @@ -458,23 +459,51 @@ def unpack_component(download_info): verbose=download_info.verbose, ) -class RustBuild(object): - """Provide all the methods required to build Rust""" +class FakeArgs: + """Used for unit tests to avoid updating all call sites""" def __init__(self): - self.checksums_sha256 = {} - self.stage0_compiler = None - self.download_url = '' self.build = '' self.build_dir = '' self.clean = False - self.config_toml = '' - self.rust_root = '' - self.use_locked_deps = False - self.use_vendored_sources = False self.verbose = False + self.json_output = False + self.color = 'auto' + self.warnings = 'default' + +class RustBuild(object): + """Provide all the methods required to build Rust""" + def __init__(self, config_toml="", args=FakeArgs()): self.git_version = None self.nix_deps_dir = None self._should_fix_bins_and_dylibs = None + self.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) + + self.config_toml = config_toml + + self.clean = args.clean + self.json_output = args.json_output + self.verbose = args.verbose + self.color = args.color + self.warnings = args.warnings + + config_verbose_count = self.get_toml('verbose', 'build') + if config_verbose_count is not None: + self.verbose = max(self.verbose, int(config_verbose_count)) + + self.use_vendored_sources = self.get_toml('vendor', 'build') == 'true' + self.use_locked_deps = self.get_toml('locked-deps', 'build') == 'true' + + build_dir = args.build_dir or self.get_toml('build-dir', 'build') or 'build' + self.build_dir = os.path.abspath(build_dir) + + with open(os.path.join(self.rust_root, "src", "stage0.json")) as f: + data = json.load(f) + self.checksums_sha256 = data["checksums_sha256"] + self.stage0_compiler = Stage0Toolchain(data["compiler"]) + self.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"] + + self.build = args.build or self.build_triple() + def download_toolchain(self): """Fetch the build system for Rust, written in Rust @@ -620,7 +649,7 @@ class RustBuild(object): # The latter one does not exist on NixOS when using tmpfs as root. try: with open("/etc/os-release", "r") as f: - if not any(l.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') for l in f): + if not any(ln.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') for ln in f): return False except FileNotFoundError: return False @@ -704,9 +733,10 @@ class RustBuild(object): """Return the path for .rustc-stamp at the given stage >>> rb = RustBuild() + >>> rb.build = "host" >>> rb.build_dir = "build" - >>> rb.rustc_stamp() == os.path.join("build", "stage0", ".rustc-stamp") - True + >>> expected = os.path.join("build", "host", "stage0", ".rustc-stamp") + >>> assert rb.rustc_stamp() == expected, rb.rustc_stamp() """ return os.path.join(self.bin_root(), '.rustc-stamp') @@ -721,15 +751,9 @@ class RustBuild(object): """Return the binary root directory for the given stage >>> rb = RustBuild() - >>> rb.build_dir = "build" - >>> rb.bin_root() == os.path.join("build", "stage0") - True - - When the 'build' property is given should be a nested directory: - >>> rb.build = "devel" - >>> rb.bin_root() == os.path.join("build", "devel", "stage0") - True + >>> expected = os.path.abspath(os.path.join("build", "devel", "stage0")) + >>> assert rb.bin_root() == expected, rb.bin_root() """ subdir = "stage0" return os.path.join(self.build_dir, self.build, subdir) @@ -761,9 +785,12 @@ class RustBuild(object): >>> rb.get_toml("key1") 'true' """ + return RustBuild.get_toml_static(self.config_toml, key, section) + @staticmethod + def get_toml_static(config_toml, key, section=None): cur_section = None - for line in self.config_toml.splitlines(): + for line in config_toml.splitlines(): section_match = re.match(r'^\s*\[(.*)\]\s*$', line) if section_match is not None: cur_section = section_match.group(1) @@ -772,7 +799,7 @@ class RustBuild(object): if match is not None: value = match.group(1) if section is None or section == cur_section: - return self.get_string(value) or value.strip() + return RustBuild.get_string(value) or value.strip() return None def cargo(self): @@ -835,13 +862,23 @@ class RustBuild(object): """ return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap") - def build_bootstrap(self, color, verbose_count): + def build_bootstrap(self): """Build bootstrap""" env = os.environ.copy() if "GITHUB_ACTIONS" in env: print("::group::Building bootstrap") else: print("Building bootstrap", file=sys.stderr) + + args = self.build_bootstrap_cmd(env) + # Run this from the source directory so cargo finds .cargo/config + run(args, env=env, verbose=self.verbose, cwd=self.rust_root) + + if "GITHUB_ACTIONS" in env: + print("::endgroup::") + + def build_bootstrap_cmd(self, env): + """For tests.""" build_dir = os.path.join(self.build_dir, "bootstrap") if self.clean and os.path.exists(build_dir): shutil.rmtree(build_dir) @@ -872,11 +909,17 @@ class RustBuild(object): } for var_name, toml_key in var_data.items(): toml_val = self.get_toml(toml_key, build_section) - if toml_val != None: + if toml_val is not None: env["{}_{}".format(var_name, host_triple_sanitized)] = toml_val # preserve existing RUSTFLAGS env.setdefault("RUSTFLAGS", "") + # we need to explicitly add +xgot here so that we can successfully bootstrap + # a usable stage1 compiler + # FIXME: remove this if condition on the next bootstrap bump + # cfg(bootstrap) + if self.build_triple().startswith('mips'): + env["RUSTFLAGS"] += " -Ctarget-feature=+xgot" target_features = [] if self.get_toml("crt-static", build_section) == "true": target_features += ["+crt-static"] @@ -888,7 +931,11 @@ class RustBuild(object): if target_linker is not None: env["RUSTFLAGS"] += " -C linker=" + target_linker env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes" - if self.get_toml("deny-warnings", "rust") != "false": + if self.warnings == "default": + deny_warnings = self.get_toml("deny-warnings", "rust") != "false" + else: + deny_warnings = self.warnings == "deny" + if deny_warnings: env["RUSTFLAGS"] += " -Dwarnings" env["PATH"] = os.path.join(self.bin_root(), "bin") + \ @@ -898,7 +945,7 @@ class RustBuild(object): self.cargo())) args = [self.cargo(), "build", "--manifest-path", os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")] - args.extend("--verbose" for _ in range(verbose_count)) + args.extend("--verbose" for _ in range(self.verbose)) if self.use_locked_deps: args.append("--locked") if self.use_vendored_sources: @@ -908,16 +955,16 @@ class RustBuild(object): args.append("build-metrics") if self.json_output: args.append("--message-format=json") - if color == "always": + if self.color == "always": args.append("--color=always") - elif color == "never": + elif self.color == "never": args.append("--color=never") + try: + args += env["CARGOFLAGS"].split() + except KeyError: + pass - # Run this from the source directory so cargo finds .cargo/config - run(args, env=env, verbose=self.verbose, cwd=self.rust_root) - - if "GITHUB_ACTIONS" in env: - print("::endgroup::") + return args def build_triple(self): """Build triple as in LLVM @@ -967,7 +1014,7 @@ class RustBuild(object): if os.path.exists(cargo_dir): shutil.rmtree(cargo_dir) -def parse_args(): +def parse_args(args): """Parse the command line arguments that the python script needs.""" parser = argparse.ArgumentParser(add_help=False) parser.add_argument('-h', '--help', action='store_true') @@ -977,18 +1024,14 @@ def parse_args(): parser.add_argument('--color', choices=['always', 'never', 'auto']) parser.add_argument('--clean', action='store_true') parser.add_argument('--json-output', action='store_true') + parser.add_argument('--warnings', choices=['deny', 'warn', 'default'], default='default') parser.add_argument('-v', '--verbose', action='count', default=0) - return parser.parse_known_args(sys.argv)[0] + return parser.parse_known_args(args)[0] def bootstrap(args): """Configure, fetch, build and run the initial bootstrap""" - # Configure initial bootstrap - build = RustBuild() - build.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) - build.verbose = args.verbose != 0 - build.clean = args.clean - build.json_output = args.json_output + rust_root = os.path.abspath(os.path.join(__file__, '../../..')) # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, # then `config.toml` in the root directory. @@ -997,52 +1040,43 @@ def bootstrap(args): if using_default_path: toml_path = 'config.toml' if not os.path.exists(toml_path): - toml_path = os.path.join(build.rust_root, toml_path) + toml_path = os.path.join(rust_root, toml_path) # Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path, # but not if `config.toml` hasn't been created. if not using_default_path or os.path.exists(toml_path): with open(toml_path) as config: - build.config_toml = config.read() + config_toml = config.read() + else: + config_toml = '' - profile = build.get_toml('profile') + profile = RustBuild.get_toml_static(config_toml, 'profile') if profile is not None: - include_file = 'config.{}.toml'.format(profile) - include_dir = os.path.join(build.rust_root, 'src', 'bootstrap', 'defaults') + # Allows creating alias for profile names, allowing + # profiles to be renamed while maintaining back compatibility + # Keep in sync with `profile_aliases` in config.rs + profile_aliases = { + "user": "dist" + } + include_file = 'config.{}.toml'.format(profile_aliases.get(profile) or profile) + include_dir = os.path.join(rust_root, 'src', 'bootstrap', 'defaults') include_path = os.path.join(include_dir, include_file) - # HACK: This works because `build.get_toml()` returns the first match it finds for a + # HACK: This works because `self.get_toml()` returns the first match it finds for a # specific key, so appending our defaults at the end allows the user to override them with open(include_path) as included_toml: - build.config_toml += os.linesep + included_toml.read() - - verbose_count = args.verbose - config_verbose_count = build.get_toml('verbose', 'build') - if config_verbose_count is not None: - verbose_count = max(args.verbose, int(config_verbose_count)) - - build.use_vendored_sources = build.get_toml('vendor', 'build') == 'true' - build.use_locked_deps = build.get_toml('locked-deps', 'build') == 'true' + config_toml += os.linesep + included_toml.read() + # Configure initial bootstrap + build = RustBuild(config_toml, args) build.check_vendored_status() - build_dir = args.build_dir or build.get_toml('build-dir', 'build') or 'build' - build.build_dir = os.path.abspath(build_dir) - - with open(os.path.join(build.rust_root, "src", "stage0.json")) as f: - data = json.load(f) - build.checksums_sha256 = data["checksums_sha256"] - build.stage0_compiler = Stage0Toolchain(data["compiler"]) - build.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"] - - build.build = args.build or build.build_triple() - if not os.path.exists(build.build_dir): os.makedirs(build.build_dir) # Fetch/build the bootstrap build.download_toolchain() sys.stdout.flush() - build.build_bootstrap(args.color, verbose_count) + build.build_bootstrap() sys.stdout.flush() # Run the bootstrap @@ -1062,7 +1096,7 @@ def main(): if len(sys.argv) > 1 and sys.argv[1] == 'help': sys.argv[1] = '-h' - args = parse_args() + args = parse_args(sys.argv) help_triggered = args.help or len(sys.argv) == 1 # If the user is asking for help, let them know that the whole download-and-build |