From 3d6d70c570dd48a4f6cc9b536b3f392f388ac297 Mon Sep 17 00:00:00 2001 From: Tianlei WU Date: Fri, 12 Dec 2025 17:24:15 -0800 Subject: [PATCH 1/7] Py_GIL_DISABLED --- cmake/onnxruntime_python.cmake | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index 1456c8caa8993..40dff4092d84f 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -69,6 +69,19 @@ endif() onnxruntime_add_shared_library_module(onnxruntime_pybind11_state ${onnxruntime_pybind_srcs}) +if (Python_EXECUTABLE) + execute_process( + COMMAND "${Python_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" + OUTPUT_VARIABLE Py_GIL_DISABLED_VALUE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if ("${Py_GIL_DISABLED_VALUE}" STREQUAL "1") + message(STATUS "Py_GIL_DISABLED=1 detected: enabling free-threaded support for onnxruntime_pybind11_state") + target_compile_definitions(onnxruntime_pybind11_state PRIVATE Py_GIL_DISABLED=1) + endif() +endif() + if(MSVC) # The following source file is only needed for the EPs that use delayloading. Namely, DML and WebGPU. target_sources(onnxruntime_pybind11_state PRIVATE "${ONNXRUNTIME_ROOT}/core/dll/delay_load_hook.cc") From ea8a28e74000fb9a150dc841a5aac1d60af32243 Mon Sep 17 00:00:00 2001 From: Tianlei WU Date: Mon, 15 Dec 2025 11:25:59 -0800 Subject: [PATCH 2/7] refine --- cmake/onnxruntime_python.cmake | 57 ++++++++++++++++--- .../python/onnxruntime_pybind_module.cc | 5 ++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index 40dff4092d84f..aeab5c8d2f2ce 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -70,15 +70,58 @@ endif() onnxruntime_add_shared_library_module(onnxruntime_pybind11_state ${onnxruntime_pybind_srcs}) if (Python_EXECUTABLE) - execute_process( - COMMAND "${Python_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" - OUTPUT_VARIABLE Py_GIL_DISABLED_VALUE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}") + message(STATUS "Python3_INCLUDE_DIRS: ${Python3_INCLUDE_DIRS}") + message(STATUS "Python3_LIBRARIES: ${Python3_LIBRARIES}") + + # Use a cached variable so we don't re-run detection on every configure + if (NOT DEFINED ORT_PYTHON_FREE_THREADED_DETECTED) + message(STATUS "Checking for Free-threaded Python environment...") + + # Check 1: Query Py_GIL_DISABLED directly (PEP 703) + execute_process( + COMMAND "${Python_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" + RESULT_VARIABLE _py_result + OUTPUT_VARIABLE Py_GIL_DISABLED_VALUE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if (NOT _py_result EQUAL 0) + message(WARNING "Failed to query Py_GIL_DISABLED from Python interpreter. Result: ${_py_result}") + set(Py_GIL_DISABLED_VALUE "0") + endif() + + # Handle explicit "None" string or empty output (common on Windows/older Pythons) + if (Py_GIL_DISABLED_VALUE STREQUAL "" OR Py_GIL_DISABLED_VALUE STREQUAL "None") + set(Py_GIL_DISABLED_VALUE "0") + + # Check 2: Fallback to ABI flags if config var wasn't explicit + execute_process( + COMMAND "${Python_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_config_var('ABIFLAGS') or sysconfig.get_config_var('SOABI') or '')" + RESULT_VARIABLE _abi_result + OUTPUT_VARIABLE Py_ABI_VALUE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) - if ("${Py_GIL_DISABLED_VALUE}" STREQUAL "1") - message(STATUS "Py_GIL_DISABLED=1 detected: enabling free-threaded support for onnxruntime_pybind11_state") + if (_abi_result EQUAL 0) + # Safer regex: Matches "t" at end of string or before a hyphen (e.g., "cp313t-win_amd64") + # OR matches standard ABI string pattern like "cp313t" + if ("${Py_ABI_VALUE}" MATCHES "cp[0-9]+t" OR "${Py_ABI_VALUE}" MATCHES "t(-|$)") + set(Py_GIL_DISABLED_VALUE "1") + message(STATUS "Detected 't' suffix in Python ABI flags (${Py_ABI_VALUE}). Assuming Free-threaded build.") + endif() + endif() + endif() + + # Cache the result + set(ORT_PYTHON_FREE_THREADED_DETECTED "${Py_GIL_DISABLED_VALUE}" CACHE STRING "Detected free-threaded Python status" FORCE) + endif() + + if ("${ORT_PYTHON_FREE_THREADED_DETECTED}" STREQUAL "1") + message(STATUS "Py_GIL_DISABLED=1 detected: Enabling free-threaded support for onnxruntime_pybind11_state") target_compile_definitions(onnxruntime_pybind11_state PRIVATE Py_GIL_DISABLED=1) + else() + message(STATUS "Free-threaded Python support NOT enabled.") endif() endif() diff --git a/onnxruntime/python/onnxruntime_pybind_module.cc b/onnxruntime/python/onnxruntime_pybind_module.cc index a067f8d548799..5bf16439c0917 100644 --- a/onnxruntime/python/onnxruntime_pybind_module.cc +++ b/onnxruntime/python/onnxruntime_pybind_module.cc @@ -102,7 +102,12 @@ static constexpr bool HAS_COLLECTIVE_OPS = false; void CreateQuantPybindModule(py::module& m); +// Check if we are building with GIL disabled (Free-threaded) +#ifdef Py_GIL_DISABLED +PYBIND11_MODULE(onnxruntime_pybind11_state, m, py::mod_gil_not_used()) { +#else PYBIND11_MODULE(onnxruntime_pybind11_state, m) { +#endif auto st = CreateInferencePybindStateModule(m); if (!st.IsOK()) throw pybind11::import_error(st.ErrorMessage()); From 4a5a0a7902da99493216c6e9e1349c8d57cdceab Mon Sep 17 00:00:00 2001 From: Tianlei WU Date: Mon, 15 Dec 2025 11:34:03 -0800 Subject: [PATCH 3/7] refine --- cmake/onnxruntime_python.cmake | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index aeab5c8d2f2ce..df69aa5bcb0ec 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -91,7 +91,8 @@ if (Python_EXECUTABLE) set(Py_GIL_DISABLED_VALUE "0") endif() - # Handle explicit "None" string or empty output (common on Windows/older Pythons) + # Handle explicit "None" string or empty output + # (common on Windows and pre-PEP 703 Python builds where the var is unset) if (Py_GIL_DISABLED_VALUE STREQUAL "" OR Py_GIL_DISABLED_VALUE STREQUAL "None") set(Py_GIL_DISABLED_VALUE "0") @@ -104,8 +105,7 @@ if (Python_EXECUTABLE) ) if (_abi_result EQUAL 0) - # Safer regex: Matches "t" at end of string or before a hyphen (e.g., "cp313t-win_amd64") - # OR matches standard ABI string pattern like "cp313t" + # Matches "cp313t", "cp314t" etc., or "t" followed by hyphen/end-of-string (e.g., "cp313t-win_amd64") if ("${Py_ABI_VALUE}" MATCHES "cp[0-9]+t" OR "${Py_ABI_VALUE}" MATCHES "t(-|$)") set(Py_GIL_DISABLED_VALUE "1") message(STATUS "Detected 't' suffix in Python ABI flags (${Py_ABI_VALUE}). Assuming Free-threaded build.") @@ -113,11 +113,18 @@ if (Python_EXECUTABLE) endif() endif() - # Cache the result - set(ORT_PYTHON_FREE_THREADED_DETECTED "${Py_GIL_DISABLED_VALUE}" CACHE STRING "Detected free-threaded Python status" FORCE) + # Normalize to 0/1 to avoid edge cases downstream + if (NOT Py_GIL_DISABLED_VALUE STREQUAL "1") + set(Py_GIL_DISABLED_VALUE "0") + endif() + + # Cache the result as BOOL so users can override it (e.g. -DORT_PYTHON_FREE_THREADED_DETECTED=OFF) + set(ORT_PYTHON_FREE_THREADED_DETECTED "${Py_GIL_DISABLED_VALUE}" CACHE BOOL "Detected free-threaded Python status" FORCE) + else() + message(STATUS "Using cached free-threaded Python detection: ORT_PYTHON_FREE_THREADED_DETECTED=${ORT_PYTHON_FREE_THREADED_DETECTED}") endif() - if ("${ORT_PYTHON_FREE_THREADED_DETECTED}" STREQUAL "1") + if (ORT_PYTHON_FREE_THREADED_DETECTED) message(STATUS "Py_GIL_DISABLED=1 detected: Enabling free-threaded support for onnxruntime_pybind11_state") target_compile_definitions(onnxruntime_pybind11_state PRIVATE Py_GIL_DISABLED=1) else() From 5ae0841f35afc6d45a00dffd3db88be179cbc678 Mon Sep 17 00:00:00 2001 From: Tianlei WU Date: Mon, 15 Dec 2025 12:04:11 -0800 Subject: [PATCH 4/7] clean up --- cmake/onnxruntime_python.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index df69aa5bcb0ec..d4758b207ea25 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -71,8 +71,6 @@ onnxruntime_add_shared_library_module(onnxruntime_pybind11_state ${onnxruntime_p if (Python_EXECUTABLE) message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}") - message(STATUS "Python3_INCLUDE_DIRS: ${Python3_INCLUDE_DIRS}") - message(STATUS "Python3_LIBRARIES: ${Python3_LIBRARIES}") # Use a cached variable so we don't re-run detection on every configure if (NOT DEFINED ORT_PYTHON_FREE_THREADED_DETECTED) From 3ab257abcb76b6b8c0ff97745c1e2ac99ca7a308 Mon Sep 17 00:00:00 2001 From: Tianlei WU Date: Mon, 15 Dec 2025 16:14:54 -0800 Subject: [PATCH 5/7] clean --- cmake/onnxruntime_python.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index d4758b207ea25..46a69a413b36c 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -124,7 +124,6 @@ if (Python_EXECUTABLE) if (ORT_PYTHON_FREE_THREADED_DETECTED) message(STATUS "Py_GIL_DISABLED=1 detected: Enabling free-threaded support for onnxruntime_pybind11_state") - target_compile_definitions(onnxruntime_pybind11_state PRIVATE Py_GIL_DISABLED=1) else() message(STATUS "Free-threaded Python support NOT enabled.") endif() From 75a95c1ca796b4f3283d82741aaae5cbdc332f84 Mon Sep 17 00:00:00 2001 From: Tianlei WU Date: Tue, 16 Dec 2025 11:45:37 -0800 Subject: [PATCH 6/7] Simplify --- cmake/onnxruntime_python.cmake | 70 ++++++---------------------------- 1 file changed, 12 insertions(+), 58 deletions(-) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index 46a69a413b36c..38b04526a9449 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -69,64 +69,18 @@ endif() onnxruntime_add_shared_library_module(onnxruntime_pybind11_state ${onnxruntime_pybind_srcs}) -if (Python_EXECUTABLE) - message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}") - - # Use a cached variable so we don't re-run detection on every configure - if (NOT DEFINED ORT_PYTHON_FREE_THREADED_DETECTED) - message(STATUS "Checking for Free-threaded Python environment...") - - # Check 1: Query Py_GIL_DISABLED directly (PEP 703) - execute_process( - COMMAND "${Python_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" - RESULT_VARIABLE _py_result - OUTPUT_VARIABLE Py_GIL_DISABLED_VALUE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if (NOT _py_result EQUAL 0) - message(WARNING "Failed to query Py_GIL_DISABLED from Python interpreter. Result: ${_py_result}") - set(Py_GIL_DISABLED_VALUE "0") - endif() - - # Handle explicit "None" string or empty output - # (common on Windows and pre-PEP 703 Python builds where the var is unset) - if (Py_GIL_DISABLED_VALUE STREQUAL "" OR Py_GIL_DISABLED_VALUE STREQUAL "None") - set(Py_GIL_DISABLED_VALUE "0") - - # Check 2: Fallback to ABI flags if config var wasn't explicit - execute_process( - COMMAND "${Python_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_config_var('ABIFLAGS') or sysconfig.get_config_var('SOABI') or '')" - RESULT_VARIABLE _abi_result - OUTPUT_VARIABLE Py_ABI_VALUE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if (_abi_result EQUAL 0) - # Matches "cp313t", "cp314t" etc., or "t" followed by hyphen/end-of-string (e.g., "cp313t-win_amd64") - if ("${Py_ABI_VALUE}" MATCHES "cp[0-9]+t" OR "${Py_ABI_VALUE}" MATCHES "t(-|$)") - set(Py_GIL_DISABLED_VALUE "1") - message(STATUS "Detected 't' suffix in Python ABI flags (${Py_ABI_VALUE}). Assuming Free-threaded build.") - endif() - endif() - endif() - - # Normalize to 0/1 to avoid edge cases downstream - if (NOT Py_GIL_DISABLED_VALUE STREQUAL "1") - set(Py_GIL_DISABLED_VALUE "0") - endif() - - # Cache the result as BOOL so users can override it (e.g. -DORT_PYTHON_FREE_THREADED_DETECTED=OFF) - set(ORT_PYTHON_FREE_THREADED_DETECTED "${Py_GIL_DISABLED_VALUE}" CACHE BOOL "Detected free-threaded Python status" FORCE) - else() - message(STATUS "Using cached free-threaded Python detection: ORT_PYTHON_FREE_THREADED_DETECTED=${ORT_PYTHON_FREE_THREADED_DETECTED}") - endif() - - if (ORT_PYTHON_FREE_THREADED_DETECTED) - message(STATUS "Py_GIL_DISABLED=1 detected: Enabling free-threaded support for onnxruntime_pybind11_state") - else() - message(STATUS "Free-threaded Python support NOT enabled.") - endif() +message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}") + +# Query Py_GIL_DISABLED (PEP 703) +execute_process( + COMMAND "${Python_EXECUTABLE}" -c + "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED') or '0')" + RESULT_VARIABLE _py_result + OUTPUT_VARIABLE _py_gil_disabled + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +if (_py_result EQUAL 0 AND _py_gil_disabled STREQUAL "1") + message(STATUS "Py_GIL_DISABLED=1 detected: Enabling free-threaded support for onnxruntime_pybind11_state") endif() if(MSVC) From 4357bd39e1cf41173f427be65bcd7b51be519850 Mon Sep 17 00:00:00 2001 From: Tianlei WU Date: Tue, 16 Dec 2025 11:48:41 -0800 Subject: [PATCH 7/7] format --- cmake/onnxruntime_python.cmake | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index 38b04526a9449..59b3d1428e081 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -73,12 +73,12 @@ message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}") # Query Py_GIL_DISABLED (PEP 703) execute_process( - COMMAND "${Python_EXECUTABLE}" -c - "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED') or '0')" - RESULT_VARIABLE _py_result - OUTPUT_VARIABLE _py_gil_disabled - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + COMMAND "${Python_EXECUTABLE}" -c + "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED') or '0')" + RESULT_VARIABLE _py_result + OUTPUT_VARIABLE _py_gil_disabled + OUTPUT_STRIP_TRAILING_WHITESPACE +) if (_py_result EQUAL 0 AND _py_gil_disabled STREQUAL "1") message(STATUS "Py_GIL_DISABLED=1 detected: Enabling free-threaded support for onnxruntime_pybind11_state") endif()