Skip to content

Commit

Permalink
Make get_host_triple public to get a triple from Bazel's repository_c…
Browse files Browse the repository at this point in the history
…tx (#1289)

I found half-baked duplicate implementations of this logic in
cargo-raze, in cxx, and in rules_rust's test suite of the
load_arbitrary_tool function. It seems such logic is necessary for
correctly using load_arbitrary_tool from the implementation of a
repository_rule.
  • Loading branch information
dtolnay committed Apr 26, 2022
1 parent 612f436 commit 58627f5
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 121 deletions.
3 changes: 2 additions & 1 deletion cargo/cargo_bootstrap.bzl
@@ -1,7 +1,8 @@
"""The `cargo_bootstrap` rule is used for bootstrapping cargo binaries in a repository rule."""

load("//cargo/private:cargo_utils.bzl", "get_host_triple", "get_rust_tools")
load("//cargo/private:cargo_utils.bzl", "get_rust_tools")
load("//rust:defs.bzl", "rust_common")
load("//rust/platform:triple.bzl", "get_host_triple")

_CARGO_BUILD_MODES = [
"release",
Expand Down
102 changes: 0 additions & 102 deletions cargo/private/cargo_utils.bzl
@@ -1,109 +1,7 @@
"""Utility functions for the cargo rules"""

load("//rust/platform:triple.bzl", "triple")
load("//rust/platform:triple_mappings.bzl", "system_to_binary_ext")

_CPU_ARCH_ERROR_MSG = """\
Command failed with exit code '{code}': {args}
----------stdout:
{stdout}
----------stderr:
{stderr}
"""

def _query_cpu_architecture(repository_ctx, expected_archs, is_windows = False):
"""Detect the host CPU architecture
Args:
repository_ctx (repository_ctx): The repository rule's context object
expected_archs (list): A list of expected architecture strings
is_windows (bool, optional): If true, the cpu lookup will use the windows method (`wmic` vs `uname`)
Returns:
str: The host's CPU architecture
"""
if is_windows:
arguments = ["wmic", "os", "get", "osarchitecture"]
else:
arguments = ["uname", "-m"]

result = repository_ctx.execute(arguments)

if result.return_code:
fail(_CPU_ARCH_ERROR_MSG.format(
code = result.return_code,
args = arguments,
stdout = result.stdout,
stderr = result.stderr,
))

if is_windows:
# Example output:
# OSArchitecture
# 64-bit
lines = result.stdout.split("\n")
arch = lines[1].strip()

# Translate 64-bit to a compatible rust platform
# https://doc.rust-lang.org/nightly/rustc/platform-support.html
if arch == "64-bit":
arch = "x86_64"
else:
arch = result.stdout.strip("\n")

# Correct the arm architecture for macos
if "mac" in repository_ctx.os.name and arch == "arm64":
arch = "aarch64"

if not arch in expected_archs:
fail("{} is not a expected cpu architecture {}\n{}".format(
arch,
expected_archs,
result.stdout,
))

return arch

def get_host_triple(repository_ctx, abi = None):
"""Query host information for the appropriate triples for the crate_universe resolver
Args:
repository_ctx (repository_ctx): The rule's repository_ctx
abi (str): Since there's no consistent way to check for ABI, this info
may be explicitly provided
Returns:
struct: A triple struct, see `@rules_rust//rust/platform:triple.bzl`
"""

# Detect the host's cpu architecture

supported_architectures = {
"linux": ["aarch64", "x86_64"],
"macos": ["aarch64", "x86_64"],
"windows": ["x86_64"],
}

if "linux" in repository_ctx.os.name:
cpu = _query_cpu_architecture(repository_ctx, supported_architectures["linux"])
return triple("{}-unknown-linux-{}".format(
cpu,
abi or "gnu",
))

if "mac" in repository_ctx.os.name:
cpu = _query_cpu_architecture(repository_ctx, supported_architectures["macos"])
return triple("{}-apple-darwin".format(cpu))

if "win" in repository_ctx.os.name:
cpu = _query_cpu_architecture(repository_ctx, supported_architectures["windows"], True)
return triple("{}-pc-windows-{}".format(
cpu,
abi or "msvc",
))

fail("Unhandled host os: {}", repository_ctx.os.name)

def _resolve_repository_template(
template,
abi = None,
Expand Down
7 changes: 2 additions & 5 deletions crate_universe/private/common_utils.bzl
@@ -1,11 +1,8 @@
"""Common utilities useful for unifying the behavior of different parts of `cargo-bazel`."""

# buildifier: disable=bzl-visibility
load(
"//cargo/private:cargo_utils.bzl",
_get_host_triple = "get_host_triple",
_rust_get_rust_tools = "get_rust_tools",
)
load("//cargo/private:cargo_utils.bzl", _rust_get_rust_tools = "get_rust_tools")
load("//rust/platform:triple.bzl", _get_host_triple = "get_host_triple")

get_host_triple = _get_host_triple

Expand Down
3 changes: 2 additions & 1 deletion crate_universe/private/crates_repository.bzl
@@ -1,6 +1,6 @@
"""`crates_repository` rule implementation"""

load("//crate_universe/private:common_utils.bzl", "get_host_triple", "get_rust_tools")
load("//crate_universe/private:common_utils.bzl", "get_rust_tools")
load(
"//crate_universe/private:generate_utils.bzl",
"CRATES_REPOSITORY_ENVIRON",
Expand All @@ -17,6 +17,7 @@ load(
)
load("//crate_universe/private:urls.bzl", "CARGO_BAZEL_SHA256S", "CARGO_BAZEL_URLS")
load("//rust:defs.bzl", "rust_common")
load("//rust/platform:triple.bzl", "get_host_triple")
load("//rust/platform:triple_mappings.bzl", "SUPPORTED_PLATFORM_TRIPLES")

def _crates_repository_impl(repository_ctx):
Expand Down
128 changes: 126 additions & 2 deletions rust/platform/triple.bzl
@@ -1,6 +1,7 @@
"""Triples are a way to define information about a platform/system. This module provides
a way to convert a triple string into a well structured object to avoid constant string
parsing in starlark code.
parsing in starlark code, and a way for a repository_rule to extract the target triple
of the host platform.
Triples can be described at the following link:
https://clang.llvm.org/docs/CrossCompilation.html#target-triple
Expand All @@ -18,14 +19,16 @@ def triple(triple):
- vendor (str): The vendor of the system
- system (str): The name of the system
- abi (str, optional): The abi to use or None if abi does not apply.
- triple (str): The original triple
- str (str): Original string representation of the triple
- triple (str): Deprecated; same as str
"""
if triple == "wasm32-wasi":
return struct(
arch = "wasm32",
system = "wasi",
vendor = "wasi",
abi = None,
str = triple,
triple = triple,
)

Expand All @@ -50,5 +53,126 @@ def triple(triple):
vendor = vendor,
system = system,
abi = abi,
str = triple,
triple = triple,
)

_CPU_ARCH_ERROR_MSG = """\
Command failed with exit code '{code}': {args}
----------stdout:
{stdout}
----------stderr:
{stderr}
"""

def _query_cpu_architecture(repository_ctx, expected_archs, is_windows = False):
"""Detect the host CPU architecture
Args:
repository_ctx (repository_ctx): The repository_rule's context object
expected_archs (list): A list of expected architecture strings
is_windows (bool, optional): If true, the cpu lookup will use the windows method (`wmic` vs `uname`)
Returns:
str: The host's CPU architecture
"""
if is_windows:
arguments = ["wmic", "os", "get", "osarchitecture"]
else:
arguments = ["uname", "-m"]

result = repository_ctx.execute(arguments)

if result.return_code:
fail(_CPU_ARCH_ERROR_MSG.format(
code = result.return_code,
args = arguments,
stdout = result.stdout,
stderr = result.stderr,
))

if is_windows:
# Example output:
# OSArchitecture
# 64-bit
lines = result.stdout.split("\n")
arch = lines[1].strip()

# Translate 64-bit to a compatible rust platform
# https://doc.rust-lang.org/nightly/rustc/platform-support.html
if arch == "64-bit":
arch = "x86_64"
else:
arch = result.stdout.strip("\n")

# Correct the arm architecture for macos
if "mac" in repository_ctx.os.name and arch == "arm64":
arch = "aarch64"

if not arch in expected_archs:
fail("{} is not a expected cpu architecture {}\n{}".format(
arch,
expected_archs,
result.stdout,
))

return arch

def get_host_triple(repository_ctx, abi = None):
"""Query host information for the appropriate triple to use with load_arbitrary_tool or the crate_universe resolver
Example:
```python
load("@rules_rust//rust:repositories.bzl", "load_arbitrary_tool")
load("@rules_rust//rust/platform:triple.bzl", "get_host_triple")
def _impl(repository_ctx):
host_triple = get_host_triple(repository_ctx)
load_arbitrary_tool(
ctx = repository_ctx,
tool_name = "cargo",
tool_subdirectories = ["cargo"],
target_triple = host_triple.str,
)
example = repository_rule(implementation = _impl)
```
Args:
repository_ctx (repository_ctx): The repository_rule's context object
abi (str): Since there's no consistent way to check for ABI, this info
may be explicitly provided
Returns:
struct: A triple struct; see the `triple` function in this module
"""

# Detect the host's cpu architecture

supported_architectures = {
"linux": ["aarch64", "x86_64"],
"macos": ["aarch64", "x86_64"],
"windows": ["x86_64"],
}

if "linux" in repository_ctx.os.name:
cpu = _query_cpu_architecture(repository_ctx, supported_architectures["linux"])
return triple("{}-unknown-linux-{}".format(
cpu,
abi or "gnu",
))

if "mac" in repository_ctx.os.name:
cpu = _query_cpu_architecture(repository_ctx, supported_architectures["macos"])
return triple("{}-apple-darwin".format(cpu))

if "win" in repository_ctx.os.name:
cpu = _query_cpu_architecture(repository_ctx, supported_architectures["windows"], True)
return triple("{}-pc-windows-{}".format(
cpu,
abi or "msvc",
))

fail("Unhandled host os: {}", repository_ctx.os.name)
15 changes: 5 additions & 10 deletions test/load_arbitrary_tool/load_arbitrary_tool_test.bzl
@@ -1,16 +1,11 @@
# buildifier: disable=module-docstring
load("//rust:repositories.bzl", "load_arbitrary_tool")
load("//rust/platform:triple.bzl", "get_host_triple")
load("//rust/platform:triple_mappings.bzl", "system_to_binary_ext")

def _load_arbitrary_tool_test_impl(repository_ctx):
if "mac" in repository_ctx.os.name:
target_triple = "x86_64-apple-darwin"
cargo_bin = "bin/cargo"
elif "windows" in repository_ctx.os.name:
target_triple = "x86_64-pc-windows-msvc"
cargo_bin = "bin/cargo.exe"
else:
target_triple = "x86_64-unknown-linux-gnu"
cargo_bin = "bin/cargo"
host_triple = get_host_triple(repository_ctx)
cargo_bin = "bin/cargo" + system_to_binary_ext(host_triple.system)

# Download cargo
load_arbitrary_tool(
Expand All @@ -19,7 +14,7 @@ def _load_arbitrary_tool_test_impl(repository_ctx):
tool_subdirectories = ["cargo"],
version = "1.53.0",
iso_date = None,
target_triple = target_triple,
target_triple = host_triple.str,
)

repo_path = repository_ctx.path(".")
Expand Down

0 comments on commit 58627f5

Please sign in to comment.