Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions cpython-unix/build-cpython.sh
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,16 @@ if [ -n "${CROSS_COMPILING}" ]; then
arm64*|aarch64*|armv7*|thumb7*|ppc64*|s390*|x86*)
CONFIGURE_FLAGS="${CONFIGURE_FLAGS} ac_cv_aligned_required=no"
;;
riscv64*)
# Cross-configure defaults to FNV on RISC-V. SipHash uses memcpy
# for unaligned reads, so select it without changing the target's
# alignment requirements. Preserve each Python version's algorithm.
if [[ -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_10}" ]]; then
CONFIGURE_FLAGS="${CONFIGURE_FLAGS} --with-hash-algorithm=siphash24"
else
CONFIGURE_FLAGS="${CONFIGURE_FLAGS} --with-hash-algorithm=siphash13"
fi
;;
esac

# When cross-compiling, configure defaults to assuming `sem_getvalue` is broken,
Expand Down Expand Up @@ -1098,10 +1108,14 @@ if xcode_path:
# -fdebug-default-version is Clang only. Strip so compiling works on GCC.
replace_in_all("-fdebug-default-version=4", "")

# Target sysroots only exist in the build container. Keeping their paths in
# sysconfig would make downstream extension builds search a nonexistent root.
# Target sysroots and GCC installations only exist in the build container.
# Downstream native extension builds must select their own compiler and linker,
# without inheriting Clang's cross-compilation flags or build-only paths.
for flag in os.environ.get("EXTRA_TARGET_CFLAGS", "").split():
if flag.startswith("--sysroot="):
if (
flag.startswith(("--sysroot=", "--gcc-install-dir=", "--target="))
or flag in ("-fuse-ld=lld", "-Wno-unused-command-line-argument")
):
replace_in_all(flag, "")

# Remove some build environment paths.
Expand Down Expand Up @@ -1131,9 +1145,20 @@ import importlib.machinery
import importlib.util
import json
import os
import runpy
import sys
import sysconfig

# The cross-build helper reads sysconfig from the unmodified build tree.
# Use the cleaned installed values for PYTHON.json as well.
lib_suffix = "t" if os.environ.get("CPYTHON_FREETHREADED") else ""
sysconfig_data = os.path.join(
os.environ["ROOT"], "out", "python", "install", "lib",
"python%s%s" % (sysconfig.get_python_version(), lib_suffix),
sysconfig._get_sysconfigdata_name() + ".py",
)
installed_config_vars = runpy.run_path(sysconfig_data)["build_time_vars"]

# When doing cross builds, sysconfig still picks up abiflags from the
# host Python, which is never built in debug or free-threaded mode. Patch abiflags accordingly.
if os.environ.get("CPYTHON_FREETHREADED") and "t" not in sysconfig.get_config_var("abiflags"):
Expand All @@ -1160,6 +1185,11 @@ extension_suffixes.append(".abi3.so")

extension_suffixes.append(".so")

# Merge into a separate dictionary: newer Python versions can reinitialize
# sysconfig's cache and restore the unmodified build-tree values.
config_vars = dict(sysconfig.get_config_vars())
config_vars.update(installed_config_vars)

metadata = {
"python_abi_tag": sys.abiflags,
"python_implementation_cache_tag": sys.implementation.cache_tag,
Expand All @@ -1180,7 +1210,7 @@ metadata = {
"python_exe": "install/bin/python%s%s" % (sysconfig.get_python_version(), sys.abiflags),
"python_major_minor_version": sysconfig.get_python_version(),
"python_stdlib_platform_config": sysconfig.get_config_var("LIBPL").lstrip("/"),
"python_config_vars": {k: str(v) for k, v in sysconfig.get_config_vars().items()},
"python_config_vars": {k: str(v) for k, v in config_vars.items()},
}

# When cross-compiling, we use a host Python to run this script. There are
Expand Down Expand Up @@ -1214,7 +1244,7 @@ ${BUILD_PYTHON} "${ROOT}/generate_metadata.py" "${ROOT}/metadata.json"
cat "${ROOT}/metadata.json"

if [ "${CC}" != "musl-clang" ]; then
objdump -T "${LIBPYTHON_SHARED_LIBRARY}" | grep GLIBC_ | awk '{print $5}' | awk -F_ '{print $2}' | sort -V | tail -n 1 > "${ROOT}/glibc_version.txt"
objdump -T "${LIBPYTHON_SHARED_LIBRARY}" | grep -oE 'GLIBC_[0-9]+(\.[0-9]+)*' | cut -d_ -f2 | sort -V | tail -n 1 > "${ROOT}/glibc_version.txt"
cat "${ROOT}/glibc_version.txt"
fi

Expand Down
4 changes: 4 additions & 0 deletions cpython-unix/build-libX11.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,9 @@ CFLAGS="${EXTRA_TARGET_CFLAGS} -fPIC -I/tools/deps/include" \
--disable-silent-rules \
${EXTRA_FLAGS}

# Libtool's shared-library link filter drops these Clang cross-compilation
# flags, which would otherwise select host startup objects and runtimes.
sed -i 's/|--sysroot=\*|/|--sysroot=*|--target=*|--gcc-install-dir=*|/g' libtool

make -j "$(nproc)"
make -j "$(nproc)" install DESTDIR="${ROOT}/out"
4 changes: 4 additions & 0 deletions cpython-unix/build-libXau.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@ CFLAGS="${EXTRA_TARGET_CFLAGS} -fPIC" CPPFLAGS="${EXTRA_TARGET_CFLAGS} -fPIC" LD
--prefix=/tools/deps \
${EXTRA_FLAGS}

# Libtool's shared-library link filter drops these Clang cross-compilation
# flags, which would otherwise select host startup objects and runtimes.
sed -i 's/|--sysroot=\*|/|--sysroot=*|--target=*|--gcc-install-dir=*|/g' libtool

make -j "$(nproc)"
make -j "$(nproc)" install DESTDIR="${ROOT}/out"
4 changes: 4 additions & 0 deletions cpython-unix/build-libxcb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,9 @@ CFLAGS="${EXTRA_TARGET_CFLAGS} -fPIC" CPPFLAGS="${EXTRA_TARGET_CFLAGS} -fPIC" L
--prefix=/tools/deps \
${EXTRA_FLAGS}

# Libtool's shared-library link filter drops these Clang cross-compilation
# flags, which would otherwise select host startup objects and runtimes.
sed -i 's/|--sysroot=\*|/|--sysroot=*|--target=*|--gcc-install-dir=*|/g' libtool

make -j "$(nproc)"
make -j "$(nproc)" install DESTDIR="${ROOT}/out"
75 changes: 41 additions & 34 deletions cpython-unix/build.cross-riscv64.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Debian Buster.
FROM debian@sha256:2a0c1b9175adf759420fe0fbd7f5b449038319171eb76554bb76cbe172b62b42
LABEL org.opencontainers.image.authors="Gregory Szorc <gregory.szorc@gmail.com>"
# Debian Trixie
FROM debian@sha256:3352c2e13876c8a5c5873ef20870e1939e73cb9a3c1aeba5e3e72172a85ce9ed
LABEL org.opencontainers.image.authors="Jonathan J. Helmus <jjhelmus@gmail.com>"

RUN groupadd -g 1000 build && \
useradd -u 1000 -g 1000 -d /build -s /bin/bash -m build && \
Expand All @@ -17,23 +17,35 @@ ENV HOME=/build \
CMD ["/bin/bash", "--login"]
WORKDIR '/build'

# curl
RUN apt-get update && apt-get install --yes ca-certificates curl

# Add the LLVM 23 repository.
RUN curl -fsSL https://apt.llvm.org/llvm-snapshot.gpg.key \
-o /etc/apt/trusted.gpg.d/apt.llvm.org.asc \
&& echo "deb https://apt.llvm.org/trixie/ llvm-toolchain-trixie-23 main" \
> /etc/apt/sources.list.d/llvm.list

# Add buster as a source for riscv sysroot packages
RUN for s in debian_buster debian_buster-updates debian-security_buster/updates; do \
echo "deb http://snapshot.debian.org/archive/${s%_*}/20250109T084424Z/ ${s#*_} main"; \
done > /etc/apt/sources.list && \
echo "deb https://snapshot.debian.org/archive/${s%_*}/20250109T084424Z/ ${s#*_} main"; \
done > /etc/apt/sources.list.d/buster.list && \
( echo 'quiet "true";'; \
echo 'APT::Get::Assume-Yes "true";'; \
echo 'APT::Install-Recommends "false";'; \
echo 'Acquire::Check-Valid-Until "false";'; \
echo 'Acquire::Retries "5";'; \
) > /etc/apt/apt.conf.d/99cpython-portable

# Pin the riscv sysroot packages to buster
RUN printf 'Package: *-riscv64-cross\nPin: release n=buster\nPin-Priority: 900\n' \
> /etc/apt/preferences.d/buster-cross

RUN apt-get update

# Host building.
RUN apt-get install \
bzip2 \
gcc \
g++ \
libc6-dev \
libffi-dev \
make \
Expand All @@ -46,32 +58,27 @@ RUN apt-get install \
zip \
zlib1g-dev

# Cross-building.
# LLVM
RUN apt-get install \
clang-23 \
lld-23 \
llvm-23

RUN apt-get install \
g++-aarch64-linux-gnu \
g++-arm-linux-gnueabi \
g++-arm-linux-gnueabihf \
g++-mips-linux-gnu \
g++-mips64el-linux-gnuabi64 \
g++-mipsel-linux-gnu \
g++-powerpc64le-linux-gnu \
g++-riscv64-linux-gnu \
g++-s390x-linux-gnu \
gcc-aarch64-linux-gnu \
gcc-arm-linux-gnueabi \
gcc-arm-linux-gnueabihf \
gcc-mips-linux-gnu \
gcc-mips64el-linux-gnuabi64 \
gcc-mipsel-linux-gnu \
gcc-powerpc64le-linux-gnu \
gcc-riscv64-linux-gnu \
gcc-s390x-linux-gnu \
libc6-dev-arm64-cross \
libc6-dev-armel-cross \
libc6-dev-armhf-cross \
libc6-dev-mips-cross \
libc6-dev-mips64el-cross \
libc6-dev-mipsel-cross \
libc6-dev-ppc64el-cross \
libc6-dev-riscv64-cross \
libc6-dev-s390x-cross
libc6-riscv64-cross \
linux-libc-dev-riscv64-cross \
libgcc1-riscv64-cross \
libgcc-8-dev-riscv64-cross

# Cross libc linker scripts use absolute /usr/riscv64-linux-gnu/lib paths,
# which the linker resolves relative to --sysroot. Mirror that prefix and
# provide the standard include/library directories in the flat cross sysroot.
RUN sysroot=/usr/riscv64-linux-gnu && \
mkdir "${sysroot}/usr" && \
ln -s .. "${sysroot}/usr/riscv64-linux-gnu" && \
ln -s ../include "${sysroot}/usr/include" && \
ln -s ../lib "${sysroot}/usr/lib"

# CPython's configure searches for a target-prefixed archiver when cross-building.
RUN ln -s /usr/lib/llvm-23/bin/llvm-ar /usr/bin/riscv64-unknown-linux-gnu-llvm-ar
14 changes: 8 additions & 6 deletions cpython-unix/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,10 @@ def toolchain_archive_path(package_name, host_platform):
return BUILD / basename


def install_binutils(platform):
return not platform.startswith("macos_")
def install_binutils(host_platform, target_triple):
if "riscv64" in target_triple:
return False
return not host_platform.startswith("macos_")


def simple_build(
Expand All @@ -275,7 +277,7 @@ def simple_build(
host_platform,
target_triple,
binutils_image=docker_image_names(settings)["gcc"],
binutils=install_binutils(host_platform),
binutils=install_binutils(host_platform, target_triple),
clang=True,
musl="musl" in target_triple,
static="static" in build_options,
Expand Down Expand Up @@ -399,7 +401,7 @@ def build_libedit(
host_platform,
target_triple,
binutils_image=docker_image_names(settings)["gcc"],
binutils=install_binutils(host_platform),
binutils=install_binutils(host_platform, target_triple),
clang=True,
musl="musl" in target_triple,
static="static" in build_options,
Expand Down Expand Up @@ -452,7 +454,7 @@ def build_cpython_host(
host_platform,
target_triple,
binutils_image=docker_image_names(settings)["gcc"],
binutils=install_binutils(host_platform),
binutils=install_binutils(host_platform, target_triple),
clang=True,
static="static" in build_options,
)
Expand Down Expand Up @@ -791,7 +793,7 @@ def build_cpython(
host_platform,
target_triple,
binutils_image=docker_image_names(settings)["gcc"],
binutils=install_binutils(host_platform),
binutils=install_binutils(host_platform, target_triple),
clang=True,
musl="musl" in target_triple,
static="static" in build_options,
Expand Down
24 changes: 19 additions & 5 deletions cpython-unix/targets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ riscv64-unknown-linux-gnu:
linux_uapi_include_arch: riscv64-linux-gnu
host_platforms:
- linux_x86_64
- linux_aarch64
- macos_arm64
pythons_supported:
- '3.10'
- '3.11'
Expand All @@ -531,16 +533,29 @@ riscv64-unknown-linux-gnu:
- '3.14'
- '3.15'
docker_image_suffix: .cross-riscv64
host_cc: /usr/bin/x86_64-linux-gnu-gcc
host_cxx: /usr/bin/x86_64-linux-gnu-g++
target_cc: /usr/bin/riscv64-linux-gnu-gcc
target_cxx: /usr/bin/riscv64-linux-gnu-g++
host_cc: clang-23
host_cxx: clang++-23
target_cc: clang-23
target_cxx: clang++-23
target_cflags:
- '--target=riscv64-unknown-linux-gnu'
- '--sysroot=/usr/riscv64-linux-gnu'
# Debian installs GCC startup objects outside the libc sysroot.
- '--gcc-install-dir=/usr/lib/gcc-cross/riscv64-linux-gnu/8'
# Some dependencies also use CFLAGS when linking. Suppress the unused
# linker argument warning in compile-only checks that enable -Werror.
- '-fuse-ld=lld'
- '-Wno-unused-command-line-argument'
# Hardening
- '-fstack-protector'
- '-U_FORTIFY_SOURCE'
- '-D_FORTIFY_SOURCE=2'
target_ldflags:
- '--target=riscv64-unknown-linux-gnu'
- '--sysroot=/usr/riscv64-linux-gnu'
# Debian installs GCC startup objects outside the libc sysroot.
- '--gcc-install-dir=/usr/lib/gcc-cross/riscv64-linux-gnu/8'
- '-fuse-ld=lld'
# Hardening
- '-Wl,-z,noexecstack'
- '-Wl,-z,relro'
Expand All @@ -549,7 +564,6 @@ riscv64-unknown-linux-gnu:
needs:
- autoconf
- bdb
- binutils
- bzip2
- expat
- libedit
Expand Down
6 changes: 5 additions & 1 deletion src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,11 @@ static ELF_ALLOWED_LIBRARIES_BY_TRIPLE: Lazy<HashMap<&'static str, Vec<&'static
("ppc64le-unknown-linux-gnu", vec!["ld64.so.1", "ld64.so.2"]),
(
"riscv64-unknown-linux-gnu",
vec!["ld-linux-riscv64-lp64d.so.1", "libatomic.so.1"],
vec![
"ld-linux-riscv64-lp64d.so.1",
"libatomic.so.1",
"libgcc_s.so.1",
],
),
("s390x-unknown-linux-gnu", vec!["ld64.so.1"]),
(
Expand Down