Downstream cross-aarch64 recipes with a C++ Python extension (e.g. numba-cuda, libnvshmem) started failing at link time after python-feedstock's aarch64 build was flipped from cross to native. The compiler stack and the recipe-side sed are both unchanged; what changed is what CPython's own configure step emits into the sysconfigdata.
When it landed
The "go native for arm builds" change removed linux_aarch64: linux_64 from conda-forge.yml, landing on 2026-06-11 to 2026-06-12 across every currently-live branch except 3.12:
Each PR bundled the flip with an unrelated main change (version bump or openssl backport); the flip itself is a one-liner in conda-forge.yml.
Symptom (downstream cross-aarch64 link step)
$PREFIX/compiler_compat/ld: $BUILD_PREFIX/bin/../libexec/gcc/aarch64-conda-linux-gnu/14.3.0/liblto_plugin.so: error loading plugin: ... cannot open shared object file: No such file or directory
Misleading error — the actual issue is the aarch64 ld shim in $PREFIX/compiler_compat/ being handed an x86_64 LTO plugin path via --plugin.
Bisect (numba-cuda-feedstock main, last-green vs first-fail)
gcc_impl_linux-aarch64 / binutils_impl_linux-aarch64 / ld_impl_linux-aarch64: identical (14.3.0=h77f067d_19 / 2.45.1=default_hc5fa074_102 / 2.45.1=default_h27e1c4c_102)
python (linux-aarch64): 3.10.20=h28be5d3_0_cpython → 3.10.20=h4f76b5d_1_cpython
Extracting _sysconfigdata_aarch64_conda_linux_gnu.py (the "raw configure" variant, saved before the recipe-side sed) from each package:
h28be5d3_0 (cross-built): 'CXX': 'aarch64-conda-linux-gnu-c++'
h4f76b5d_1 (native-built): 'CXX': 'aarch64-conda-linux-gnu-c++ -pthread'
LDCXXSHARED = "$(CXX) -shared", so it picks up the same -pthread on native. Then recipe/build_base.sh#L453-L456:
sed -i.bak "s@-pthread@-pthread -B $PREFIX/compiler_compat@g" sysconfigfile
turns the default sysconfigdata's LDCXXSHARED into 'g++ -pthread -B $PREFIX/compiler_compat -shared'. Setuptools uses LDCXXSHARED verbatim for C++ extension links, so -B $PREFIX/compiler_compat reaches the cross-toolchain link line and routes ld through the aarch64 shim. On a linux-64 build host driving an x86_64 GCC, the aarch64 ld can't handle the x86_64 LTO plugin GCC hands it via --plugin, and the link fails.
Why C-only cross-builds haven't been failing the same way
LDSHARED has always had -B $PREFIX/compiler_compat in it too, but patch 0019-Fix-LDSHARED-when-CC-is-overriden-on-Linux-too.patch makes distutils' customize_compiler strip the sysconfig CC prefix off LDSHARED and replace it with os.environ['CC']. Since LDSHARED starts with exactly the sysconfig CC string ('gcc -pthread -B $PREFIX/compiler_compat'), the entire -pthread -B compiler_compat chunk is consumed along with gcc, leaving only -shared -Wl,... in the resulting command. No equivalent exists for LDCXXSHARED, so it's used as-is.
Why 3.12 isn't affected
The 3.12 branch of this feedstock still has linux_aarch64: linux_64 in conda-forge.yml — it wasn't included in the "go native" flip. Correspondingly, only linux_aarch64_python3.12 passes in numba-cuda-feedstock run 28638905979; all other Python versions fail on aarch64.
Confirmed affected feedstocks
Suggested fixes
- Extend patch
0019 to also strip the sysconfig CXX prefix off LDCXXSHARED — symmetric with the C side. Preserves the sed's intent for native/system-gcc users.
- Or scope the sed itself away from
CXX/LDCXXSHARED so -pthread -B compiler_compat never enters those vars.
Happy to test either against numba-cuda-feedstock's CI once a rebuild is available.
Downstream cross-aarch64 recipes with a C++ Python extension (e.g. numba-cuda, libnvshmem) started failing at link time after python-feedstock's aarch64 build was flipped from cross to native. The compiler stack and the recipe-side sed are both unchanged; what changed is what CPython's own
configurestep emits into the sysconfigdata.When it landed
The "go native for arm builds" change removed
linux_aarch64: linux_64fromconda-forge.yml, landing on 2026-06-11 to 2026-06-12 across every currently-live branch except3.12:main:babe1dd57bin python v3.14.6 #8743.13:5a74e3a0abin python v3.13.14 #8773.11:e20ad42441in [3.11] backport fix for stricter openssl #8753.10:5ddb2eb7c5in [3.10] backport fix for stricter openssl #876Each PR bundled the flip with an unrelated main change (version bump or openssl backport); the flip itself is a one-liner in
conda-forge.yml.Symptom (downstream cross-aarch64 link step)
Misleading error — the actual issue is the aarch64
ldshim in$PREFIX/compiler_compat/being handed an x86_64 LTO plugin path via--plugin.Bisect (numba-cuda-feedstock main, last-green vs first-fail)
gcc_impl_linux-aarch64/binutils_impl_linux-aarch64/ld_impl_linux-aarch64: identical (14.3.0=h77f067d_19/2.45.1=default_hc5fa074_102/2.45.1=default_h27e1c4c_102)python(linux-aarch64):3.10.20=h28be5d3_0_cpython→3.10.20=h4f76b5d_1_cpythonExtracting
_sysconfigdata_aarch64_conda_linux_gnu.py(the "raw configure" variant, saved before the recipe-side sed) from each package:h28be5d3_0(cross-built):'CXX': 'aarch64-conda-linux-gnu-c++'h4f76b5d_1(native-built):'CXX': 'aarch64-conda-linux-gnu-c++ -pthread'LDCXXSHARED = "$(CXX) -shared", so it picks up the same-pthreadon native. Thenrecipe/build_base.sh#L453-L456:sed -i.bak "s@-pthread@-pthread -B $PREFIX/compiler_compat@g" sysconfigfileturns the default sysconfigdata's
LDCXXSHAREDinto'g++ -pthread -B $PREFIX/compiler_compat -shared'. Setuptools usesLDCXXSHAREDverbatim for C++ extension links, so-B $PREFIX/compiler_compatreaches the cross-toolchain link line and routesldthrough the aarch64 shim. On a linux-64 build host driving an x86_64 GCC, the aarch64ldcan't handle the x86_64 LTO plugin GCC hands it via--plugin, and the link fails.Why C-only cross-builds haven't been failing the same way
LDSHAREDhas always had-B $PREFIX/compiler_compatin it too, but patch0019-Fix-LDSHARED-when-CC-is-overriden-on-Linux-too.patchmakes distutils'customize_compilerstrip the sysconfigCCprefix offLDSHAREDand replace it withos.environ['CC']. SinceLDSHAREDstarts with exactly the sysconfigCCstring ('gcc -pthread -B $PREFIX/compiler_compat'), the entire-pthread -B compiler_compatchunk is consumed along withgcc, leaving only-shared -Wl,...in the resulting command. No equivalent exists forLDCXXSHARED, so it's used as-is.Why 3.12 isn't affected
The
3.12branch of this feedstock still haslinux_aarch64: linux_64inconda-forge.yml— it wasn't included in the "go native" flip. Correspondingly, onlylinux_aarch64_python3.12passes in numba-cuda-feedstock run 28638905979; all other Python versions fail on aarch64.Confirmed affected feedstocks
-fno-use-linker-pluginSuggested fixes
0019to also strip the sysconfigCXXprefix offLDCXXSHARED— symmetric with the C side. Preserves the sed's intent for native/system-gcc users.CXX/LDCXXSHAREDso-pthread -B compiler_compatnever enters those vars.Happy to test either against numba-cuda-feedstock's CI once a rebuild is available.