From 8feaeba67256ecb1cd9bc65d9bd2e8f9acb40f10 Mon Sep 17 00:00:00 2001 From: Michael Kubacki Date: Fri, 3 Nov 2023 21:24:01 -0400 Subject: [PATCH] BaseTools/Plugin/RustEnvironmentCheck: Add rust-src component check Checks if the rust-src component is installed for the workspace toolchain. This is a basic requirement to build firmware code and not having rust-src can result in an obscure error during firmware build. Signed-off-by: Michael Kubacki --- .../RustEnvironmentCheck.py | 91 ++++++++++++++++--- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/BaseTools/Plugin/RustEnvironmentCheck/RustEnvironmentCheck.py b/BaseTools/Plugin/RustEnvironmentCheck/RustEnvironmentCheck.py index cd8f0b6ba1..989d95450c 100644 --- a/BaseTools/Plugin/RustEnvironmentCheck/RustEnvironmentCheck.py +++ b/BaseTools/Plugin/RustEnvironmentCheck/RustEnvironmentCheck.py @@ -27,6 +27,8 @@ from edk2toollib.utility_functions import RunCmd from io import StringIO +WORKSPACE_TOOLCHAIN_FILE = "rust-toolchain.toml" + RustToolInfo = namedtuple("RustToolInfo", ["presence_cmd", "install_help"]) RustToolChainInfo = namedtuple("RustToolChainInfo", ["error", "toolchain"]) @@ -59,19 +61,14 @@ def verify_cmd(name: str, params: str = "--version") -> bool: logging_level=logging.DEBUG) return ret == 0 - def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo: - """Verifies the rust toolchain used in the workspace is available. - - Note: This function does not use the toml library to parse the toml - file since the file is very simple and its not desirable to add the - toml module as a dependency. + def get_workspace_toolchain_version() -> RustToolChainInfo: + """Returns the rust toolchain version specified in the workspace + toolchain file. Returns: - RustToolChainInfo: A tuple that indicates if the toolchain is - available and any the toolchain version if found. + RustToolChainInfo: The rust toolchain information. If an error + occurs, the error field will be True with no toolchain info. """ - WORKSPACE_TOOLCHAIN_FILE = "rust-toolchain.toml" - toolchain_version = None try: with open(WORKSPACE_TOOLCHAIN_FILE, 'r') as toml_file: @@ -79,15 +76,30 @@ def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo: match = re.search(r'channel\s*=\s*"([^"]+)"', content) if match: toolchain_version = match.group(1) + return RustToolChainInfo(error=False, toolchain=toolchain_version) except FileNotFoundError: # If a file is not found. Do not check any further. - return RustToolChainInfo(error=False, toolchain=None) + return RustToolChainInfo(error=True, toolchain=None) + + def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo: + """Verifies the rust toolchain used in the workspace is available. + + Note: This function does not use the toml library to parse the toml + file since the file is very simple and its not desirable to add the + toml module as a dependency. - if not toolchain_version: + Returns: + RustToolChainInfo: A tuple that indicates if the toolchain is + available and any the toolchain version if found. + """ + toolchain_version = get_workspace_toolchain_version() + if toolchain_version.error or not toolchain_version: # If the file is not in an expected format, let that be handled # elsewhere and do not look further. return RustToolChainInfo(error=False, toolchain=None) + toolchain_version = toolchain_version.toolchain + installed_toolchains = StringIO() ret = RunCmd("rustup", "toolchain list", outstream=installed_toolchains, @@ -104,6 +116,58 @@ def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo: for toolchain in installed_toolchains), toolchain=toolchain_version) + def verify_rust_src_component_is_installed() -> bool: + """Verifies the rust-src component is installed. + + Returns: + bool: True if the rust-src component is installed for the default + toolchain or the status could not be determined, otherwise, False. + """ + toolchain_version = get_workspace_toolchain_version() + if toolchain_version.error or not toolchain_version: + # If the file is not in an expected format, let that be handled + # elsewhere and do not look further. + return True + + toolchain_version = toolchain_version.toolchain + + rustup_output = StringIO() + ret = RunCmd("rustc", "--version --verbose", + outstream=rustup_output, + logging_level=logging.DEBUG) + if ret != 0: + # rustc installation is checked elsewhere. Exit here on failure. + return True + + for line in rustup_output.getvalue().splitlines(): + start_index = line.lower().strip().find("host: ") + if start_index != -1: + target_triple = line[start_index + len("host: "):] + break + else: + logging.error("Failed to get host target triple information.") + return False + + rustup_output = StringIO() + ret = RunCmd("rustup", f"component list --toolchain {toolchain_version}", + outstream=rustup_output, + logging_level=logging.DEBUG) + if ret != 0: + # rustup installation and the toolchain are checked elsewhere. + # Exit here on failure. + return True + + for component in rustup_output.getvalue().splitlines(): + if "rust-src (installed)" in component: + return True + + logging.error("The Rust toolchain is installed but the rust-src component " + "needs to be installed:\n\n" + f" rustup component add --toolchain {toolchain_version}-" + f"{target_triple} rust-src") + + return False + generic_rust_install_instructions = \ "Visit https://rustup.rs/ to install Rust and cargo." @@ -184,4 +248,7 @@ def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo: f"{rust_toolchain_info.toolchain}-\"") errors += 1 + if not verify_rust_src_component_is_installed(): + errors += 1 + return errors