Skip to content

Commit

Permalink
BaseTools/Plugin/RustEnvironmentCheck: Add rust-src component check
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
makubacki committed Nov 4, 2023
1 parent bf28b45 commit 8feaeba
Showing 1 changed file with 79 additions and 12 deletions.
91 changes: 79 additions & 12 deletions BaseTools/Plugin/RustEnvironmentCheck/RustEnvironmentCheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"])

Expand Down Expand Up @@ -59,35 +61,45 @@ 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:
content = toml_file.read()
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,
Expand All @@ -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."

Expand Down Expand Up @@ -184,4 +248,7 @@ def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo:
f"{rust_toolchain_info.toolchain}-<host>\"")
errors += 1

if not verify_rust_src_component_is_installed():
errors += 1

return errors

0 comments on commit 8feaeba

Please sign in to comment.