From 3176328e9e186957f58c78c30c3e52c92ec5fe52 Mon Sep 17 00:00:00 2001 From: Janick Martinez Esturo Date: Wed, 12 Aug 2026 10:52:38 +0200 Subject: [PATCH] feat: support aarch64 hosts via a host_arch attribute Every toolchain this module generates hardcodes `exec_compatible_with = [linux, x86_64]` -- it is a string literal in the hub's BUILD template, while target_compatible_with beside it is a format field. So on an aarch64 host Bazel matches no cc toolchain at all and every C/C++ action fails resolution, not just cross-compiles. The binaries to fix that already exist: gcc-builds has published `-host-aarch64` archives since 08072026, covering aarch64, armv7 and x86_64 targets for every GCC version pinned to 08072026 or later (14.3.0, 15.2.0, 16.1.0 and 16.2.0). Only the Starlark wiring was missing. `host_arch` names the architecture the toolchain binaries RUN on. It defaults to `rctx.os.arch`, so a native build on either architecture needs no configuration, and it drives three things: - which archive is fetched, via a host dimension on AVAILABLE_GCC_VERSIONS; - `exec_compatible_with`, now a templated hub attribute defaulting to `[linux, {host_arch}]`, mirroring target_compatible_with; - the builtin include layout. That last one was a latent bug. A NATIVE build lays libstdc++ out flat (`include/c++/`) while a CROSS build nests it under the target triple, and the existing code keyed that on `target_arch == x86_64` -- correct only because every published build was x86_64-hosted. It is now keyed on `host_arch == target_arch`, which is what the archives actually do: the aarch64-hosted aarch64 build is flat, and the aarch64-hosted x86_64 one is nested. Getting this wrong is quiet, because a nonexistent -isystem directory is ignored and only surfaces later as a missing . Backwards compatible. Existing entries keep their exact URLs and digests, and the binary prefix needs no host handling because _detect_binary_prefix already probes the extracted archive. A hand-written `gcc_versions` in the old `{version: {target: {url, sha256}}}` shape still works and is read as x86_64-hosted; combining it with a non-x86_64 host fails with a message saying what to write instead. Verified all four host/target combinations (plus aarch64-hosted armv7) resolve, fetch the archive whose ELF machine matches their host_arch, and declare only include directories that exist -- and that the x86_64-hosted paths are unchanged. //tests/host_arch asserts the aarch64-hosted compiler is an ARM ELF by reading e_machine, so it runs anywhere; it fails if pointed at the x86_64-hosted cross toolchain. It is skipped for 12.5.0 and 13.4.0, whose releases publish no aarch64-hosted build, as //tests/lld is for the versions built without lld. --- MODULE.bazel | 11 + README.md | 5 +- WORKSPACE | 12 +- docs/README.md | 33 +++ docs/defs.md | 7 +- docs/updating-gcc-builds.md | 36 +++- tests/host_arch/BUILD.bazel | 42 ++++ tests/host_arch/host_arch_test.sh | 43 ++++ toolchain/defs.bzl | 332 +++++++++++++++++++++++------- toolchain/module_extensions.bzl | 1 + 10 files changed, 432 insertions(+), 90 deletions(-) create mode 100644 tests/host_arch/BUILD.bazel create mode 100755 tests/host_arch/host_arch_test.sh diff --git a/MODULE.bazel b/MODULE.bazel index 098a09e..45c8781 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -33,6 +33,17 @@ gcc_toolchains = use_extension("//toolchain:module_extensions.bzl", "gcc_toolcha ] ] +# An aarch64-HOSTED toolchain, for //tests/host_arch. Deliberately not registered: its +# binaries are ARM, so it cannot execute on an x86_64 CI machine -- the test only inspects +# the fetched archive. +gcc_toolchains.toolchain( + name = "gcc_toolchain_aarch64_host", + gcc_version = "14.3.0", + host_arch = "aarch64", + target_arch = "aarch64", +) +use_repo(gcc_toolchains, "gcc_toolchain_aarch64_host") + # Dev Dependencies (for examples/) # =============================== bazel_dep(name = "rules_foreign_cc", version = "0.15.1", dev_dependency = True) diff --git a/README.md b/README.md index 2963432..93fd2f1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ performance and portability. You can find the comprehensive documentation under ## Features -- **Multi-architecture**: Support for x86_64, aarch64, and armv7 Linux targets. +- **Multi-architecture**: Support for x86_64, aarch64, and armv7 Linux targets, + hosted on x86_64 or aarch64. - **Hermetic**: Fully self-contained with no system dependencies. - **Optimized**: Reduced toolchain sizes and improved build performance. - **Fortran Support**: Complete Fortran compilation, including OpenMP support. @@ -42,7 +43,7 @@ The toolchain has been optimized to reduce size and improve build performance th * **First-party Code**: Your repository contains C/C++/Fortran code. * **Sanitizer Testing**: Need to run sanitizers (asan, lsan, tsan, ubsan) on your code. -* **Cross-compilation**: Build for Linux armv7 or aarch64 from x86_64. +* **Cross-compilation**: Build for Linux armv7, aarch64 or x86_64 from x86_64 or aarch64. * **Portability**: Create binaries compatible with any Linux distribution. * **Reproducibility**: Ensure consistent builds across development and CI environments. * **Remote Execution**: Use with Bazel RBE for distributed builds. diff --git a/WORKSPACE b/WORKSPACE index d0f983c..2deed06 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -41,7 +41,7 @@ load("@bazel_lib//lib:repositories.bzl", "bazel_lib_dependencies") bazel_lib_dependencies() -load("//toolchain:defs.bzl", "ARCHS", "gcc_register_toolchain") +load("//toolchain:defs.bzl", "ARCHS", "gcc_declare_toolchain", "gcc_register_toolchain") gcc_register_toolchain( name = "gcc_toolchain_aarch64", @@ -58,6 +58,16 @@ gcc_register_toolchain( target_arch = ARCHS.x86_64, ) +# An aarch64-HOSTED toolchain, for //tests/host_arch. DECLARED, not registered: its +# binaries are ARM, so it cannot execute on an x86_64 CI machine -- the test only inspects +# the fetched archive. +gcc_declare_toolchain( + name = "gcc_toolchain_aarch64_host", + gcc_version = "14.3.0", + host_arch = ARCHS.aarch64, + target_arch = ARCHS.aarch64, +) + load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") rules_foreign_cc_dependencies() diff --git a/docs/README.md b/docs/README.md index c674d46..d617907 100644 --- a/docs/README.md +++ b/docs/README.md @@ -87,6 +87,39 @@ copts = select({ Note that these settings only match when the flag is set explicitly, so a `select()` over them needs a `//conditions:default` branch to cover the unset case. +## Choosing the host architecture + +`target_arch` names the architecture a toolchain produces code FOR. `host_arch` names the one its +binaries RUN on, and defaults to whatever architecture Bazel itself is running on, so building +natively on either x86_64 or aarch64 needs no configuration at all: + +```bazel +# On an x86_64 machine this is an x86_64-hosted cross toolchain; on an aarch64 machine it is a +# native one. Either way it targets aarch64. +gcc_toolchains.toolchain( + name = "gcc_toolchain_aarch64", + target_arch = "aarch64", +) +``` + +It drives `exec_compatible_with` on the generated `toolchain()`, so toolchain resolution picks the +toolchain whose binaries the execution platform can actually run. + +Set it explicitly only to fetch a toolchain for a host you are not on — for example to declare an +aarch64-hosted toolchain from x86_64: + +```bazel +gcc_toolchains.toolchain( + name = "gcc_toolchain_aarch64_host", + host_arch = "aarch64", + target_arch = "aarch64", +) +``` + +gcc-builds publishes aarch64-hosted archives from the `08072026` release on, which covers GCC +14.3.0 and newer. Asking for a version with no build for that host fails at fetch time, naming the +hosts it does have. `armv7` is a target only. + ## Language Support ### Pure C diff --git a/docs/defs.md b/docs/defs.md index 5cbb763..9042e1c 100644 --- a/docs/defs.md +++ b/docs/defs.md @@ -10,7 +10,7 @@ This module provides the definitions for registering a GCC toolchain for C and C
 gcc_toolchain(name, binary_prefix, enable_fortran, extra_asmflags, extra_cflags, extra_cxxflags,
               extra_fflags, extra_ldflags, fincludes, gcc_toolchain_workspace_name, gcc_version,
-              gcc_versions, includes, repo_mapping, supports_param_files, target_arch)
+              gcc_versions, host_arch, includes, repo_mapping, supports_param_files, target_arch)
 
@@ -31,7 +31,8 @@ gcc_toolchain(name, fincludes | Extra includes for compiling Fortran, if enabled. %workspace% is rendered to the toolchain root path. | List of strings | optional | [] | | gcc_toolchain_workspace_name | The name given to the gcc-toolchain repository, if the default was not used. | String | optional | "gcc_toolchain" | | gcc_version | The version of GCC. | String | optional | "16.2.0" | -| gcc_versions | A JSON dictionary of GCC versions to their download URLs and SHA256 hashes. The structure is {<gcc_version>: {<target_arch>: {url: <url>, sha256: <sha256>}}}. | String | optional | "{"12.5.0":{"aarch64":{"sha256":"7b0e25133a98d44b648a925ba11f64a3adc470e87668af80ce2c3af389ebe9be","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-aarch64.tar.xz"},"armv7":{"sha256":"a0ef76c8cc517b3d76dd2f09b1a371975b2ff1082e2f9372ed79af01b9292934","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-armv7.tar.xz"},"x86_64":{"sha256":"51076e175839b434bb2dc0006c0096916df585e8c44666d35b0e3ce821d535db","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-x86_64.tar.xz"}},"13.4.0":{"aarch64":{"sha256":"770cf6bf62bdf78763de526d3a9f5cae4c19f1a3aca0ef8f18b05f1a46d1ffaf","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-aarch64.tar.xz"},"armv7":{"sha256":"1b2739b5003c5a3f0ab7c4cc7fb95cc99c0e933982512de7255c2bd9ced757ad","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-armv7.tar.xz"},"x86_64":{"sha256":"d96071c1b98499afd7b7b56ebd69ad414020edf66e982004acffe7df8aaf7e02","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-x86_64.tar.xz"}},"14.3.0":{"aarch64":{"sha256":"b5a73bc840938c8dbb49e2f15b8b8d63e5c33beae0be2aa9a7c52b593522cdcd","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-aarch64.tar.xz"},"armv7":{"sha256":"376684c062a23e84b619a717fa4c7bba336211c8b48169f76eb5aa6ed4da6bb8","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-armv7.tar.xz"},"x86_64":{"sha256":"d155a38e4acff9588df466f0edc98c1a2c54d09bc0162805ba38908cfd7a1d28","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-x86_64.tar.xz"}},"15.2.0":{"aarch64":{"sha256":"f38696590786e7c99d3bb5b8ce9ed66be6224d505fa45dcae0b2a6ec07eb0570","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-aarch64.tar.xz"},"armv7":{"sha256":"8ecb5b35aa25efe78772701c70ed27eda727264303d03cffc372a6f24f18be90","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-armv7.tar.xz"},"x86_64":{"sha256":"f31edf791877935258dcc864afbfb7c9f9238be9f7d9da0ee57f5bc121074457","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-x86_64.tar.xz"}},"16.1.0":{"aarch64":{"sha256":"4331e513156a699c1015fb94021497306f0a896520efbad8b3e16418eb683468","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-aarch64.tar.xz"},"armv7":{"sha256":"8d42c1fd130ccb170fe8d5d17148ae2d3f97134ac0009fdcac87550fec6a6289","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-armv7.tar.xz"},"x86_64":{"sha256":"cfd8ca5bc365c1c838825ed6e44c7b2c309aada25791f76ef73b1aec819e362e","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-x86_64.tar.xz"}},"16.2.0":{"aarch64":{"sha256":"6407b35116f21c59e98ab5ad68ddd8ff5f3e0469723a5d465ec08ed615b11a55","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-aarch64.tar.xz"},"armv7":{"sha256":"515da8a22fa560002d3d149ad701acb725502c70f7bf8d4905f90b0830d38238","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-armv7.tar.xz"},"x86_64":{"sha256":"54af34c821e59b03ded8f82d3a1104426ec4baaf3b226233e1fd76ad5dcb78cf","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-x86_64.tar.xz"}}}" | +| gcc_versions | A JSON dictionary of GCC versions to their download URLs and SHA256 hashes. The structure is {<gcc_version>: {<target_arch>: {<host_arch>: {url: <url>, sha256: <sha256>}}}}. A {url, sha256} directly under <target_arch> is also accepted and means an x86_64-hosted build. | String | optional | "{"12.5.0":{"aarch64":{"x86_64":{"sha256":"7b0e25133a98d44b648a925ba11f64a3adc470e87668af80ce2c3af389ebe9be","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-aarch64.tar.xz"}},"armv7":{"x86_64":{"sha256":"a0ef76c8cc517b3d76dd2f09b1a371975b2ff1082e2f9372ed79af01b9292934","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-armv7.tar.xz"}},"x86_64":{"x86_64":{"sha256":"51076e175839b434bb2dc0006c0096916df585e8c44666d35b0e3ce821d535db","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-x86_64.tar.xz"}}},"13.4.0":{"aarch64":{"x86_64":{"sha256":"770cf6bf62bdf78763de526d3a9f5cae4c19f1a3aca0ef8f18b05f1a46d1ffaf","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-aarch64.tar.xz"}},"armv7":{"x86_64":{"sha256":"1b2739b5003c5a3f0ab7c4cc7fb95cc99c0e933982512de7255c2bd9ced757ad","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-armv7.tar.xz"}},"x86_64":{"x86_64":{"sha256":"d96071c1b98499afd7b7b56ebd69ad414020edf66e982004acffe7df8aaf7e02","url":"https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-x86_64.tar.xz"}}},"14.3.0":{"aarch64":{"aarch64":{"sha256":"def0f33e644f8586f6ca39754951eebe2189b92823bdaf6d4c4ba42fdad6c598","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-aarch64-host-aarch64.tar.xz"},"x86_64":{"sha256":"b5a73bc840938c8dbb49e2f15b8b8d63e5c33beae0be2aa9a7c52b593522cdcd","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-aarch64.tar.xz"}},"armv7":{"aarch64":{"sha256":"ff3e11e2b222fb42146f1254c6a089234e8cd8e384128de56afc781af13d72d9","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-armv7-host-aarch64.tar.xz"},"x86_64":{"sha256":"376684c062a23e84b619a717fa4c7bba336211c8b48169f76eb5aa6ed4da6bb8","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-armv7.tar.xz"}},"x86_64":{"aarch64":{"sha256":"716ed801e7f2cb35cf25614ffe8e8293934587198e919bcb8c55016c862628f1","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-x86_64-host-aarch64.tar.xz"},"x86_64":{"sha256":"d155a38e4acff9588df466f0edc98c1a2c54d09bc0162805ba38908cfd7a1d28","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-x86_64.tar.xz"}}},"15.2.0":{"aarch64":{"aarch64":{"sha256":"963b612339998a2dc68aea42ac0928933c0aa4ae18be22f365ec83c86e685b52","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-aarch64-host-aarch64.tar.xz"},"x86_64":{"sha256":"f38696590786e7c99d3bb5b8ce9ed66be6224d505fa45dcae0b2a6ec07eb0570","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-aarch64.tar.xz"}},"armv7":{"aarch64":{"sha256":"24a3c48b46cd3d0b80f6a780cdc87e4327e06e7a6ba3b08de9045dda010e6721","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-armv7-host-aarch64.tar.xz"},"x86_64":{"sha256":"8ecb5b35aa25efe78772701c70ed27eda727264303d03cffc372a6f24f18be90","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-armv7.tar.xz"}},"x86_64":{"aarch64":{"sha256":"5096ac470ff1023ac337b1fee847d941946401142121f1f094600b854e2569d6","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-x86_64-host-aarch64.tar.xz"},"x86_64":{"sha256":"f31edf791877935258dcc864afbfb7c9f9238be9f7d9da0ee57f5bc121074457","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-x86_64.tar.xz"}}},"16.1.0":{"aarch64":{"aarch64":{"sha256":"4492c3160e07f5a931112a1646413b5a0ccaefff1d6ae5dc58d361cb7840d394","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-aarch64-host-aarch64.tar.xz"},"x86_64":{"sha256":"4331e513156a699c1015fb94021497306f0a896520efbad8b3e16418eb683468","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-aarch64.tar.xz"}},"armv7":{"aarch64":{"sha256":"0f51857564e065113dbec6b106241ec6437b9cba7bb5dedc54ada0fd6ab73e80","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-armv7-host-aarch64.tar.xz"},"x86_64":{"sha256":"8d42c1fd130ccb170fe8d5d17148ae2d3f97134ac0009fdcac87550fec6a6289","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-armv7.tar.xz"}},"x86_64":{"aarch64":{"sha256":"7b10a4d5e89d043044e7d7850e0693740bb4643ef231499d1c887759ed7b8615","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-x86_64-host-aarch64.tar.xz"},"x86_64":{"sha256":"cfd8ca5bc365c1c838825ed6e44c7b2c309aada25791f76ef73b1aec819e362e","url":"https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-x86_64.tar.xz"}}},"16.2.0":{"aarch64":{"aarch64":{"sha256":"82a482d269cf75334cb969ef93593655f7e726e855043214e38b3672b10f97de","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-aarch64-host-aarch64.tar.xz"},"x86_64":{"sha256":"6407b35116f21c59e98ab5ad68ddd8ff5f3e0469723a5d465ec08ed615b11a55","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-aarch64.tar.xz"}},"armv7":{"aarch64":{"sha256":"cb97908d9d375a9e7502898a7277832aa63ca696ffc1088411f0eac921d5d54d","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-armv7-host-aarch64.tar.xz"},"x86_64":{"sha256":"515da8a22fa560002d3d149ad701acb725502c70f7bf8d4905f90b0830d38238","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-armv7.tar.xz"}},"x86_64":{"aarch64":{"sha256":"600c8d1a6e70eb0b259a01eef3fd4429a43d3cfebe4c6e01659bc6fcf5556415","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-x86_64-host-aarch64.tar.xz"},"x86_64":{"sha256":"54af34c821e59b03ded8f82d3a1104426ec4baaf3b226233e1fd76ad5dcb78cf","url":"https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-x86_64.tar.xz"}}}}" | +| host_arch | The architecture the toolchain binaries RUN on. E.g. aarch64. Defaults to the architecture Bazel is running on, so a native build needs no configuration; set it only to fetch a toolchain for a different host. | String | optional | "" | | includes | Extra includes for compiling C and C++. %workspace% is rendered to the toolchain root path. See https://github.com/bazelbuild/bazel/blob/a48e246e/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderHelper.java#L234-L254. | List of strings | optional | [] | | repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.<p>For example, an entry "@foo": "@bar" declares that, for any time this repository depends on @foo (such as a dependency on @foo//some:target, it should actually resolve that dependency within globally-declared @bar (@bar//some:target). | Dictionary: String -> String | required | | | supports_param_files | Set supports_param_files = 1 on the generated cc_toolchain, which lets Bazel pass linker arguments via an @params file. Enable this when link command lines for large targets overflow ARG_MAX (e.g. collect2: posix_spawn: Argument list too long). Off by default to preserve historical behavior. | Boolean | optional | False | @@ -63,7 +64,7 @@ e.g. if you are consuming this repository as a Bzlmod dependency. | :------------- | :------------- | :------------- | | name | The name of the hub repository holding the toolchain declarations. | none | | target_arch | The target architecture of the toolchain. | none | -| kwargs | The extra arguments passed to gcc_toolchain. See gcc_toolchain for more info. The attributes of the toolchain declarations themselves are also accepted here, since they apply to the hub rather than to gcc_toolchain:

target_compatible_with: constraint_values passed to target_compatible_with of the toolchain. {target_arch} is rendered to the target_arch argument value. Defaults to ["@platforms//os:linux", "@platforms//cpu:{target_arch}"].

extra_target_compatible_with: Additional constraint_values appended to target_compatible_with of the toolchain, on top of the values from the target_compatible_with argument (including its defaults). Unlike target_compatible_with, {target_arch} is not rendered.

target_settings: Additional config_settings passed to target_settings of the toolchain, on top of the GCC version selection. {target_arch} is rendered to the target_arch argument value. | none | +| kwargs | The extra arguments passed to gcc_toolchain. See gcc_toolchain for more info. The attributes of the toolchain declarations themselves are also accepted here, since they apply to the hub rather than to gcc_toolchain:

exec_compatible_with: constraint_values passed to exec_compatible_with of the toolchain. {host_arch} is rendered to the host_arch argument value. Defaults to ["@platforms//os:linux", "@platforms//cpu:{host_arch}"].

target_compatible_with: constraint_values passed to target_compatible_with of the toolchain. {target_arch} is rendered to the target_arch argument value. Defaults to ["@platforms//os:linux", "@platforms//cpu:{target_arch}"].

extra_target_compatible_with: Additional constraint_values appended to target_compatible_with of the toolchain, on top of the values from the target_compatible_with argument (including its defaults). Unlike target_compatible_with, {target_arch} is not rendered.

target_settings: Additional config_settings passed to target_settings of the toolchain, on top of the GCC version selection. {target_arch} is rendered to the target_arch argument value. | none | diff --git a/docs/updating-gcc-builds.md b/docs/updating-gcc-builds.md index 402aee6..69fd2fe 100644 --- a/docs/updating-gcc-builds.md +++ b/docs/updating-gcc-builds.md @@ -3,18 +3,25 @@ The prebuilt toolchain tarballs are produced by [f0rmiga/gcc-builds](https://github.com/f0rmiga/gcc-builds) and pinned in this repository by `AVAILABLE_GCC_VERSIONS` in [toolchain/defs.bzl](../toolchain/defs.bzl). Each GCC version maps to -one URL and SHA256 per target architecture: +one URL and SHA256 per target architecture and host architecture: ```starlark AVAILABLE_GCC_VERSIONS = { "16.2.0": { - "aarch64": {"url": "...", "sha256": "..."}, - "armv7": {"url": "...", "sha256": "..."}, - "x86_64": {"url": "...", "sha256": "..."}, + "aarch64": { + "aarch64": {"url": "...", "sha256": "..."}, + "x86_64": {"url": "...", "sha256": "..."}, + }, + "armv7": {...}, + "x86_64": {...}, }, } ``` +The outer architecture is the **target**, the inner one is the **host** the binaries run on. A +version needs no entry for a host it has no build for; asking for one fails with a message listing +the hosts it does have. + A gcc-builds release is tagged `DDMMYYYY` and does not necessarily rebuild every GCC version. Pin each version to the **newest release that publishes it**, which means the entries in `AVAILABLE_GCC_VERSIONS` routinely point at different release tags. @@ -26,10 +33,10 @@ gh release list --repo f0rmiga/gcc-builds --limit 30 gh release view --repo f0rmiga/gcc-builds --json assets --jq '.assets[].name' ``` -Assets are named `gcc-toolchain--.tar.xz`. Assets carrying an extra -`-host-aarch64` suffix are toolchains that *run* on aarch64 hosts; this repository keys -`AVAILABLE_GCC_VERSIONS` by target architecture only and consumes the x86_64-host builds, so the -`-host-aarch64` variants are ignored. Filter them out when collecting assets. +Assets are named `gcc-toolchain--.tar.xz` for an x86_64-hosted build, and +`gcc-toolchain---host-aarch64.tar.xz` for an aarch64-hosted one. Both go +into `AVAILABLE_GCC_VERSIONS`, under the matching host key. Releases before `08072026` publish no +`-host-aarch64` assets at all, so the versions pinned to them have an `x86_64` host entry only. ## 2. Collect the SHA256 hashes @@ -38,7 +45,7 @@ downloaded: ```shell gh api repos/f0rmiga/gcc-builds/releases/tags/ \ - --jq '.assets[] | select(.name | test("host") | not) | "\(.name) \(.digest)"' + --jq '.assets[] | "\(.name) \(.digest)"' ``` Strip the `sha256:` prefix from each value. To confirm a digest independently: @@ -62,7 +69,9 @@ adding or removing a version also means: [.github/workflows/default.yaml](../.github/workflows/default.yaml); - checking whether the tarball ships `bin/ld.lld`. GCC versions built without it cannot use the `linker-lld` feature, and `//tests/lld` marks those versions incompatible so the test is skipped - rather than failing. + rather than failing; +- checking whether it has an aarch64-hosted build. `//tests/host_arch` marks the versions that do + not incompatible, the same way. ## 4. Regenerate the docs @@ -132,5 +141,12 @@ tar -tJf /tmp/toolchain.tar.xz | grep -E '^\./bin/' tar -tJf /tmp/toolchain.tar.xz | grep -E '^\./(lib|include)/' ``` +Note that where the C++ headers live depends on whether the build is **native**, not on the +architecture. A build whose host and target match lays libstdc++ out flat under +`include/c++/`, while a cross build nests it under the target triple. So the +x86_64-hosted x86_64 and aarch64-hosted aarch64 tarballs are both flat, and the x86_64-hosted +aarch64 and aarch64-hosted x86_64 ones are both nested. Getting this wrong is quiet: a nonexistent +`-isystem` directory is ignored, and only surfaces later as a missing `` naming no path. + Detection only covers the binary prefix. If the include or library directories move, both `_gcc_toolchain_impl` and `_TOOLCHAIN_BUILD_FILE_CONTENT` need updating. diff --git a/tests/host_arch/BUILD.bazel b/tests/host_arch/BUILD.bazel new file mode 100644 index 0000000..55aae22 --- /dev/null +++ b/tests/host_arch/BUILD.bazel @@ -0,0 +1,42 @@ +# Copyright (c) Thulio Ferraz Assis 2026 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_shell//shell:sh_test.bzl", "sh_test") + +# The aarch64-hosted toolchain, declared (not registered) as @gcc_toolchain_aarch64_host. +# Its binaries are ARM, so they cannot be RUN on an x86_64 CI machine; this inspects the +# fetched archive instead, which works on any host. +# +# `include` carries the builtin header tree, so requiring it as data also proves the layout +# the toolchain declares is the layout the archive actually has -- a nonexistent -isystem +# path is otherwise ignored silently, surfacing much later as a missing . +# +# gcc-builds only publishes -host-aarch64 archives from the 08072026 release on, so the +# versions pinned to older releases have no aarch64-hosted build to inspect and the test is +# skipped for them, as in //tests/lld. Being incompatible keeps the target unanalyzed, so +# the archive that does not exist is never fetched. +sh_test( + name = "host_arch_test", + srcs = ["host_arch_test.sh"], + data = [ + "@gcc_toolchain_aarch64_host//:gcc", + "@gcc_toolchain_aarch64_host//:include", + ], + env = {"GCC_FILES": "$(locations @gcc_toolchain_aarch64_host//:gcc)"}, + target_compatible_with = select({ + "//toolchain:gcc_version_12_5_0": ["@platforms//:incompatible"], + "//toolchain:gcc_version_13_4_0": ["@platforms//:incompatible"], + "//conditions:default": [], + }), +) diff --git a/tests/host_arch/host_arch_test.sh b/tests/host_arch/host_arch_test.sh new file mode 100755 index 0000000..bf12884 --- /dev/null +++ b/tests/host_arch/host_arch_test.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Copyright (c) Thulio Ferraz Assis 2026 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# An aarch64-hosted toolchain must ship ARM binaries. Verified by inspecting the archive +# rather than running it, so this test works on any host. + +set -euo pipefail + +gcc="" +for f in ${GCC_FILES}; do + if [[ "${f}" == *-gcc ]]; then + gcc="${f}" + break + fi +done + +if [[ -z "${gcc}" ]]; then + echo >&2 "FAIL: no *-gcc among the toolchain's compiler files: ${GCC_FILES}" + exit 1 +fi + +# ELF e_machine, at offset 18, little-endian: 0x00b7 is EM_AARCH64, 0x003e is x86-64. An +# x86_64-hosted build here would mean the toolchain cannot run on an aarch64 machine at +# all, which is the bug the host_arch attribute exists to fix. +readonly machine="$(od -An -tx1 -j18 -N2 "${gcc}" | tr -d ' \n')" +if [[ "${machine}" != "b700" ]]; then + echo >&2 "FAIL: ${gcc} has e_machine 0x${machine}, want 0xb7 (EM_AARCH64)." + exit 1 +fi + +echo "PASS: the aarch64-hosted toolchain ships ARM binaries." diff --git a/toolchain/defs.bzl b/toolchain/defs.bzl index f96cc79..9cf91ae 100644 --- a/toolchain/defs.bzl +++ b/toolchain/defs.bzl @@ -31,6 +31,14 @@ _TRIPLE_BINARY_PREFIXES = { "x86_64": "x86_64-linux-", } +# Bazel spells the host CPU the way Go does ("amd64"), while target_arch and the +# @platforms//cpu constraints use the GNU name ("x86_64"). Only these two architectures can +# HOST a toolchain; armv7 is a target only. +_BAZEL_HOST_ARCHS = { + "aarch64": "aarch64", + "amd64": "x86_64", +} + def _detect_binary_prefix(rctx, target_arch): """Resolves the prefix that `bin/` binaries carry in the extracted toolchain. @@ -50,10 +58,63 @@ def _detect_binary_prefix(rctx, target_arch): return triple_prefix return "" +def _resolve_host_arch(rctx): + """Resolves the architecture the toolchain binaries run on. + + Args: + rctx: The repository context. + + Returns: + The value of the `host_arch` attribute, or the architecture Bazel itself is running + on when that attribute is left at its empty default. + """ + return rctx.attr.host_arch or _BAZEL_HOST_ARCHS.get(rctx.os.arch, ARCHS.x86_64) + +def _resolve_build(gcc_versions, gcc_version, target_arch, host_arch): + """Picks the archive to fetch for one (version, target, host) combination. + + Args: + gcc_versions: The decoded `gcc_versions` attribute. + gcc_version: The GCC version to fetch. + target_arch: The architecture the toolchain produces code for. + host_arch: The architecture the toolchain binaries run on. + + Returns: + The `{url, sha256}` dict of the archive to fetch. + """ + build = gcc_versions[gcc_version][target_arch] + + # A build entry is either a `{host_arch: {url, sha256}}` mapping, or the flat + # `{url, sha256}` of an x86_64-hosted toolchain. The flat form keeps a hand-written + # gcc_versions from before host_arch existed working, and means it as x86_64-hosted. + if "url" not in build: + if host_arch not in build: + fail("gcc {} for target {} has no {}-hosted build. Available: {}.".format( + gcc_version, + target_arch, + host_arch, + ", ".join(sorted(build)), + )) + return build[host_arch] + if host_arch != ARCHS.x86_64: + fail(("gcc_versions for {} target {} lists a single (x86_64-hosted) build, but this " + + "toolchain is {}-hosted. Give it a {{host_arch: {{url, sha256}}}} mapping.").format( + gcc_version, + target_arch, + host_arch, + )) + return build + def _gcc_toolchain_impl(rctx): - versions = json.decode(rctx.attr.gcc_versions) - url = versions[rctx.attr.gcc_version][rctx.attr.target_arch]["url"] - sha256 = versions[rctx.attr.gcc_version][rctx.attr.target_arch]["sha256"] + host_arch = _resolve_host_arch(rctx) + build = _resolve_build( + json.decode(rctx.attr.gcc_versions), + rctx.attr.gcc_version, + rctx.attr.target_arch, + host_arch, + ) + url = build["url"] + sha256 = build["sha256"] rctx.download_and_extract( url = url, sha256 = sha256, @@ -93,6 +154,12 @@ def _gcc_toolchain_impl(rctx): elif target_arch == ARCHS.x86_64: include_prefix = "x86_64-linux/" + # A NATIVE build (host == target) puts libstdc++ and the target headers at the root of + # the archive, while a CROSS build nests them under the target triple. This is a + # property of the build, not of the architecture: the aarch64-hosted aarch64 toolchain + # is native and therefore flat, whereas the aarch64-hosted x86_64 one is nested. + is_native = host_arch == target_arch + c_builtin_includes = [ include.format( gcc_version = rctx.attr.gcc_version, @@ -101,38 +168,28 @@ def _gcc_toolchain_impl(rctx): for include in [ "%workspace%/lib/gcc/{include_prefix}{gcc_version}/include", "%workspace%/lib/gcc/{include_prefix}{gcc_version}/include-fixed", - ] + ([ + ] + ([] if is_native else [ "%workspace%/{include_prefix}include", - ] if target_arch != ARCHS.x86_64 else []) + [ + ]) + [ "%workspace%/sysroot/usr/include", ] ] - cxx_builtin_includes = [] - if target_arch == ARCHS.x86_64: - cxx_builtin_includes.extend([ - include.format( - gcc_version = rctx.attr.gcc_version, - include_prefix = include_prefix, - ) - for include in [ - "%workspace%/include/c++/{gcc_version}", - "%workspace%/include/c++/{gcc_version}/{include_prefix}", - "%workspace%/include/c++/{gcc_version}/backward", - ] - ]) - else: - cxx_builtin_includes.extend([ - include.format( - gcc_version = rctx.attr.gcc_version, - include_prefix = include_prefix, - ) - for include in [ - "%workspace%/{include_prefix}include/c++/{gcc_version}", - "%workspace%/{include_prefix}include/c++/{gcc_version}/{include_prefix}", - "%workspace%/{include_prefix}include/c++/{gcc_version}/backward", - ] + cxx_builtin_includes = [ + include.format( + gcc_version = rctx.attr.gcc_version, + include_prefix = include_prefix, + ) + for include in ([ + "%workspace%/include/c++/{gcc_version}", + "%workspace%/include/c++/{gcc_version}/{include_prefix}", + "%workspace%/include/c++/{gcc_version}/backward", + ] if is_native else [ + "%workspace%/{include_prefix}include/c++/{gcc_version}", + "%workspace%/{include_prefix}include/c++/{gcc_version}/{include_prefix}", + "%workspace%/{include_prefix}include/c++/{gcc_version}/backward", ]) + ] f_builtin_includes = [ include.format( @@ -315,86 +372,170 @@ def _fortran_vars(enable_fortran, gcc_toolchain_workspace_name, include_prefix, AVAILABLE_GCC_VERSIONS = { "12.5.0": { "aarch64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-aarch64.tar.xz", - "sha256": "7b0e25133a98d44b648a925ba11f64a3adc470e87668af80ce2c3af389ebe9be", + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-aarch64.tar.xz", + "sha256": "7b0e25133a98d44b648a925ba11f64a3adc470e87668af80ce2c3af389ebe9be", + }, }, "armv7": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-armv7.tar.xz", - "sha256": "a0ef76c8cc517b3d76dd2f09b1a371975b2ff1082e2f9372ed79af01b9292934", + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-armv7.tar.xz", + "sha256": "a0ef76c8cc517b3d76dd2f09b1a371975b2ff1082e2f9372ed79af01b9292934", + }, }, "x86_64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-x86_64.tar.xz", - "sha256": "51076e175839b434bb2dc0006c0096916df585e8c44666d35b0e3ce821d535db", + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-12.5.0-x86_64.tar.xz", + "sha256": "51076e175839b434bb2dc0006c0096916df585e8c44666d35b0e3ce821d535db", + }, }, }, "13.4.0": { "aarch64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-aarch64.tar.xz", - "sha256": "770cf6bf62bdf78763de526d3a9f5cae4c19f1a3aca0ef8f18b05f1a46d1ffaf", + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-aarch64.tar.xz", + "sha256": "770cf6bf62bdf78763de526d3a9f5cae4c19f1a3aca0ef8f18b05f1a46d1ffaf", + }, }, "armv7": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-armv7.tar.xz", - "sha256": "1b2739b5003c5a3f0ab7c4cc7fb95cc99c0e933982512de7255c2bd9ced757ad", + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-armv7.tar.xz", + "sha256": "1b2739b5003c5a3f0ab7c4cc7fb95cc99c0e933982512de7255c2bd9ced757ad", + }, }, "x86_64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-x86_64.tar.xz", - "sha256": "d96071c1b98499afd7b7b56ebd69ad414020edf66e982004acffe7df8aaf7e02", + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/18082025/gcc-toolchain-13.4.0-x86_64.tar.xz", + "sha256": "d96071c1b98499afd7b7b56ebd69ad414020edf66e982004acffe7df8aaf7e02", + }, }, }, "14.3.0": { "aarch64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-aarch64.tar.xz", - "sha256": "b5a73bc840938c8dbb49e2f15b8b8d63e5c33beae0be2aa9a7c52b593522cdcd", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-aarch64-host-aarch64.tar.xz", + "sha256": "def0f33e644f8586f6ca39754951eebe2189b92823bdaf6d4c4ba42fdad6c598", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-aarch64.tar.xz", + "sha256": "b5a73bc840938c8dbb49e2f15b8b8d63e5c33beae0be2aa9a7c52b593522cdcd", + }, }, "armv7": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-armv7.tar.xz", - "sha256": "376684c062a23e84b619a717fa4c7bba336211c8b48169f76eb5aa6ed4da6bb8", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-armv7-host-aarch64.tar.xz", + "sha256": "ff3e11e2b222fb42146f1254c6a089234e8cd8e384128de56afc781af13d72d9", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-armv7.tar.xz", + "sha256": "376684c062a23e84b619a717fa4c7bba336211c8b48169f76eb5aa6ed4da6bb8", + }, }, "x86_64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-x86_64.tar.xz", - "sha256": "d155a38e4acff9588df466f0edc98c1a2c54d09bc0162805ba38908cfd7a1d28", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-x86_64-host-aarch64.tar.xz", + "sha256": "716ed801e7f2cb35cf25614ffe8e8293934587198e919bcb8c55016c862628f1", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-14.3.0-x86_64.tar.xz", + "sha256": "d155a38e4acff9588df466f0edc98c1a2c54d09bc0162805ba38908cfd7a1d28", + }, }, }, "15.2.0": { "aarch64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-aarch64.tar.xz", - "sha256": "f38696590786e7c99d3bb5b8ce9ed66be6224d505fa45dcae0b2a6ec07eb0570", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-aarch64-host-aarch64.tar.xz", + "sha256": "963b612339998a2dc68aea42ac0928933c0aa4ae18be22f365ec83c86e685b52", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-aarch64.tar.xz", + "sha256": "f38696590786e7c99d3bb5b8ce9ed66be6224d505fa45dcae0b2a6ec07eb0570", + }, }, "armv7": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-armv7.tar.xz", - "sha256": "8ecb5b35aa25efe78772701c70ed27eda727264303d03cffc372a6f24f18be90", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-armv7-host-aarch64.tar.xz", + "sha256": "24a3c48b46cd3d0b80f6a780cdc87e4327e06e7a6ba3b08de9045dda010e6721", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-armv7.tar.xz", + "sha256": "8ecb5b35aa25efe78772701c70ed27eda727264303d03cffc372a6f24f18be90", + }, }, "x86_64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-x86_64.tar.xz", - "sha256": "f31edf791877935258dcc864afbfb7c9f9238be9f7d9da0ee57f5bc121074457", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-x86_64-host-aarch64.tar.xz", + "sha256": "5096ac470ff1023ac337b1fee847d941946401142121f1f094600b854e2569d6", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-15.2.0-x86_64.tar.xz", + "sha256": "f31edf791877935258dcc864afbfb7c9f9238be9f7d9da0ee57f5bc121074457", + }, }, }, "16.1.0": { "aarch64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-aarch64.tar.xz", - "sha256": "4331e513156a699c1015fb94021497306f0a896520efbad8b3e16418eb683468", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-aarch64-host-aarch64.tar.xz", + "sha256": "4492c3160e07f5a931112a1646413b5a0ccaefff1d6ae5dc58d361cb7840d394", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-aarch64.tar.xz", + "sha256": "4331e513156a699c1015fb94021497306f0a896520efbad8b3e16418eb683468", + }, }, "armv7": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-armv7.tar.xz", - "sha256": "8d42c1fd130ccb170fe8d5d17148ae2d3f97134ac0009fdcac87550fec6a6289", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-armv7-host-aarch64.tar.xz", + "sha256": "0f51857564e065113dbec6b106241ec6437b9cba7bb5dedc54ada0fd6ab73e80", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-armv7.tar.xz", + "sha256": "8d42c1fd130ccb170fe8d5d17148ae2d3f97134ac0009fdcac87550fec6a6289", + }, }, "x86_64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-x86_64.tar.xz", - "sha256": "cfd8ca5bc365c1c838825ed6e44c7b2c309aada25791f76ef73b1aec819e362e", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-x86_64-host-aarch64.tar.xz", + "sha256": "7b10a4d5e89d043044e7d7850e0693740bb4643ef231499d1c887759ed7b8615", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/08072026/gcc-toolchain-16.1.0-x86_64.tar.xz", + "sha256": "cfd8ca5bc365c1c838825ed6e44c7b2c309aada25791f76ef73b1aec819e362e", + }, }, }, "16.2.0": { "aarch64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-aarch64.tar.xz", - "sha256": "6407b35116f21c59e98ab5ad68ddd8ff5f3e0469723a5d465ec08ed615b11a55", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-aarch64-host-aarch64.tar.xz", + "sha256": "82a482d269cf75334cb969ef93593655f7e726e855043214e38b3672b10f97de", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-aarch64.tar.xz", + "sha256": "6407b35116f21c59e98ab5ad68ddd8ff5f3e0469723a5d465ec08ed615b11a55", + }, }, "armv7": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-armv7.tar.xz", - "sha256": "515da8a22fa560002d3d149ad701acb725502c70f7bf8d4905f90b0830d38238", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-armv7-host-aarch64.tar.xz", + "sha256": "cb97908d9d375a9e7502898a7277832aa63ca696ffc1088411f0eac921d5d54d", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-armv7.tar.xz", + "sha256": "515da8a22fa560002d3d149ad701acb725502c70f7bf8d4905f90b0830d38238", + }, }, "x86_64": { - "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-x86_64.tar.xz", - "sha256": "54af34c821e59b03ded8f82d3a1104426ec4baaf3b226233e1fd76ad5dcb78cf", + "aarch64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-x86_64-host-aarch64.tar.xz", + "sha256": "600c8d1a6e70eb0b259a01eef3fd4429a43d3cfebe4c6e01659bc6fcf5556415", + }, + "x86_64": { + "url": "https://github.com/f0rmiga/gcc-builds/releases/download/10082026/gcc-toolchain-16.2.0-x86_64.tar.xz", + "sha256": "54af34c821e59b03ded8f82d3a1104426ec4baaf3b226233e1fd76ad5dcb78cf", + }, }, }, } @@ -451,7 +592,17 @@ _FEATURE_ATTRS = { "gcc_versions": attr.string( default = json.encode(AVAILABLE_GCC_VERSIONS), doc = "A JSON dictionary of GCC versions to their download URLs and SHA256 hashes." + - " The structure is {: {: {url: , sha256: }}}.", + " The structure is" + + " {: {: {: {url: , sha256: }}}}." + + " A {url, sha256} directly under is also accepted and means an" + + " x86_64-hosted build.", + ), + "host_arch": attr.string( + doc = "The architecture the toolchain binaries RUN on. E.g. aarch64." + + " Defaults to the architecture Bazel is running on, so a native build needs" + + " no configuration; set it only to fetch a toolchain for a different host.", + default = "", + values = ["", "aarch64", "x86_64"], ), "includes": attr.string_list( doc = "Extra includes for compiling C and C++." + @@ -473,6 +624,14 @@ _FEATURE_ATTRS = { # Attributes of the `toolchain` declarations, which live in the hub rather than in the repository # holding the compiler itself. _TOOLCHAIN_DECLARATION_ATTRS = { + "exec_compatible_with": attr.string_list( + default = [ + "@platforms//os:linux", + "@platforms//cpu:{host_arch}", + ], + doc = "constraint_values passed to exec_compatible_with of the toolchain. {host_arch} is rendered to the host_arch attribute value.", + mandatory = False, + ), "extra_target_compatible_with": attr.label_list( doc = "Additional constraint_values appended to target_compatible_with of the toolchain," + " on top of the values from the target_compatible_with attribute (including its defaults)." + @@ -515,6 +674,14 @@ def _gcc_toolchains_hub_impl(rctx): target_arch = rctx.attr.target_arch gcc_version_flag = str(rctx.attr._gcc_version_flag) + # The toolchain binaries are built FOR host_arch, so that is what can execute them. + # Resolved the same way the toolchain repositories resolve it, since both see the same + # rctx.os.arch. + exec_compatible_with = [ + v.format(host_arch = _resolve_host_arch(rctx)) + for v in rctx.attr.exec_compatible_with + ] + target_compatible_with = [ v.format(target_arch = target_arch) for v in rctx.attr.target_compatible_with @@ -564,6 +731,7 @@ def _gcc_toolchains_hub_impl(rctx): setting = ":_gcc_version_default" if is_default else ":_gcc_version_" + _sanitize_version(gcc_version) content.append(_HUB_TOOLCHAIN_TEMPLATE.format( suffix = suffix, + exec_compatible_with = exec_compatible_with, target_compatible_with = target_compatible_with, target_settings = [setting] + extra_target_settings, toolchain_repo = toolchain_repos[gcc_version], @@ -571,6 +739,7 @@ def _gcc_toolchains_hub_impl(rctx): if rctx.attr.enable_fortran: content.append(_HUB_FORTRAN_TOOLCHAIN_TEMPLATE.format( suffix = suffix, + exec_compatible_with = exec_compatible_with, target_compatible_with = target_compatible_with, target_settings = [setting] + extra_target_settings, toolchain_repo = toolchain_repos[gcc_version], @@ -609,6 +778,9 @@ _gcc_toolchains_hub = repository_rule( doc = "Whether to declare the Fortran toolchains.", default = True, ), + # The same attribute the toolchain repositories take: the hub renders it into + # exec_compatible_with, they use it to pick the archive. + "host_arch": _FEATURE_ATTRS["host_arch"], "target_arch": attr.string( doc = "The target architecture the toolchains produce. E.g. x86_64.", mandatory = True, @@ -634,6 +806,7 @@ ATTRS_SHARED_WITH_MODULE_EXTENSION = { for attr_name in [ "gcc_version", "gcc_versions", + "host_arch", "enable_fortran", "extra_cflags", "extra_cxxflags", @@ -744,6 +917,10 @@ def gcc_declare_toolchain( The attributes of the `toolchain` declarations themselves are also accepted here, since they apply to the hub rather than to `gcc_toolchain`: + `exec_compatible_with`: constraint_values passed to `exec_compatible_with` of the + toolchain. `{host_arch}` is rendered to the `host_arch` argument value. Defaults to + `["@platforms//os:linux", "@platforms//cpu:{host_arch}"]`. + `target_compatible_with`: constraint_values passed to `target_compatible_with` of the toolchain. `{target_arch}` is rendered to the `target_arch` argument value. Defaults to `["@platforms//os:linux", "@platforms//cpu:{target_arch}"]`. @@ -766,10 +943,16 @@ def gcc_declare_toolchain( default_gcc_version = kwargs.pop("gcc_version", DEFAULT_GCC_VERSION) gcc_versions = kwargs.pop("gcc_versions", json.encode(AVAILABLE_GCC_VERSIONS)) enable_fortran = kwargs.pop("enable_fortran", True) + exec_compatible_with = kwargs.pop("exec_compatible_with", None) extra_target_compatible_with = kwargs.pop("extra_target_compatible_with", []) target_compatible_with = kwargs.pop("target_compatible_with", None) target_settings = kwargs.pop("target_settings", []) + # Read by both the hub, which renders it into exec_compatible_with, and every toolchain + # repository, which uses it to pick the archive. Left at "" it resolves to the host + # Bazel is running on, which each repository rule can see for itself. + host_arch = kwargs.pop("host_arch", "") + # Left in kwargs so that the per-version repositories keep receiving it. repo_mapping = kwargs.get("repo_mapping", None) @@ -798,12 +981,18 @@ def gcc_declare_toolchain( fincludes = fincludes, gcc_version = gcc_version, gcc_versions = gcc_versions, + host_arch = host_arch, target_arch = target_arch, **kwargs ) hub_kwargs = {} + # An explicitly empty exec_compatible_with / target_compatible_with drops the default + # constraints, so only an omitted one may fall back to the attribute default. + if exec_compatible_with != None: + hub_kwargs["exec_compatible_with"] = exec_compatible_with + # An explicitly empty target_compatible_with drops the default constraints, so only an omitted # one may fall back to the attribute default. if target_compatible_with != None: @@ -819,6 +1008,7 @@ def gcc_declare_toolchain( default_gcc_version = default_gcc_version, enable_fortran = enable_fortran, extra_target_compatible_with = extra_target_compatible_with, + host_arch = host_arch, target_arch = target_arch, target_settings = target_settings, toolchain_repos = toolchain_repos, @@ -895,10 +1085,7 @@ package(default_visibility = ["//visibility:public"])''' _HUB_TOOLCHAIN_TEMPLATE = '''\ toolchain( name = "cc_toolchain{suffix}", - exec_compatible_with = [ - "@platforms//os:linux", - "@platforms//cpu:x86_64", - ], + exec_compatible_with = {exec_compatible_with}, target_compatible_with = {target_compatible_with}, target_settings = {target_settings}, toolchain = "@{toolchain_repo}//:_cc_toolchain", @@ -908,10 +1095,7 @@ toolchain( _HUB_FORTRAN_TOOLCHAIN_TEMPLATE = '''\ toolchain( name = "fortran_toolchain{suffix}", - exec_compatible_with = [ - "@platforms//os:linux", - "@platforms//cpu:x86_64", - ], + exec_compatible_with = {exec_compatible_with}, target_compatible_with = {target_compatible_with}, target_settings = {target_settings}, toolchain = "@{toolchain_repo}//:_fortran_toolchain", diff --git a/toolchain/module_extensions.bzl b/toolchain/module_extensions.bzl index efe9f27..bb4e182 100644 --- a/toolchain/module_extensions.bzl +++ b/toolchain/module_extensions.bzl @@ -15,6 +15,7 @@ def _gcc_register_toolchain_module_extension(mctx): target_arch = declare.target_arch, gcc_version = declare.gcc_version, gcc_versions = declare.gcc_versions, + host_arch = declare.host_arch, enable_fortran = declare.enable_fortran, extra_cflags = declare.extra_cflags, extra_cxxflags = declare.extra_cxxflags,