From f5d76691ae8fa7b841fd72a77bbb283277d73480 Mon Sep 17 00:00:00 2001 From: "M. Chornyi" <99709299+mc-nv@users.noreply.github.com> Date: Tue, 4 Aug 2026 21:48:15 -0700 Subject: [PATCH 1/2] build: Export the stub's dynamic symbols when libpython is static The manylinux base container builds CPython with --disable-shared, so on that platform triton_python_backend_stub links libpython3.x.a and the Py_* symbols live in the executable rather than a shared library. Python C extension modules are dlopen'ed and deliberately leave Py_* undefined -- every one of the 77 lib-dynload modules in the image does, math.so alone with 63 undefined symbols and no libpython in DT_NEEDED -- so they can only bind against the stub's dynamic symbol table. Without the export the stub links and starts, then fails on the first `import math`. Set ENABLE_EXPORTS, which makes CMake add the platform's flag (-Wl,--export-dynamic on Linux, per Platform/Linux.cmake), matching how CPython links its own interpreter. Gate it on the resolved library being an archive rather than on the platform. A shared libpython needs no export, so the Debian build is unaffected, and the condition stays correct if a target moves between the two linkage modes. The condition reads PYTHON_LIBRARY, not PYTHON_LIBRARIES: pybind11 arrives through FetchContent_MakeAvailable, which uses add_subdirectory, so only the cache entry find_library creates crosses back into this scope. PYTHON_LIBRARIES is a plain variable in pybind11's directory and is empty here, which would have made this a silent no-op. --- CMakeLists.txt | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5c5b293..cd80c69a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2020-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# Copyright 2020-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -285,6 +285,30 @@ target_compile_options( ) target_compile_definitions(triton-python-backend-stub PRIVATE TRITON_PB_STUB) +# When libpython is a static archive -- the manylinux base container builds +# CPython with --disable-shared -- the Py_* symbols land inside the stub +# executable instead of a shared library. Python C extension modules are +# dlopen'ed and deliberately leave Py_* undefined, so they can only resolve +# against the stub's dynamic symbol table. ENABLE_EXPORTS makes CMake add the +# platform's flag for that (-Wl,--export-dynamic on Linux), the same way +# CPython links its own interpreter binary. +# +# A shared libpython needs none of this, since modules bind to it directly. +# Key off the linkage rather than the platform so this stays correct if a +# target ever moves between the two. +# +# PYTHON_LIBRARY rather than PYTHON_LIBRARIES: pybind11 is pulled in with +# FetchContent_MakeAvailable, which uses add_subdirectory, so only the cache +# entry that find_library creates survives into this scope. PYTHON_LIBRARIES +# is a plain variable set inside pybind11's directory and reads empty here. +if(PYTHON_LIBRARY MATCHES "\\.a$") + set_target_properties( + triton-python-backend-stub + PROPERTIES + ENABLE_EXPORTS TRUE + ) +endif() + # RHEL assets are not released in a container environment nor do the current # Python lib versions in the manylinux base container match those currently # available for RHEL8 package managers. Therefore, we package the correct From 16a0ecbf54e536e99d98be4c85e3272d46fb3a55 Mon Sep 17 00:00:00 2001 From: "M. Chornyi" <99709299+mc-nv@users.noreply.github.com> Date: Wed, 5 Aug 2026 08:28:01 -0700 Subject: [PATCH 2/2] docs: Correct the stale RHEL_BUILD rationale The comment said RHEL_BUILD existed because pybind would otherwise pick up Python 3.6 in the RHEL base container, so PYBIND11_PYTHON_VERSION was set to force 3.12. That pin has been dropped from build.py -- pybind11 prefers the newest entry of its own Python_ADDITIONAL_VERSIONS list, and the manylinux base container puts a single interpreter first on PATH. RHEL_BUILD itself stays: it still selects the stub's link settings further down. Only the justification was wrong. --- CMakeLists.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd80c69a..d0bcdfed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,9 +93,15 @@ FetchContent_Declare( GIT_SHALLOW ON ) -# RHEL base container has multiple version of Python installed. By default -# it seems like pybind will pickup v3.6, so we specifically assign it to -# search for 3.12 here. +# Detect a RHEL-family build. Used further down to adjust how the stub +# executable is linked. +# +# This used to also justify passing PYBIND11_PYTHON_VERSION, because pybind +# would otherwise pick up an older interpreter present in the RHEL base +# container. That is no longer needed: pybind11 prefers the newest entry of +# its own Python_ADDITIONAL_VERSIONS list, and the manylinux base container +# puts a single interpreter first on PATH. Set PYBIND11_PYTHON_VERSION +# explicitly if a build ever has to target a specific version again. set(RHEL_BUILD OFF) if(LINUX) file(STRINGS "/etc/os-release" DISTRO_ID_LIKE REGEX "ID_LIKE")