Skip to content

Commit

Permalink
Consistently thread extra target constraints around (#2829)
Browse files Browse the repository at this point in the history
This allows for selecting non-default toolchains where the exec triple
matches the target triple.

This is tested by enabling the musl static linking tests on the Linux
host platform. Before this PR, the test would fail because the -gnu
rather than -musl rust toolchain would end up getting selected. Now,
everything works.

Fixes #2726
  • Loading branch information
illicitonion authored Sep 3, 2024
1 parent 9569c9c commit 13e566e
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 43 deletions.
8 changes: 8 additions & 0 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,14 @@ tasks:
- "//..."
test_targets:
- "//..."
musl_cross_compiling_linux_to_linux:
name: Musl cross compiling test from Linux to Linux
platform: ubuntu2204
working_directory: examples/musl_cross_compiling
build_targets:
- "//..."
test_targets:
- "//..."
nix_cross_compiling:
name: Nix cross compiling test
platform: ubuntu2204
Expand Down
83 changes: 59 additions & 24 deletions examples/musl_cross_compiling/WORKSPACE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,32 @@ EDITION = "2021"
# Before 1.80.0, proc macros couldn't be used when exec!=target where exec and target platforms use different shared library extension (i.e. so vs dylib) because of an error in rustc's handling of extensions.
RUST_VERSION = "1.80.0"

rust_register_toolchains(
edition = EDITION,
)

rust_repository_set(
name = "darwin_x86_64_to_x86_64_musl_tuple",
edition = EDITION,
exec_triple = "x86_64-apple-darwin",
# Setting this extra_target_triples allows differentiating the musl case from the non-musl case, in case multiple linux-targeting toolchains are registered.
extra_target_triples = {"x86_64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:x86_64",
"@platforms//os:linux",
]},
extra_target_triples = {
"x86_64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:x86_64",
"@platforms//os:linux",
],
},
versions = [RUST_VERSION],
)

rust_repository_set(
name = "darwin_arm64_to_x86_64_musl_tuple",
edition = EDITION,
exec_triple = "aarch64-apple-darwin",
extra_target_triples = {"x86_64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:x86_64",
"@platforms//os:linux",
]},
extra_target_triples = {
"x86_64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:x86_64",
"@platforms//os:linux",
],
},
versions = [RUST_VERSION],
)

Expand All @@ -46,26 +46,61 @@ rust_repository_set(
edition = EDITION,
exec_triple = "x86_64-apple-darwin",
# Setting this extra_target_triples allows differentiating the musl case from the non-musl case, in case multiple linux-targeting toolchains are registered.
extra_target_triples = {"aarch64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:arm64",
"@platforms//os:linux",
]},
extra_target_triples = {
"aarch64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:arm64",
"@platforms//os:linux",
],
},
versions = [RUST_VERSION],
)

rust_repository_set(
name = "darwin_arm64_to_arm64_musl_tuple",
edition = EDITION,
exec_triple = "aarch64-apple-darwin",
extra_target_triples = {"aarch64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:arm64",
"@platforms//os:linux",
]},
extra_target_triples = {
"aarch64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:arm64",
"@platforms//os:linux",
],
},
versions = [RUST_VERSION],
)

# This overrides a default rust_repository_set created by rust_register_toolchain.
# It must be named exactly this, and must be called before rust_register_toolchain is.
rust_repository_set(
name = "rust_linux_x86_64",
edition = EDITION,
exec_triple = "x86_64-unknown-linux-gnu",
# Setting this extra_target_triples allows differentiating the musl case from the non-musl case, in case multiple linux-targeting toolchains are registered.
extra_target_triples = {
"aarch64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:arm64",
"@platforms//os:linux",
],
"x86_64-unknown-linux-gnu": [
"@//linker_config:unknown",
"@platforms//cpu:x86_64",
"@platforms//os:linux",
],
"x86_64-unknown-linux-musl": [
"@//linker_config:musl",
"@platforms//cpu:x86_64",
"@platforms//os:linux",
],
},
versions = [RUST_VERSION],
)

rust_register_toolchains(
edition = EDITION,
)

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
Expand Down
2 changes: 1 addition & 1 deletion examples/musl_cross_compiling/hello_linux_musl_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fi
binary="$1"
want_file_output="$2"

out="$(file "${binary}")"
out="$(file -L "${binary}")"

if [[ "${out}" != *"${want_file_output}"* ]]; then
echo >&2 "Wrong file type: ${out}"
Expand Down
34 changes: 16 additions & 18 deletions rust/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,11 @@ def rust_register_toolchains(
rustfmt_repo_name,
))

for toolchain in _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions):
for toolchain in _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions, fallback_target_compatible_with = None):
toolchain_names.append(toolchain.name)
toolchain_labels[toolchain.name] = "@{}//:{}".format(toolchain.name + "_tools", "rust_toolchain")
exec_compatible_with_by_toolchain[toolchain.name] = triple_to_constraint_set(exec_triple)
target_compatible_with_by_toolchain[toolchain.name] = triple_to_constraint_set(toolchain.target_triple)
target_compatible_with_by_toolchain[toolchain.name] = toolchain.target_constraints
toolchain_types[toolchain.name] = "@rules_rust//rust:toolchain"

toolchain_names.append(rustfmt_repo_name)
Expand Down Expand Up @@ -923,10 +923,12 @@ rust_toolchain_set_repository = repository_rule(
implementation = _rust_toolchain_set_repository_impl,
)

def _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions):
def _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions, fallback_target_compatible_with):
extra_target_triples_list = extra_target_triples.keys() if type(extra_target_triples) == "dict" else extra_target_triples

toolchain_repos = []

for target_triple in depset([exec_triple] + extra_target_triples).to_list():
for target_triple in depset([exec_triple] + extra_target_triples_list).to_list():
# Parse all provided versions while checking for duplicates
channels = {}
for version in versions:
Expand All @@ -943,12 +945,20 @@ def _get_toolchain_repositories(name, exec_triple, extra_target_triples, version
version = version,
)})

if type(extra_target_triples) == "dict" and target_triple in extra_target_triples:
target_constraints = extra_target_triples[target_triple]
elif fallback_target_compatible_with != None:
target_constraints = fallback_target_compatible_with
else:
target_constraints = triple_to_constraint_set(target_triple)

# Define toolchains for each requested version
for channel in channels.values():
toolchain_repos.append(struct(
name = "{}__{}__{}".format(name, target_triple, channel.name),
target_triple = target_triple,
channel = channel,
target_constraints = target_constraints,
))

return toolchain_repos
Expand Down Expand Up @@ -1012,20 +1022,8 @@ def rust_repository_set(
default_target_compatible_with (list, optional): A list of constraints for the target platform for this toolchain when the exec platform is the same as the target platform.
"""

# extra_target_triples may be a dict or list - make a list we can pass to _get_toolchain_repositories
extra_target_triples_list = []
for extra_target_triple in extra_target_triples:
extra_target_triples_list.append(extra_target_triple)

all_toolchain_names = []
for toolchain in _get_toolchain_repositories(name, exec_triple, extra_target_triples_list, versions):
target_compatible_with = None
if toolchain.target_triple == exec_triple:
# The exec triple implicitly gets a toolchain with itself as a target - use default_target_compatible_with for it
target_compatible_with = default_target_compatible_with
elif type(extra_target_triples) == "dict":
target_compatible_with = extra_target_triples.get(toolchain.target_triple)

for toolchain in _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions, default_target_compatible_with):
# Infer toolchain-specific rustc flags depending on the type (list, dict, optional) of extra_rustc_flags
if extra_rustc_flags == None:
toolchain_extra_rustc_flags = []
Expand Down Expand Up @@ -1057,7 +1055,7 @@ def rust_repository_set(
urls = urls,
version = toolchain.channel.version,
exec_compatible_with = exec_compatible_with,
target_compatible_with = target_compatible_with,
target_compatible_with = toolchain.target_constraints,
))

# This repository exists to allow `rust_repository_set` to work with the `maybe` wrapper.
Expand Down

0 comments on commit 13e566e

Please sign in to comment.