Skip to content

Commit 3176328

Browse files
committed
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++/<version>`) 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 <string>. 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.
1 parent ed8c2ab commit 3176328

10 files changed

Lines changed: 432 additions & 90 deletions

File tree

MODULE.bazel

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ gcc_toolchains = use_extension("//toolchain:module_extensions.bzl", "gcc_toolcha
3333
]
3434
]
3535

36+
# An aarch64-HOSTED toolchain, for //tests/host_arch. Deliberately not registered: its
37+
# binaries are ARM, so it cannot execute on an x86_64 CI machine -- the test only inspects
38+
# the fetched archive.
39+
gcc_toolchains.toolchain(
40+
name = "gcc_toolchain_aarch64_host",
41+
gcc_version = "14.3.0",
42+
host_arch = "aarch64",
43+
target_arch = "aarch64",
44+
)
45+
use_repo(gcc_toolchains, "gcc_toolchain_aarch64_host")
46+
3647
# Dev Dependencies (for examples/)
3748
# ===============================
3849
bazel_dep(name = "rules_foreign_cc", version = "0.15.1", dev_dependency = True)

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ performance and portability. You can find the comprehensive documentation under
66

77
## Features
88

9-
- **Multi-architecture**: Support for x86_64, aarch64, and armv7 Linux targets.
9+
- **Multi-architecture**: Support for x86_64, aarch64, and armv7 Linux targets,
10+
hosted on x86_64 or aarch64.
1011
- **Hermetic**: Fully self-contained with no system dependencies.
1112
- **Optimized**: Reduced toolchain sizes and improved build performance.
1213
- **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
4243

4344
* **First-party Code**: Your repository contains C/C++/Fortran code.
4445
* **Sanitizer Testing**: Need to run sanitizers (asan, lsan, tsan, ubsan) on your code.
45-
* **Cross-compilation**: Build for Linux armv7 or aarch64 from x86_64.
46+
* **Cross-compilation**: Build for Linux armv7, aarch64 or x86_64 from x86_64 or aarch64.
4647
* **Portability**: Create binaries compatible with any Linux distribution.
4748
* **Reproducibility**: Ensure consistent builds across development and CI environments.
4849
* **Remote Execution**: Use with Bazel RBE for distributed builds.

WORKSPACE

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ load("@bazel_lib//lib:repositories.bzl", "bazel_lib_dependencies")
4141

4242
bazel_lib_dependencies()
4343

44-
load("//toolchain:defs.bzl", "ARCHS", "gcc_register_toolchain")
44+
load("//toolchain:defs.bzl", "ARCHS", "gcc_declare_toolchain", "gcc_register_toolchain")
4545

4646
gcc_register_toolchain(
4747
name = "gcc_toolchain_aarch64",
@@ -58,6 +58,16 @@ gcc_register_toolchain(
5858
target_arch = ARCHS.x86_64,
5959
)
6060

61+
# An aarch64-HOSTED toolchain, for //tests/host_arch. DECLARED, not registered: its
62+
# binaries are ARM, so it cannot execute on an x86_64 CI machine -- the test only inspects
63+
# the fetched archive.
64+
gcc_declare_toolchain(
65+
name = "gcc_toolchain_aarch64_host",
66+
gcc_version = "14.3.0",
67+
host_arch = ARCHS.aarch64,
68+
target_arch = ARCHS.aarch64,
69+
)
70+
6171
load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies")
6272

6373
rules_foreign_cc_dependencies()

docs/README.md

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/defs.md

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/updating-gcc-builds.md

Lines changed: 26 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/host_arch/BUILD.bazel

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright (c) Thulio Ferraz Assis 2026
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
load("@rules_shell//shell:sh_test.bzl", "sh_test")
16+
17+
# The aarch64-hosted toolchain, declared (not registered) as @gcc_toolchain_aarch64_host.
18+
# Its binaries are ARM, so they cannot be RUN on an x86_64 CI machine; this inspects the
19+
# fetched archive instead, which works on any host.
20+
#
21+
# `include` carries the builtin header tree, so requiring it as data also proves the layout
22+
# the toolchain declares is the layout the archive actually has -- a nonexistent -isystem
23+
# path is otherwise ignored silently, surfacing much later as a missing <string>.
24+
#
25+
# gcc-builds only publishes -host-aarch64 archives from the 08072026 release on, so the
26+
# versions pinned to older releases have no aarch64-hosted build to inspect and the test is
27+
# skipped for them, as in //tests/lld. Being incompatible keeps the target unanalyzed, so
28+
# the archive that does not exist is never fetched.
29+
sh_test(
30+
name = "host_arch_test",
31+
srcs = ["host_arch_test.sh"],
32+
data = [
33+
"@gcc_toolchain_aarch64_host//:gcc",
34+
"@gcc_toolchain_aarch64_host//:include",
35+
],
36+
env = {"GCC_FILES": "$(locations @gcc_toolchain_aarch64_host//:gcc)"},
37+
target_compatible_with = select({
38+
"//toolchain:gcc_version_12_5_0": ["@platforms//:incompatible"],
39+
"//toolchain:gcc_version_13_4_0": ["@platforms//:incompatible"],
40+
"//conditions:default": [],
41+
}),
42+
)

tests/host_arch/host_arch_test.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env bash
2+
# Copyright (c) Thulio Ferraz Assis 2026
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
# An aarch64-hosted toolchain must ship ARM binaries. Verified by inspecting the archive
17+
# rather than running it, so this test works on any host.
18+
19+
set -euo pipefail
20+
21+
gcc=""
22+
for f in ${GCC_FILES}; do
23+
if [[ "${f}" == *-gcc ]]; then
24+
gcc="${f}"
25+
break
26+
fi
27+
done
28+
29+
if [[ -z "${gcc}" ]]; then
30+
echo >&2 "FAIL: no *-gcc among the toolchain's compiler files: ${GCC_FILES}"
31+
exit 1
32+
fi
33+
34+
# ELF e_machine, at offset 18, little-endian: 0x00b7 is EM_AARCH64, 0x003e is x86-64. An
35+
# x86_64-hosted build here would mean the toolchain cannot run on an aarch64 machine at
36+
# all, which is the bug the host_arch attribute exists to fix.
37+
readonly machine="$(od -An -tx1 -j18 -N2 "${gcc}" | tr -d ' \n')"
38+
if [[ "${machine}" != "b700" ]]; then
39+
echo >&2 "FAIL: ${gcc} has e_machine 0x${machine}, want 0xb7 (EM_AARCH64)."
40+
exit 1
41+
fi
42+
43+
echo "PASS: the aarch64-hosted toolchain ships ARM binaries."

0 commit comments

Comments
 (0)