Skip to content

Commit db20466

Browse files
committed
windows: support static Python 3.9 builds
Python 3.9 changed some code that we patch in order to produce static builds. The change to the _asyncio extension is actually a welcome change. But since we need to maintain compatibility building CPython 3.7 and 3.8, we had to add a hack to our hack.
1 parent d12f4f9 commit db20466

File tree

1 file changed

+107
-17
lines changed

1 file changed

+107
-17
lines changed

cpython-windows/build.py

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
CONVERT_TO_BUILTIN_EXTENSIONS = {
4242
"_asyncio": {
4343
# _asynciomodule.c is included in pythoncore for some reason.
44+
# This was fixed in Python 3.9. See hacky code for
45+
# `honor_allow_missing_preprocessor`.
4446
"allow_missing_preprocessor": True
4547
},
4648
"_bz2": {},
@@ -407,7 +409,12 @@ def make_project_static_library(source_path: pathlib.Path, project: str):
407409
fh.write("\n".join(lines))
408410

409411

410-
def convert_to_static_library(source_path: pathlib.Path, extension: str, entry: dict):
412+
def convert_to_static_library(
413+
source_path: pathlib.Path,
414+
extension: str,
415+
entry: dict,
416+
honor_allow_missing_preprocessor: bool,
417+
):
411418
"""Converts an extension to a static library."""
412419

413420
proj_path = source_path / "PCbuild" / ("%s.vcxproj" % extension)
@@ -460,7 +467,7 @@ def convert_to_static_library(source_path: pathlib.Path, extension: str, entry:
460467
lines.append(line)
461468

462469
if not found_preprocessor:
463-
if entry.get("allow_missing_preprocessor"):
470+
if honor_allow_missing_preprocessor and entry.get("allow_missing_preprocessor"):
464471
log("not adjusting preprocessor definitions for %s" % extension)
465472
else:
466473
log("introducing <PreprocessorDefinitions> to %s" % extension)
@@ -817,6 +824,7 @@ def hack_project_files(
817824
build_directory: str,
818825
static: bool,
819826
building_libffi: bool,
827+
honor_allow_missing_preprocessor: bool,
820828
):
821829
"""Hacks Visual Studio project files to work with our build."""
822830

@@ -900,13 +908,23 @@ def hack_project_files(
900908
# do here.
901909
if static and building_libffi:
902910
libffi_path = td / "libffi" / "libffi.lib"
903-
static_replace_in_file(
904-
pythoncore_proj,
905-
b"<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>",
906-
b"<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;"
907-
+ bytes(libffi_path)
908-
+ b";%(AdditionalDependencies)</AdditionalDependencies>",
909-
)
911+
try:
912+
# Python 3.9 version
913+
static_replace_in_file(
914+
pythoncore_proj,
915+
b"<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>",
916+
b"<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;pathcch.lib;"
917+
+ bytes(libffi_path)
918+
+ b";%(AdditionalDependencies)</AdditionalDependencies>",
919+
)
920+
except NoSearchStringError:
921+
static_replace_in_file(
922+
pythoncore_proj,
923+
b"<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>",
924+
b"<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;"
925+
+ bytes(libffi_path)
926+
+ b";%(AdditionalDependencies)</AdditionalDependencies>",
927+
)
910928

911929
if static:
912930
for extension, entry in sorted(CONVERT_TO_BUILTIN_EXTENSIONS.items()):
@@ -916,7 +934,9 @@ def hack_project_files(
916934

917935
init_fn = entry.get("init", "PyInit_%s" % extension)
918936

919-
if convert_to_static_library(cpython_source_path, extension, entry):
937+
if convert_to_static_library(
938+
cpython_source_path, extension, entry, honor_allow_missing_preprocessor
939+
):
920940
add_to_config_c(cpython_source_path, extension, init_fn)
921941

922942
# pythoncore.vcxproj produces libpython. Typically pythonXY.dll. We change
@@ -1013,7 +1033,63 @@ def hack_project_files(
10131033
)
10141034

10151035

1016-
PYPORT_EXPORT_SEARCH_NEW = b"""
1036+
PYPORT_EXPORT_SEARCH_39 = b"""
1037+
#if defined(__CYGWIN__)
1038+
# define HAVE_DECLSPEC_DLL
1039+
#endif
1040+
1041+
#include "exports.h"
1042+
1043+
/* only get special linkage if built as shared or platform is Cygwin */
1044+
#if defined(Py_ENABLE_SHARED) || defined(__CYGWIN__)
1045+
# if defined(HAVE_DECLSPEC_DLL)
1046+
# if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
1047+
# define PyAPI_FUNC(RTYPE) Py_EXPORTED_SYMBOL RTYPE
1048+
# define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE
1049+
/* module init functions inside the core need no external linkage */
1050+
/* except for Cygwin to handle embedding */
1051+
# if defined(__CYGWIN__)
1052+
# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
1053+
# else /* __CYGWIN__ */
1054+
# define PyMODINIT_FUNC PyObject*
1055+
# endif /* __CYGWIN__ */
1056+
# else /* Py_BUILD_CORE */
1057+
/* Building an extension module, or an embedded situation */
1058+
/* public Python functions and data are imported */
1059+
/* Under Cygwin, auto-import functions to prevent compilation */
1060+
/* failures similar to those described at the bottom of 4.1: */
1061+
/* http://docs.python.org/extending/windows.html#a-cookbook-approach */
1062+
# if !defined(__CYGWIN__)
1063+
# define PyAPI_FUNC(RTYPE) Py_IMPORTED_SYMBOL RTYPE
1064+
# endif /* !__CYGWIN__ */
1065+
# define PyAPI_DATA(RTYPE) extern Py_IMPORTED_SYMBOL RTYPE
1066+
/* module init functions outside the core must be exported */
1067+
# if defined(__cplusplus)
1068+
# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
1069+
# else /* __cplusplus */
1070+
# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
1071+
# endif /* __cplusplus */
1072+
# endif /* Py_BUILD_CORE */
1073+
# endif /* HAVE_DECLSPEC_DLL */
1074+
#endif /* Py_ENABLE_SHARED */
1075+
1076+
/* If no external linkage macros defined by now, create defaults */
1077+
#ifndef PyAPI_FUNC
1078+
# define PyAPI_FUNC(RTYPE) Py_EXPORTED_SYMBOL RTYPE
1079+
#endif
1080+
#ifndef PyAPI_DATA
1081+
# define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE
1082+
#endif
1083+
#ifndef PyMODINIT_FUNC
1084+
# if defined(__cplusplus)
1085+
# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
1086+
# else /* __cplusplus */
1087+
# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
1088+
# endif /* __cplusplus */
1089+
#endif
1090+
"""
1091+
1092+
PYPORT_EXPORT_SEARCH_38 = b"""
10171093
#if defined(__CYGWIN__)
10181094
# define HAVE_DECLSPEC_DLL
10191095
#endif
@@ -1067,7 +1143,7 @@ def hack_project_files(
10671143
#endif
10681144
"""
10691145

1070-
PYPORT_EXPORT_SEARCH_OLD = b"""
1146+
PYPORT_EXPORT_SEARCH_37 = b"""
10711147
#if defined(__CYGWIN__)
10721148
# define HAVE_DECLSPEC_DLL
10731149
#endif
@@ -1121,7 +1197,14 @@ def hack_project_files(
11211197
#endif
11221198
"""
11231199

1124-
PYPORT_EXPORT_REPLACE = b"""
1200+
PYPORT_EXPORT_REPLACE_NEW = b"""
1201+
#include "exports.h"
1202+
#define PyAPI_FUNC(RTYPE) __declspec(dllexport) RTYPE
1203+
#define PyAPI_DATA(RTYPE) extern __declspec(dllexport) RTYPE
1204+
#define PyMODINIT_FUNC __declspec(dllexport) PyObject*
1205+
"""
1206+
1207+
PYPORT_EXPORT_REPLACE_OLD = b"""
11251208
#define PyAPI_FUNC(RTYPE) __declspec(dllexport) RTYPE
11261209
#define PyAPI_DATA(RTYPE) extern __declspec(dllexport) RTYPE
11271210
#define PyMODINIT_FUNC __declspec(dllexport) PyObject*
@@ -1157,12 +1240,17 @@ def hack_source_files(source_path: pathlib.Path, static: bool):
11571240
pyport_h = source_path / "Include" / "pyport.h"
11581241
try:
11591242
static_replace_in_file(
1160-
pyport_h, PYPORT_EXPORT_SEARCH_NEW, PYPORT_EXPORT_REPLACE
1243+
pyport_h, PYPORT_EXPORT_SEARCH_39, PYPORT_EXPORT_REPLACE_NEW
11611244
)
11621245
except NoSearchStringError:
1163-
static_replace_in_file(
1164-
pyport_h, PYPORT_EXPORT_SEARCH_OLD, PYPORT_EXPORT_REPLACE
1165-
)
1246+
try:
1247+
static_replace_in_file(
1248+
pyport_h, PYPORT_EXPORT_SEARCH_38, PYPORT_EXPORT_REPLACE_OLD
1249+
)
1250+
except NoSearchStringError:
1251+
static_replace_in_file(
1252+
pyport_h, PYPORT_EXPORT_SEARCH_37, PYPORT_EXPORT_REPLACE_OLD
1253+
)
11661254

11671255
# Modules/_winapi.c and Modules/overlapped.c both define an
11681256
# ``OverlappedType`` symbol. We rename one to make the symbol conflict
@@ -1928,6 +2016,8 @@ def build_cpython(
19282016
build_directory,
19292017
static=static,
19302018
building_libffi=libffi_archive is not None,
2019+
honor_allow_missing_preprocessor=python_entry_name
2020+
in ("cpython-3.7", "cpython-3.8"),
19312021
)
19322022
hack_source_files(cpython_source_path, static=static)
19332023

0 commit comments

Comments
 (0)