From 13e566e6b8b9a230d29c6c7cd024577837e809b8 Mon Sep 17 00:00:00 2001 From: Daniel Wagner-Hall Date: Tue, 3 Sep 2024 20:44:28 +0100 Subject: [PATCH] Consistently thread extra target constraints around (#2829) 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 --- .bazelci/presubmit.yml | 8 ++ examples/musl_cross_compiling/WORKSPACE.bazel | 83 +++++++++++++------ .../hello_linux_musl_test.sh | 2 +- rust/repositories.bzl | 34 ++++---- 4 files changed, 84 insertions(+), 43 deletions(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index a489982d85..0d1da3ee2e 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -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 diff --git a/examples/musl_cross_compiling/WORKSPACE.bazel b/examples/musl_cross_compiling/WORKSPACE.bazel index a141c63ec3..8a00fe10f7 100644 --- a/examples/musl_cross_compiling/WORKSPACE.bazel +++ b/examples/musl_cross_compiling/WORKSPACE.bazel @@ -12,20 +12,18 @@ 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], ) @@ -33,11 +31,13 @@ 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], ) @@ -46,11 +46,13 @@ 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], ) @@ -58,14 +60,47 @@ 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( diff --git a/examples/musl_cross_compiling/hello_linux_musl_test.sh b/examples/musl_cross_compiling/hello_linux_musl_test.sh index 72c5fc8b53..eec79995b8 100755 --- a/examples/musl_cross_compiling/hello_linux_musl_test.sh +++ b/examples/musl_cross_compiling/hello_linux_musl_test.sh @@ -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}" diff --git a/rust/repositories.bzl b/rust/repositories.bzl index 88612310a9..44680f24e7 100644 --- a/rust/repositories.bzl +++ b/rust/repositories.bzl @@ -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) @@ -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: @@ -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 @@ -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 = [] @@ -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.