diff --git a/ci-targets.yaml b/ci-targets.yaml index c59d5b7f..492b815c 100644 --- a/ci-targets.yaml +++ b/ci-targets.yaml @@ -348,6 +348,26 @@ linux: minimum-python-version: "3.13" run: true + aarch64-unknown-linux-musl: + arch: aarch64 + libc: musl + python_versions: + - "3.9" + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" + build_options: + # TODO: Static support is current blocked by some compiler-rt linking issues + # - debug+static + # - noopt+static + # - lto+static + - debug + - noopt + - lto + run: true + windows: i686-pc-windows-msvc: arch: x86 diff --git a/cpython-unix/build-cpython-host.sh b/cpython-unix/build-cpython-host.sh index 99b021d7..ff7c3a45 100755 --- a/cpython-unix/build-cpython-host.sh +++ b/cpython-unix/build-cpython-host.sh @@ -70,6 +70,11 @@ case "${BUILD_TRIPLE}" in EXTRA_HOST_CPPFLAGS="${EXTRA_HOST_CPPFLAGS} -I/usr/include/x86_64-linux-gnu" EXTRA_HOST_LDFLAGS="${EXTRA_HOST_LDFLAGS} -L/usr/lib/x86_64-linux-gnu" ;; + aarch64-unknown-linux-gnu) + EXTRA_HOST_CFLAGS="${EXTRA_HOST_CFLAGS} -I/usr/include/aarch64-linux-gnu" + EXTRA_HOST_CPPFLAGS="${EXTRA_HOST_CPPFLAGS} -I/usr/include/aarch64-linux-gnu" + EXTRA_HOST_LDFLAGS="${EXTRA_HOST_LDFLAGS} -L/usr/lib/aarch64-linux-gnu" + ;; *) ;; esac diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh index 658395a9..30b0d2b2 100755 --- a/cpython-unix/build-cpython.sh +++ b/cpython-unix/build-cpython.sh @@ -1077,8 +1077,14 @@ touch "${LIB_DYNLOAD}/.empty" # Symlink libpython so we don't have 2 copies. case "${TARGET_TRIPLE}" in -aarch64-unknown-linux-gnu) - PYTHON_ARCH="aarch64-linux-gnu" +aarch64-unknown-linux-*) + # In Python 3.13+, the musl target is identified in cross compiles and the output directory + # is named accordingly. + if [[ "${CC}" = "musl-clang" && -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]]; then + PYTHON_ARCH="aarch64-linux-musl" + else + PYTHON_ARCH="aarch64-linux-gnu" + fi ;; # This is too aggressive. But we don't have patches in place for # setting the platform name properly on non-Darwin. diff --git a/cpython-unix/build-zstd.sh b/cpython-unix/build-zstd.sh index 5a889da5..bcce804b 100755 --- a/cpython-unix/build-zstd.sh +++ b/cpython-unix/build-zstd.sh @@ -15,16 +15,20 @@ tar -xf zstd-${ZSTD_VERSION}.tar.gz pushd cpython-source-deps-zstd-${ZSTD_VERSION}/lib if [ "${CC}" = "musl-clang" ]; then - # In order to build the library with SSE2, BMI, and AVX2 intrinstics, we need musl-clang to find + # In order to build the library with intrinsics, we need musl-clang to find # headers that provide access to the intrinsics, as they are not provided by musl. These are # part of the include files that are part of clang. But musl-clang eliminates them from the # default include path. So copy them into place. - for h in ${TOOLS_PATH}/${TOOLCHAIN}/lib/clang/*/include/*intrin.h ${TOOLS_PATH}/${TOOLCHAIN}/lib/clang/*/include/{__wmmintrin_aes.h,__wmmintrin_pclmul.h,emmintrin.h,immintrin.h,mm_malloc.h}; do + for h in ${TOOLS_PATH}/${TOOLCHAIN}/lib/clang/*/include/*intrin.h ${TOOLS_PATH}/${TOOLCHAIN}/lib/clang/*/include/{__wmmintrin_aes.h,__wmmintrin_pclmul.h,emmintrin.h,immintrin.h,mm_malloc.h,arm_neon.h,arm_neon_sve_bridge.h,arm_bf16.h,arm_fp16.h,arm_acle.h,arm_vector_types.h}; do filename=$(basename "$h") - if [ -e "${TOOLS_PATH}/host/include/${filename}" ]; then - echo "warning: ${filename} already exists" + if [ -f "$h" ]; then + if [ -e "${TOOLS_PATH}/host/include/${filename}" ]; then + echo "warning: ${filename} already exists" + fi + cp "$h" ${TOOLS_PATH}/host/include/ + else + echo "warning: ${filename} not found (skipping)" fi - cp "$h" ${TOOLS_PATH}/host/include/ done EXTRA_TARGET_CFLAGS="${EXTRA_TARGET_CFLAGS} -I${TOOLS_PATH}/host/include/" @@ -33,7 +37,7 @@ if [ "${CC}" = "musl-clang" ]; then # `qsort_r` is actually available so we patch it to include a check for glibc. patch -p1 <suffix, ctx->suffixSize, sizeof(U32), ctx, diff --git a/cpython-unix/build.py b/cpython-unix/build.py index ea44c294..138a9c9b 100755 --- a/cpython-unix/build.py +++ b/cpython-unix/build.py @@ -88,6 +88,11 @@ def add_target_env(env, build_platform, target_triple, build_env): extra_host_cflags = [] extra_host_ldflags = [] + # Add compiler-rt for aarch64-musl to resolve missing builtins + if target_triple == "aarch64-unknown-linux-musl": + extra_target_cflags.append("--rtlib=compiler-rt") + extra_target_ldflags.append("--rtlib=compiler-rt") + if build_platform.startswith("linux_"): machine = platform.machine() diff --git a/cpython-unix/targets.yml b/cpython-unix/targets.yml index d0ef4a78..451b9840 100644 --- a/cpython-unix/targets.yml +++ b/cpython-unix/targets.yml @@ -1131,3 +1131,50 @@ x86_64_v4-unknown-linux-musl: - zlib - zstd openssl_target: linux-x86_64 + +aarch64-unknown-linux-musl: + host_platforms: + - linux_x86_64 + - linux_aarch64 + pythons_supported: + - '3.9' + - '3.10' + - '3.11' + - '3.12' + - '3.13' + - '3.14' + needs_toolchain: true + docker_image_suffix: .debian9 + needs_toolchain: true + host_cc: clang + host_cxx: clang++ + target_cc: musl-clang + target_cxx: clang++ + target_cflags: + - '-fvisibility=hidden' + needs: + - autoconf + - bdb + - binutils + - bzip2 + - expat + - libedit + - libffi-3.3 + - libX11 + - libXau + - libxcb + - m4 + - mpdecimal + - musl + - ncurses + - openssl-3.0 + - patchelf + - sqlite + - tcl + - tk + - uuid + - xorgproto + - xz + - zlib + - zstd + openssl_target: linux-aarch64 diff --git a/src/release.rs b/src/release.rs index 0b67888d..4c123f61 100644 --- a/src/release.rs +++ b/src/release.rs @@ -339,6 +339,18 @@ pub static RELEASE_TRIPLES: Lazy> = Lazy:: }], }, ); + h.insert( + "aarch64-unknown-linux-musl", + TripleRelease { + suffixes: vec!["debug", "lto", "noopt"], + install_only_suffix: "lto", + python_version_requirement: None, + conditional_suffixes: vec![ConditionalSuffixes { + python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), + suffixes: linux_suffixes_musl_freethreaded.clone(), + }], + }, + ); h }); diff --git a/src/validation.rs b/src/validation.rs index 6d9b5dbf..163e7b01 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -35,6 +35,7 @@ const RECOGNIZED_TRIPLES: &[&str] = &[ "aarch64-apple-ios", "aarch64-pc-windows-msvc", "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", "armv7-unknown-linux-gnueabi", "armv7-unknown-linux-gnueabihf", "arm64-apple-tvos", @@ -211,6 +212,10 @@ static GLIBC_MAX_VERSION_BY_TRIPLE: Lazy> = Lazy: ("aarch64-apple-ios", "iOS-aarch64"), ("aarch64-pc-windows-msvc", "win-arm64"), ("aarch64-unknown-linux-gnu", "linux-aarch64"), + ("aarch64-unknown-linux-musl", "linux-aarch64"), ("armv7-unknown-linux-gnueabi", "linux-arm"), ("armv7-unknown-linux-gnueabihf", "linux-arm"), ("i686-pc-windows-msvc", "win32"), @@ -949,6 +955,7 @@ fn validate_elf>( let wanted_cpu_type = match target_triple { "aarch64-unknown-linux-gnu" => object::elf::EM_AARCH64, + "aarch64-unknown-linux-musl" => object::elf::EM_AARCH64, "armv7-unknown-linux-gnueabi" => object::elf::EM_ARM, "armv7-unknown-linux-gnueabihf" => object::elf::EM_ARM, "i686-unknown-linux-gnu" => object::elf::EM_386,