Skip to content

Add support for building Python 3.12x #398

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 2, 2025
Merged
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
18 changes: 18 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ jobs:
workflows:
build-and-test:
jobs:
# 3.12.10
- build-test-python:
name: python-3.12.10-x64
python_version: 3.12.10
python_arch: x64

- build-test-python:
name: python-3.12.10-x86
python_version: 3.12.10
python_arch: x86

# 3.11.12
- build-test-python:
name: python-3.11.12-x64
Expand Down Expand Up @@ -155,6 +166,13 @@ workflows:

build-and-test-win:
jobs:
# 3.12.10
- build-test-python-win:
name: python-3.12.10-win-x64
python_version: 3.12.10
python_arch: x64
generator: "Visual Studio 16 2019"

# 3.11.12
- build-test-python-win:
name: python-3.11.12-win-x64
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
fail-fast: false
matrix:
runs-on: [macos-latest]
python-version: [3.7.17, 3.8.20, 3.9.22, 3.10.17, 3.11.12]
python-version: [3.7.17, 3.8.20, 3.9.22, 3.10.17, 3.11.12, 3.12.10]
include:
- runs-on: macos-latest
c-compiler: "clang"
Expand Down
22 changes: 21 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20.6)

set(PYTHON_VERSION "3.11.12" CACHE STRING "The version of Python to build.")
set(PYTHON_VERSION "3.12.10" CACHE STRING "The version of Python to build.")

string(REPLACE "." ";" VERSION_LIST ${PYTHON_VERSION})
list(GET VERSION_LIST 0 PY_VERSION_MAJOR)
Expand Down Expand Up @@ -311,6 +311,18 @@ set(_download_3.11.9_md5 "bfd4d3bfeac4216ce35d7a503bf02d5c")
set(_download_3.11.10_md5 "35c36069a43dd57a7e9915deba0f864e")
set(_download_3.11.11_md5 "9a5b43fcc06810b8ae924b0a080e6569")
set(_download_3.11.12_md5 "b8bb496014f05f5be180fab74810f40b")
# 3.12.x
set(_download_3.12.0_md5 "d6eda3e1399cef5dfde7c4f319b0596c")
set(_download_3.12.1_md5 "51c5c22dcbc698483734dff5c8028606")
set(_download_3.12.2_md5 "4e64a004f8ad9af1a75607cfd0d5a8c8")
set(_download_3.12.3_md5 "3c5498a34d5226c9b746b1199f0bf2d9")
set(_download_3.12.4_md5 "ead819dab6d165937138daa9e51ccb54")
set(_download_3.12.5_md5 "d23d56b51d36a9d51b2b13d30c849d00")
set(_download_3.12.6_md5 "c2f1dd5c8807ee50b778684b7958ee28")
set(_download_3.12.7_md5 "5d0c0e4c6a022a87165a9addcd869109")
set(_download_3.12.8_md5 "304473cf367fa65e450edf4b06b55fcc")
set(_download_3.12.9_md5 "ce613c72fa9b32fb4f109762d61b249b")
set(_download_3.12.10_md5 "35c03f014408e26e2b06d576c19cac54")

set(_extracted_dir "Python-${PY_VERSION}")

Expand Down Expand Up @@ -623,6 +635,14 @@ if(BUILD_WININST)
add_subdirectory(cmake/PC/bdist_wininst CMakeBuild/bdist_wininst)
endif()

# Ensure the "_testcapi" extension introduced in Python 3.12 can find
# find "Python3.lib" as it is specified in "PC/pyconfig." using
# `pragma comment(lib,"python3.lib")`.
if(WIN32 AND TARGET extension_testcapi)
set(libpython_output_dir "${PROJECT_BINARY_DIR}/CMakeBuild/libpython/$<CONFIG>")
target_link_directories(extension_testcapi PRIVATE ${libpython_output_dir})
endif()

# Add target to run "Argument Clinic" over all source files
add_custom_target(clinic
COMMAND python ${SRC_DIR}/Tools/clinic/clinic.py --make
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ options on the commandline with `-DOPTION=VALUE`, or use the "ccmake" gui.

::

PYTHON_VERSION=major.minor.patch (defaults to 3.11.12)
PYTHON_VERSION=major.minor.patch (defaults to 3.12.10)
The version of Python to build.

PYTHON_APPLY_PATCHES=ON|OFF (defaults to ON)
Expand Down
32 changes: 32 additions & 0 deletions cmake/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ if(USE_SYSTEM_Curses)
message(STATUS "${_msg} - not found")
endif()

# Python 3.12
if(Curses_FOUND)
set(HAVE_NCURSESW 1)
else()
set(HAVE_NCURSESW 0)
endif()

if(NOT Curses_FOUND)
message(STATUS "")
set(_msg "Looking for curses without Unicode support")
Expand Down Expand Up @@ -80,6 +87,7 @@ if(USE_SYSTEM_LibFFI)
message(STATUS "LibFFI_INCLUDE_DIR=${LibFFI_INCLUDE_DIR}")
message(STATUS "LibFFI_LIBRARY=${LibFFI_LIBRARY}")
endif()
set(HAVE_LIBFFI ${LibFFI_LIBRARY}) # Python 3.12

if(USE_SYSTEM_LIBMPDEC)
find_library(LIBMPDEC_LIBRARY NAMES mpdec libmpdec)
Expand Down Expand Up @@ -195,9 +203,11 @@ set(HAVE_LZMA_H ${LZMA_INCLUDE_PATH}) # Python 3.11
if(USE_SYSTEM_READLINE)
if(USE_LIBEDIT)
find_path(READLINE_INCLUDE_PATH editline/readline.h)
set(HAVE_EDITLINE_READLINE_H ${READLINE_INCLUDE_PATH}) # Python 3.12
find_library(READLINE_LIBRARY edit)
else()
find_path(READLINE_INCLUDE_PATH readline/readline.h)
set(HAVE_READLINE_READLINE_H ${READLINE_INCLUDE_PATH}) # Python 3.12
find_library(READLINE_LIBRARY readline)
endif()
endif()
Expand Down Expand Up @@ -387,6 +397,7 @@ check_include_files(minix/config.h HAVE_MINIX_CONFIG_H)
check_include_files(ncurses.h HAVE_NCURSES_H)
check_include_files(ncurses/panel.h HAVE_NCURSES_PANEL_H)
check_include_files(netdb.h HAVE_NETDB_H)
check_include_files(net/ethernet.h HAVE_NET_ETHERNET_H) # Python 3.12
check_include_files(netinet/in.h HAVE_NETINET_IN_H)
check_include_files(netpacket/packet.h HAVE_NETPACKET_PACKET_H)
check_include_files(panel.h HAVE_PANEL_H)
Expand All @@ -406,6 +417,7 @@ check_include_files(shadow.h HAVE_SHADOW_H)
check_include_files(signal.h HAVE_SIGNAL_H)
check_include_files(spawn.h HAVE_SPAWN_H)
check_include_files(stdint.h HAVE_STDINT_H) # libffi and cpython
check_include_files(stdio.h HAVE_STDIO_H) # Python 3.12
check_include_files(stdlib.h HAVE_STDLIB_H) # libffi and cpython
check_include_files(strings.h HAVE_STRINGS_H) # libffi and cpython
check_include_files(string.h HAVE_STRING_H) # libffi and cpython
Expand All @@ -428,6 +440,7 @@ set(MAJOR_IN_MKDEV ${HAVE_SYS_MKDEV_H})
check_include_files(sys/mman.h HAVE_SYS_MMAN_H) # libffi and cpython
check_include_files(sys/modem.h HAVE_SYS_MODEM_H)
check_include_files(sys/param.h HAVE_SYS_PARAM_H)
check_include_files(sys/pidfd.h HAVE_SYS_PIDFD_H) # Python 3.12
check_include_files(sys/poll.h HAVE_SYS_POLL_H)
check_include_files(sys/random.h HAVE_SYS_RANDOM_H)
check_include_files(sys/resource.h HAVE_SYS_RESOURCE_H)
Expand Down Expand Up @@ -455,6 +468,7 @@ check_include_files(stdarg.h HAVE_STDARG_PROTOTYPES)

check_include_files(endian.h HAVE_ENDIAN_H)
check_include_files(sched.h HAVE_SCHED_H)
check_include_files(linux/fs.h HAVE_LINUX_FS_H) # Python 3.12
check_include_files(linux/limits.h HAVE_LINUX_LIMITS_H) # Python 3.11
check_include_files(linux/memfd.h HAVE_LINUX_MEMFD_H)
check_include_files(linux/random.h HAVE_LINUX_RANDOM_H)
Expand Down Expand Up @@ -877,6 +891,7 @@ endfunction()

_check_type_alignof(long) # Python 3.10
_check_type_alignof(size_t) # Python 3.10
_check_type_alignof(max_align_t) # Python 3.12

set(HAVE_C99_BOOL ${SIZEOF__BOOL})

Expand Down Expand Up @@ -920,6 +935,7 @@ add_cond(CFG_HEADERS HAVE_SYS_SYSMACROS_H sys/sysmacros.h)
add_cond(CFG_HEADERS HAVE_SYS_TYPES_H sys/types.h)
add_cond(CFG_HEADERS HAVE_SYS_TIME_H sys/time.h)
add_cond(CFG_HEADERS HAVE_SYS_FILE_H sys/file.h)
add_cond(CFG_HEADERS HAVE_SYS_PIDFD_H sys/pidfd.h)
add_cond(CFG_HEADERS HAVE_SYS_POLL_H sys/poll.h)
add_cond(CFG_HEADERS HAVE_SYS_STATVFS_H sys/statvfs.h)
add_cond(CFG_HEADERS HAVE_SYS_STAT_H sys/stat.h)
Expand All @@ -941,6 +957,7 @@ add_cond(CFG_HEADERS HAVE_FCNTL_H fcntl.h)
add_cond(CFG_HEADERS HAVE_PTY_H pty.h)
add_cond(CFG_HEADERS HAVE_SIGNAL_H signal.h)
add_cond(CFG_HEADERS HAVE_STDINT_H stdint.h)
add_cond(CFG_HEADERS HAVE_STDIO_H stdio.h)
add_cond(CFG_HEADERS HAVE_STDLIB_H stdlib.h)
add_cond(CFG_HEADERS HAVE_STRING_H string.h)
add_cond(CFG_HEADERS HAVE_UTIL_H util.h)
Expand Down Expand Up @@ -1113,6 +1130,7 @@ check_symbol_exists(tmpnam "${CFG_HEADERS}" HAVE_TMPNAM)
check_symbol_exists(tmpnam_r "${CFG_HEADERS}" HAVE_TMPNAM_R)
check_symbol_exists(truncate "${CFG_HEADERS}" HAVE_TRUNCATE)
check_symbol_exists(ttyname "${CFG_HEADERS}" HAVE_TTYNAME) # Python 3.11
check_symbol_exists(ttyname_r "${CFG_HEADERS}" HAVE_TTYNAME_R) # Python 3.12
check_symbol_exists(umask "${CFG_HEADERS}" HAVE_UMASK) # Python 3.11
check_symbol_exists(uname "${CFG_HEADERS}" HAVE_UNAME)
check_symbol_exists(unsetenv "${CFG_HEADERS}" HAVE_UNSETENV)
Expand Down Expand Up @@ -1215,6 +1233,10 @@ check_symbol_exists(wcsxfrm "${CFG_HEADERS}" HAVE_WCSXFRM)
check_symbol_exists(wmemcmp "${CFG_HEADERS}" HAVE_WMEMCMP)
check_symbol_exists(writev "${CFG_HEADERS}" HAVE_WRITEV)

# check for namespace functions
check_symbol_exists(setns "${CFG_HEADERS}" HAVE_SETNS) # Python 3.12
check_symbol_exists(unshare "${CFG_HEADERS}" HAVE_UNSHARE) # Python 3.12

check_struct_has_member("struct stat" st_mtim.tv_nsec "${CFG_HEADERS}" HAVE_STAT_TV_NSEC)
check_struct_has_member("struct stat" st_mtimespec.tv_nsec "${CFG_HEADERS}" HAVE_STAT_TV_NSEC2)
check_struct_has_member("struct stat" st_birthtime "${CFG_HEADERS}" HAVE_STRUCT_STAT_ST_BIRTHTIME)
Expand Down Expand Up @@ -1356,6 +1378,15 @@ python_platform_test(
DIRECT
)

# Python 3.12
cmake_push_check_state()
add_cond(CMAKE_REQUIRED_LIBRARIES HAVE_LIBFFI ${LibFFI_LIBRARY})
check_symbol_exists(ffi_call "ffi.h" HAVE_FFI_CALL)
check_symbol_exists(ffi_closure_alloc "ffi.h" HAVE_FFI_CLOSURE_ALLOC)
check_symbol_exists(ffi_prep_cif_var "ffi.h" HAVE_FFI_PREP_CIF_VAR)
check_symbol_exists(ffi_prep_closure_loc "ffi.h" HAVE_FFI_PREP_CLOSURE_LOC)
cmake_pop_check_state()

# libffi specific: Cannot use PROT_EXEC on this target, so, we revert to alternative means
# XXX In autoconf system, it was set to true if target matches *arm*-apple-darwin*
if(NOT DEFINED FFI_EXEC_TRAMPOLINE_TABLE)
Expand Down Expand Up @@ -1998,6 +2029,7 @@ endif()
cmake_push_check_state()
set(CFG_HEADERS_SAVE ${CFG_HEADERS})
add_cond(CFG_HEADERS HAVE_NETDB_H netdb.h)
add_cond(CFG_HEADERS HAVE_NET_ETHERNET_H net/ethernet.h)
add_cond(CFG_HEADERS HAVE_NETINET_IN_H netinet/in.h)
add_cond(CFG_HEADERS HAVE_ARPA_INET_H arpa/inet.h)

Expand Down
54 changes: 51 additions & 3 deletions cmake/config-unix/pyconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
/* The normal alignment of `long', in bytes. [Python 3.10] */
#cmakedefine ALIGNOF_LONG @SIZEOF_LONG@

/* The normal alignment of `max_align_t', in bytes. [Python 3.12] */
#cmakedefine ALIGNOF_MAX_ALIGN_T @ALIGNOF_MAX_ALIGN_T@

/* The normal alignment of `size_t', in bytes. [Python 3.10] */
#cmakedefine ALIGNOF_SIZE_T @SIZEOF_SIZE_T@

Expand Down Expand Up @@ -129,7 +132,7 @@
/* Define if `unsetenv` does not return an int. */
#cmakedefine HAVE_BROKEN_UNSETENV 1

/* Has builtin atomics [Python 3] */
/* Has builtin __atomic_load_n() and __atomic_store_n() functions [Python 3] */
#cmakedefine HAVE_BUILTIN_ATOMIC 1

/* Define this if you have the type _Bool. [Python <= 3.5] */
Expand Down Expand Up @@ -328,6 +331,9 @@
/* Defined when any dynamic module loading is enabled. */
#cmakedefine HAVE_DYNAMIC_LOADING 1

/* Define to 1 if you have the <editline/readline.h> header file. [Python 3.12] */
#cmakedefine HAVE_EDITLINE_READLINE_H 1

/* Define to 1 if you have the <endian.h> header file. [Python 3] */
#cmakedefine HAVE_ENDIAN_H 1

Expand Down Expand Up @@ -394,6 +400,15 @@
/* Define to 1 if you have the `fexecve' function. [Python 3] */
#cmakedefine HAVE_FEXECVE 1

/* Define if you have the 'ffi_closure_alloc' function. [Python 3.12] */
#cmakedefine HAVE_FFI_CLOSURE_ALLOC 1

/* Define if you have the 'ffi_prep_cif_var' function. [Python 3.12] */
#cmakedefine HAVE_FFI_PREP_CIF_VAR 1

/* Define if you have the 'ffi_prep_closure_loc' function. [Python 3.12] */
#cmakedefine HAVE_FFI_PREP_CLOSURE_LOC 1

/* Define to 1 if you have the `finite' function. [Python <= 3.10] */
#cmakedefine HAVE_FINITE 1

Expand Down Expand Up @@ -768,6 +783,9 @@
/* Define if compiling using Linux 4.1 or later. [Python 3.9] */
#cmakedefine HAVE_LINUX_CAN_RAW_JOIN_FILTERS 1

/* Define to 1 if you have the <linux/fs.h> header file. [Python 3.12] */
#cmakedefine HAVE_LINUX_FS_H 1

/* Define to 1 if you have the <linux/limits.h> header file. [Python 3.11] */
#cmakedefine HAVE_LINUX_LIMITS_H 1

Expand Down Expand Up @@ -846,6 +864,9 @@
/* Define to 1 if you have the `memrchr' function. [Python 3] */
#cmakedefine HAVE_MEMRCHR 1

/* Define to 1 if you have the <minix/config.h> header file. [Python 3.12] */
#cmakedefine HAVE_MINIX_CONFIG_H 1

/* Define to 1 if you have the `mkdirat' function. [Python 3] */
#cmakedefine HAVE_MKDIRAT 1

Expand Down Expand Up @@ -873,6 +894,9 @@
/* Define to 1 if you have the `nanosleep' function. [Python 3.11] */
#cmakedefine HAVE_NANOSLEEP 1

/* Define to 1 if you have the `ncursesw' library. [Python 3.12] */
#cmakedefine HAVE_NCURSESW 1

/* Define to 1 if you have the <ncurses.h> header file. */
#cmakedefine HAVE_NCURSES_H 1

Expand All @@ -894,6 +918,9 @@
/* Define to 1 if you have the <netpacket/packet.h> header file. */
#cmakedefine HAVE_NETPACKET_PACKET_H 1

/* Define to 1 if you have the <net/ethernet.h> header file. [Python 3.12] */
#cmakedefine HAVE_NET_ETHERNET_H 1

/* Define to 1 if you have the <net/if.h> header file. [Python 3] */
#cmakedefine HAVE_NET_IF_H 1

Expand All @@ -916,6 +943,9 @@
/* Define if compiling using MacOS X 10.5 SDK or later. [Python <= 3.5] */
#cmakedefine HAVE_OSX105_SDK 1

/* Define to 1 if you have the <panel.h> header file. [Python 3.12] */
#cmakedefine HAVE_PANEL_H 1

/* Define to 1 if you have the `pathconf' function. */
#cmakedefine HAVE_PATHCONF 1

Expand Down Expand Up @@ -1015,6 +1045,9 @@
/* Define if the libcrypto has RAND_egd [Python 3, Python <= 3.4] */
#cmakedefine HAVE_RAND_EGD 1

/* Define to 1 if you have the <readline/readline.h> header file. [Python 3.12] */
#cmakedefine HAVE_READLINE_READLINE_H 1

/* Define to 1 if you have the `readlink' function. */
#cmakedefine HAVE_READLINK 1

Expand Down Expand Up @@ -1138,6 +1171,9 @@
/* Define to 1 if you have the `setlocale' function. */
#cmakedefine HAVE_SETLOCALE 1

/* Define to 1 if you have the `setns' function. [Python 3.12] */
#cmakedefine HAVE_SETNS 1

/* Define to 1 if you have the `setpgid' function. */
#cmakedefine HAVE_SETPGID 1

Expand Down Expand Up @@ -1259,6 +1295,9 @@
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H 1

/* Define to 1 if you have the <stdio.h> header file. [Python 3.12] */
#cmakedefine HAVE_STDIO_H 1

/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine HAVE_STDLIB_H 1

Expand Down Expand Up @@ -1400,6 +1439,9 @@
/* Define to 1 if you have the <sys/param.h> header file. */
#cmakedefine HAVE_SYS_PARAM_H 1

/* Define to 1 if you have the <sys/pidfd.h> header file. [Python 3.12] */
#cmakedefine HAVE_SYS_PIDFD_H 1

/* Define to 1 if you have the <sys/poll.h> header file. */
#cmakedefine HAVE_SYS_POLL_H 1

Expand Down Expand Up @@ -1506,6 +1548,9 @@
/* Define to 1 if you have the `ttyname' function. [Python 3.11] */
#cmakedefine HAVE_TTYNAME 1

/* Define to 1 if you have the `ttyname_r' function. [Python 3.12] */
#cmakedefine HAVE_TTYNAME_R 1

/* Define to 1 if you don't have `tm_zone' but do have the external array
`tzname'. */
#cmakedefine HAVE_TZNAME 1
Expand Down Expand Up @@ -1537,6 +1582,9 @@
/* Define to 1 if you have the `unsetenv' function. [Python <= 3.8] */
#cmakedefine HAVE_UNSETENV 1

/* Define to 1 if you have the `unshare' function. [Python 3.12] */
#cmakedefine HAVE_UNSHARE 1

/* Define if you have a useable wchar_t type defined in wchar.h; useable means
wchar_t must be an unsigned type with at least 16 bits. (see
Include/unicodeobject.h). */
Expand Down Expand Up @@ -1805,7 +1853,7 @@
#ifndef _GNU_SOURCE
#cmakedefine _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
/* Enable POSIX-compatible threading on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
#cmakedefine _POSIX_PTHREAD_SEMANTICS 1
#endif
Expand Down Expand Up @@ -2005,7 +2053,7 @@
/* Define to `long int' if <sys/types.h> does not define. */
#cmakedefine off_t @off_t@

/* Define to `int' if <sys/types.h> does not define. */
/* Define as a signed integer type capable of holding a process identifier. */
#cmakedefine pid_t @pid_t@

/* Define to empty if the keyword does not work. */
Expand Down
Loading