Skip to content

Commit a253fa4

Browse files
committed
Enable native builds on Linux aarch64
I just published an LLVM 20 toolchain for aarch64. The toolchain has support for PGO and BOLT. This commit switches the Linux aarch64 builds to be performed natively on aarch64 machines. PGO and BOLT are enabled on the builds, hopefully making them a bit faster.
1 parent e591651 commit a253fa4

10 files changed

+108
-29
lines changed

ci-runners.yaml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ depot-ubuntu-22.04:
55
platform: linux
66
free: false
77

8-
# TODO: Enable this runner to perform native builds for aarch64
9-
# depot-ubuntu-22.04-arm:
10-
# arch: aarch64
11-
# platform: linux
12-
# free: false
8+
depot-ubuntu-22.04-arm:
9+
arch: aarch64
10+
platform: linux
11+
free: false
1312

1413
depot-macos-latest:
1514
arch: x86_64

ci-targets.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,11 @@ linux:
5050
- "3.14"
5151
build_options:
5252
- debug
53-
- noopt
54-
- lto
53+
- pgo+lto
5554
build_options_conditional:
5655
- options:
5756
- freethreaded+debug
58-
- freethreaded+noopt
59-
- freethreaded+lto
57+
- freethreaded+pgo+lto
6058
minimum-python-version: "3.13"
6159

6260
armv7-unknown-linux-gnueabi:

cpython-unix/base.debian9.Dockerfile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Debian Stretch.
2+
FROM debian@sha256:c5c5200ff1e9c73ffbf188b4a67eb1c91531b644856b4aefe86a58d2f0cb05be
3+
MAINTAINER Gregory Szorc <[email protected]>
4+
5+
RUN groupadd -g 1000 build && \
6+
useradd -u 1000 -g 1000 -d /build -s /bin/bash -m build && \
7+
mkdir /tools && \
8+
chown -R build:build /build /tools
9+
10+
ENV HOME=/build \
11+
SHELL=/bin/bash \
12+
USER=build \
13+
LOGNAME=build \
14+
HOSTNAME=builder \
15+
DEBIAN_FRONTEND=noninteractive
16+
17+
CMD ["/bin/bash", "--login"]
18+
WORKDIR '/build'
19+
20+
RUN for s in debian_stretch debian_stretch-updates debian-security_stretch/updates; do \
21+
echo "deb http://snapshot.debian.org/archive/${s%_*}/${20230423T032736Z}/ ${s#*_} main"; \
22+
done > /etc/apt/sources.list && \
23+
( echo 'quiet "true";'; \
24+
echo 'APT::Get::Assume-Yes "true";'; \
25+
echo 'APT::Install-Recommends "false";'; \
26+
echo 'Acquire::Check-Valid-Until "false";'; \
27+
echo 'Acquire::Retries "5";'; \
28+
) > /etc/apt/apt.conf.d/99cpython-portable
29+
30+
# apt iterates all available file descriptors up to rlim_max and calls
31+
# fcntl(fd, F_SETFD, FD_CLOEXEC). This can result in millions of system calls
32+
# (we've seen 1B in the wild) and cause operations to take seconds to minutes.
33+
# Setting a fd limit mitigates.
34+
#
35+
# Attempts at enforcing the limit globally via /etc/security/limits.conf and
36+
# /root/.bashrc were not successful. Possibly because container image builds
37+
# don't perform a login or use a shell the way we expect.
38+
RUN ulimit -n 10000 && apt-get update

cpython-unix/build-main.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,13 @@
2929

3030
def main():
3131
if sys.platform == "linux":
32-
host_platform = "linux64"
33-
default_target_triple = "x86_64-unknown-linux-gnu"
32+
machine = platform.machine()
33+
if machine == "aarch64":
34+
host_platform = "linux_aarch64"
35+
default_target_triple = "aarch64-unknown-linux-gnu"
36+
else:
37+
host_platform = "linux64"
38+
default_target_triple = "x86_64-unknown-linux-gnu"
3439
elif sys.platform == "darwin":
3540
host_platform = "macos"
3641
machine = platform.machine()

cpython-unix/build.debian9.Dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{% include 'base.debian9.Dockerfile' %}
2+
3+
RUN ulimit -n 10000 && apt-get install \
4+
bzip2 \
5+
file \
6+
libc6-dev \
7+
libffi-dev \
8+
make \
9+
patch \
10+
perl \
11+
pkg-config \
12+
tar \
13+
xz-utils \
14+
unzip \
15+
zip \
16+
zlib1g-dev

cpython-unix/build.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,17 @@ def add_target_env(env, build_platform, target_triple, build_env):
117117
extra_host_ldflags = []
118118

119119
if build_platform == "linux64":
120-
env["BUILD_TRIPLE"] = "x86_64-unknown-linux-gnu"
120+
machine = platform.machine()
121121

122-
env["TARGET_TRIPLE"] = (
123-
target_triple.replace("x86_64_v2-", "x86_64-")
124-
.replace("x86_64_v3-", "x86_64-")
125-
.replace("x86_64_v4-", "x86_64-")
126-
)
122+
if machine == "aarch64":
123+
env["BUILD_TRIPLE"] = "aarch64-unknown-linux-gnu"
124+
else:
125+
env["BUILD_TRIPLE"] = "x86_64-unknown-linux-gnu"
126+
env["TARGET_TRIPLE"] = (
127+
target_triple.replace("x86_64_v2-", "x86_64-")
128+
.replace("x86_64_v3-", "x86_64-")
129+
.replace("x86_64_v4-", "x86_64-")
130+
)
127131

128132
# This will make x86_64_v2, etc count as cross-compiling. This is
129133
# semantically correct, since the current machine may not support
@@ -516,10 +520,12 @@ def python_build_info(
516520

517521
binary_suffix = ""
518522

519-
if platform == "linux64":
523+
if platform in ("linux64", "linux_aarch64"):
524+
arch = "aarch64" if platform == "linux_aarch64" else "x86_64"
525+
520526
bi["core"]["static_lib"] = (
521-
"install/lib/python{version}/config-{version}{binary_suffix}-x86_64-linux-gnu/libpython{version}{binary_suffix}.a".format(
522-
version=version, binary_suffix=binary_suffix
527+
"install/lib/python{version}/config-{version}{binary_suffix}-{arch}-linux-gnu/libpython{version}{binary_suffix}.a".format(
528+
version=version, binary_suffix=binary_suffix, arch=arch,
523529
)
524530
)
525531

@@ -586,7 +592,7 @@ def python_build_info(
586592
if lib.startswith("-l"):
587593
lib = lib[2:]
588594

589-
if platform == "linux64" and lib not in linux_allowed_system_libraries:
595+
if platform in ("linux64", "linux_aarch64") and lib not in linux_allowed_system_libraries:
590596
raise Exception("unexpected library in LIBS (%s): %s" % (libs, lib))
591597
elif platform == "macos" and lib not in MACOS_ALLOW_SYSTEM_LIBRARIES:
592598
raise Exception("unexpected library in LIBS (%s): %s" % (libs, lib))
@@ -854,7 +860,7 @@ def build_cpython(
854860
extension_module_loading = ["builtin"]
855861
crt_features = []
856862

857-
if host_platform == "linux64":
863+
if host_platform in ("linux64", "linux_aarch64"):
858864
if "static" in parsed_build_options:
859865
crt_features.append("static")
860866
else:

cpython-unix/targets.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,19 +153,24 @@ aarch64-apple-ios:
153153

154154
aarch64-unknown-linux-gnu:
155155
host_platforms:
156-
- linux64
156+
- linux_aarch64
157157
pythons_supported:
158158
- '3.9'
159159
- '3.10'
160160
- '3.11'
161161
- '3.12'
162162
- '3.13'
163163
- '3.14'
164-
docker_image_suffix: .cross
165-
host_cc: /usr/bin/x86_64-linux-gnu-gcc
166-
host_cxx: /usr/bin/x86_64-linux-gnu-g++
167-
target_cc: /usr/bin/aarch64-linux-gnu-gcc
168-
target_cxx: /usr/bin/aarch64-linux-gnu-g++
164+
docker_image_suffix: .debian9
165+
need_toolchain: true
166+
host_cc: clang
167+
host_cxx: clang++
168+
target_cc: clang
169+
target_cxx: clang++
170+
target_cflags:
171+
- '-fvisibility=hidden'
172+
# Needed to prevent BOLT from crashing.
173+
- '-fdebug-default-version=4'
169174
needs:
170175
- autoconf
171176
- bdb
@@ -191,6 +196,7 @@ aarch64-unknown-linux-gnu:
191196
- xz
192197
- zlib
193198
openssl_target: linux-aarch64
199+
bolt_capable: true
194200

195201
arm64-apple-tvos:
196202
host_platforms:

docs/running.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ Common configurations include:
143143
Profile guided optimization.
144144

145145
Starting with CPython 3.12, BOLT is also applied alongside traditional
146-
PGO on platforms supporting BOLT. (Currently just Linux x86-64.)
146+
PGO on platforms supporting BOLT. (Currently just Linux aarch64 and x86-64.)
147147

148148
``lto``
149149
Link-time optimization.

pythonbuild/downloads.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,13 @@
186186
"version": "14.0.3+20220508",
187187
},
188188
# Remember to update LLVM_URL in src/release.rs whenever upgrading.
189+
"llvm-20-aarch64-linux": {
190+
"url": "https://github.com/indygreg/toolchain-tools/releases/download/toolchain-bootstrap%2F20250511/llvm-20.1.4+20250511-gnu_only-aarch64-unknown-linux-gnu.tar.zst",
191+
"size": 255946687,
192+
"sha256": "e70753f294b8f83fffbaf07af36857c27ceaef0291cb10f724ada6af11b0a5bc",
193+
"version": "20.1.4+20250511",
194+
},
195+
# Remember to update LLVM_URL in src/release.rs whenever upgrading.
189196
"llvm-20-x86_64-linux": {
190197
"url": "https://github.com/indygreg/toolchain-tools/releases/download/toolchain-bootstrap%2F20250511/llvm-20.1.4+20250511-gnu_only-x86_64-unknown-linux-gnu.tar.zst",
191198
"size": 299883811,

pythonbuild/utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ def supported_targets(yaml_path: pathlib.Path):
4949
for host_platform in settings["host_platforms"]:
5050
if sys.platform == "linux" and host_platform == "linux64":
5151
targets.add(target)
52+
elif sys.platform == "linux" and host_platform == "linux_aarch64":
53+
targets.add(target)
5254
elif sys.platform == "darwin" and host_platform == "macos":
5355
targets.add(target)
5456

@@ -436,6 +438,8 @@ def clang_toolchain(host_platform: str, target_triple: str) -> str:
436438
return "llvm-14-x86_64-linux"
437439
else:
438440
return "llvm-20-x86_64-linux"
441+
elif host_platform == "linux_aarch64":
442+
return "llvm-20-aarch64-linux"
439443
elif host_platform == "macos":
440444
if platform.mac_ver()[2] == "arm64":
441445
return "llvm-aarch64-macos"

0 commit comments

Comments
 (0)