Skip to content

Commit afe21b9

Browse files
committed
pythongh-92906: Enable test_cext and test_cppext on Windows
On Windows in release mode, the test_cext and test_cppext can now C and C++ extensions.
1 parent 1312094 commit afe21b9

File tree

4 files changed

+119
-37
lines changed

4 files changed

+119
-37
lines changed

Lib/test/test_cext/__init__.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# gh-116869: Build a basic C test extension to check that the Python C API
22
# does not emit C compiler warnings.
33
#
4-
# Python C API must build with -Werror=declaration-after-statement.
4+
# The Python C API must be compatible with building
5+
# with the -Werror=declaration-after-statement compiler flag.
56

67
import os.path
78
import shutil
@@ -14,9 +15,10 @@
1415
SETUP = os.path.join(os.path.dirname(__file__), 'setup.py')
1516

1617

17-
# With MSVC, the linker fails with: cannot open file 'python311.lib'
18-
# https://github.com/python/cpython/pull/32175#issuecomment-1111175897
19-
@unittest.skipIf(support.MS_WINDOWS, 'test fails on Windows')
18+
# With MSVC on a debug build, the linker fails with: cannot open file
19+
# 'python311.lib', it should look 'python311_d.lib'.
20+
@unittest.skipIf(support.MS_WINDOWS and support.Py_DEBUG,
21+
'test fails on Windows debug build')
2022
# Building and running an extension in clang sanitizing mode is not
2123
# straightforward
2224
@support.skip_if_sanitizer('test does not work with analyzing builds',
@@ -26,17 +28,22 @@
2628
@support.requires_subprocess()
2729
@support.requires_resource('cpu')
2830
class TestExt(unittest.TestCase):
29-
def test_build_c99(self):
30-
self.check_build('_test_c99_ext', std='c99')
31+
# Default build with no options
32+
def test_build(self):
33+
self.check_build('_test_cext')
3134

3235
def test_build_c11(self):
33-
self.check_build('_test_c11_ext', std='c11')
36+
self.check_build('_test_c11_cext', std='c11')
37+
38+
@unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c99")
39+
def test_build_c99(self):
40+
self.check_build('_test_c99_cext', std='c99')
3441

3542
def test_build_limited(self):
36-
self.check_build('_test_limited_ext', limited=True)
43+
self.check_build('_test_limited_cext', limited=True)
3744

3845
def test_build_limited_c11(self):
39-
self.check_build('_test_limited_c11_ext', limited=True, std='c11')
46+
self.check_build('_test_limited_c11_cext', limited=True, std='c11')
4047

4148
def check_build(self, extension_name, std=None, limited=False):
4249
venv_dir = 'env'

Lib/test/test_cext/setup.py

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# gh-91321: Build a basic C test extension to check that the Python C API is
22
# compatible with C and does not emit C compiler warnings.
33
import os
4+
import platform
45
import shlex
56
import sys
67
import sysconfig
@@ -17,8 +18,8 @@
1718
# extension using the Python C API does not emit C compiler warnings.
1819
'-Werror',
1920

20-
# gh-116869: The Python C API must build with
21-
# -Werror=declaration-after-statement.
21+
# gh-116869: The Python C API must be compatible with building
22+
# with the -Werror=declaration-after-statement compiler flag.
2223
'-Werror=declaration-after-statement',
2324
]
2425
else:
@@ -34,22 +35,58 @@ def main():
3435
cflags = list(CFLAGS)
3536
cflags.append(f'-DMODULE_NAME={module_name}')
3637

38+
# Add -std=STD or /std:STD (MSVC) compiler flag
3739
if std:
38-
cflags.append(f'-std={std}')
40+
if support.MS_WINDOWS:
41+
cflags.append(f'/std:{std}')
42+
std_prefix = '/std'
43+
else:
44+
cflags.append(f'-std={std}')
45+
std_prefix = '-std'
3946

4047
# Remove existing -std options to only test ours
4148
cmd = (sysconfig.get_config_var('CC') or '')
4249
if cmd is not None:
4350
cmd = shlex.split(cmd)
44-
cmd = [arg for arg in cmd if not arg.startswith('-std=')]
51+
cmd = [arg for arg in cmd if not arg.startswith(std_prefix)]
4552
cmd = shlex.join(cmd)
4653
# CC env var overrides sysconfig CC variable in setuptools
4754
os.environ['CC'] = cmd
4855

56+
# Define Py_LIMITED_API macro
4957
if limited:
5058
version = sys.hexversion
5159
cflags.append(f'-DPy_LIMITED_API={version:#x}')
5260

61+
# On Windows, add PCbuild\amd64\ to include and library directories
62+
include_dirs = []
63+
library_dirs = []
64+
if support.MS_WINDOWS:
65+
srcdir = sysconfig.get_config_var('srcdir')
66+
machine = platform.uname().machine
67+
pcbuild = os.path.join(srcdir, 'PCbuild', machine)
68+
if os.path.exists(pcbuild):
69+
# pyconfig.h is generated in PCbuild\amd64\
70+
include_dirs.append(pcbuild)
71+
# is generated in PCbuild\amd64\
72+
library_dirs.append(pcbuild)
73+
print(f"Add PCbuild directory: {pcbuild}")
74+
75+
# On Windows, add PCbuild\amd64\ to include and library directories
76+
include_dirs = []
77+
library_dirs = []
78+
if support.MS_WINDOWS:
79+
srcdir = sysconfig.get_config_var('srcdir')
80+
machine = platform.uname().machine
81+
pcbuild = os.path.join(srcdir, 'PCbuild', machine)
82+
if os.path.exists(pcbuild):
83+
# pyconfig.h is generated in PCbuild\amd64\
84+
include_dirs.append(pcbuild)
85+
# python313.lib is generated in PCbuild\amd64\
86+
library_dirs.append(pcbuild)
87+
print(f"Add PCbuild directory: {pcbuild}")
88+
89+
# Display information to help debugging
5390
for env_name in ('CC', 'CFLAGS'):
5491
if env_name in os.environ:
5592
print(f"{env_name} env var: {os.environ[env_name]!r}")
@@ -60,7 +97,9 @@ def main():
6097
ext = Extension(
6198
module_name,
6299
sources=[SOURCE],
63-
extra_compile_args=cflags)
100+
extra_compile_args=cflags,
101+
include_dirs=include_dirs,
102+
library_dirs=library_dirs)
64103
setup(name=f'internal_{module_name}',
65104
version='0.0',
66105
ext_modules=[ext])

Lib/test/test_cppext/__init__.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
SETUP = os.path.join(os.path.dirname(__file__), 'setup.py')
1212

1313

14-
# With MSVC, the linker fails with: cannot open file 'python311.lib'
15-
# https://github.com/python/cpython/pull/32175#issuecomment-1111175897
16-
@unittest.skipIf(support.MS_WINDOWS, 'test fails on Windows')
14+
# With MSVC on a debug build, the linker fails with: cannot open file
15+
# 'python311.lib', it should look 'python311_d.lib'.
16+
@unittest.skipIf(support.MS_WINDOWS and support.Py_DEBUG,
17+
'test fails on Windows debug build')
1718
# Building and running an extension in clang sanitizing mode is not
1819
# straightforward
1920
@support.skip_if_sanitizer('test does not work with analyzing builds',
@@ -23,26 +24,30 @@
2324
@support.requires_subprocess()
2425
@support.requires_resource('cpu')
2526
class TestCPPExt(unittest.TestCase):
27+
def test_build(self):
28+
self.check_build('_testcppext')
29+
2630
def test_build_cpp11(self):
27-
self.check_build(False, '_testcpp11ext')
31+
self.check_build('_testcpp11ext', std='c++11')
2832

2933
def test_build_cpp03(self):
30-
self.check_build(True, '_testcpp03ext')
34+
self.check_build('_testcpp03ext', std='c++03')
3135

32-
def check_build(self, std_cpp03, extension_name):
36+
def check_build(self, extension_name, std=None):
3337
venv_dir = 'env'
3438
with support.setup_venv_with_pip_setuptools_wheel(venv_dir) as python_exe:
35-
self._check_build(std_cpp03, extension_name, python_exe)
39+
self._check_build(extension_name, python_exe, std=std)
3640

37-
def _check_build(self, std_cpp03, extension_name, python_exe):
41+
def _check_build(self, extension_name, python_exe, std):
3842
pkg_dir = 'pkg'
3943
os.mkdir(pkg_dir)
4044
shutil.copy(SETUP, os.path.join(pkg_dir, os.path.basename(SETUP)))
4145
shutil.copy(SOURCE, os.path.join(pkg_dir, os.path.basename(SOURCE)))
4246

4347
def run_cmd(operation, cmd):
4448
env = os.environ.copy()
45-
env['CPYTHON_TEST_CPP_STD'] = 'c++03' if std_cpp03 else 'c++11'
49+
if std:
50+
env['CPYTHON_TEST_CPP_STD'] = std
4651
env['CPYTHON_TEST_EXT_NAME'] = extension_name
4752
if support.verbose:
4853
print('Run:', ' '.join(cmd))

Lib/test/test_cppext/setup.py

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# gh-91321: Build a basic C++ test extension to check that the Python C API is
22
# compatible with C++ and does not emit C++ compiler warnings.
33
import os
4+
import platform
45
import shlex
5-
import sys
66
import sysconfig
77
from test import support
88

@@ -25,27 +25,58 @@
2525

2626
def main():
2727
cppflags = list(CPPFLAGS)
28-
std = os.environ["CPYTHON_TEST_CPP_STD"]
28+
std = os.environ.get("CPYTHON_TEST_CPP_STD", "")
2929
name = os.environ["CPYTHON_TEST_EXT_NAME"]
3030

31-
cppflags = [*CPPFLAGS, f'-std={std}']
31+
cppflags = [*CPPFLAGS]
3232

33-
# gh-105776: When "gcc -std=11" is used as the C++ compiler, -std=c11
34-
# option emits a C++ compiler warning. Remove "-std11" option from the
35-
# CC command.
36-
cmd = (sysconfig.get_config_var('CC') or '')
37-
if cmd is not None:
38-
cmd = shlex.split(cmd)
39-
cmd = [arg for arg in cmd if not arg.startswith('-std=')]
40-
cmd = shlex.join(cmd)
41-
# CC env var overrides sysconfig CC variable in setuptools
42-
os.environ['CC'] = cmd
33+
# Add -std=STD or /std:STD (MSVC) compiler flag
34+
if std:
35+
if support.MS_WINDOWS:
36+
cppflags.append(f'/std:{std}')
37+
std_prefix = '/std'
38+
else:
39+
cppflags.append(f'-std={std}')
40+
std_prefix = '-std'
41+
42+
# Remove existing -std options to only test ours
43+
cmd = (sysconfig.get_config_var('CC') or '')
44+
if cmd is not None:
45+
cmd = shlex.split(cmd)
46+
cmd = [arg for arg in cmd if not arg.startswith(std_prefix)]
47+
cmd = shlex.join(cmd)
48+
# CC env var overrides sysconfig CC variable in setuptools
49+
os.environ['CC'] = cmd
50+
51+
# On Windows, add PCbuild\amd64\ to include and library directories
52+
include_dirs = []
53+
library_dirs = []
54+
if support.MS_WINDOWS:
55+
srcdir = sysconfig.get_config_var('srcdir')
56+
machine = platform.uname().machine
57+
pcbuild = os.path.join(srcdir, 'PCbuild', machine)
58+
if os.path.exists(pcbuild):
59+
# pyconfig.h is generated in PCbuild\amd64\
60+
include_dirs.append(pcbuild)
61+
# python313.lib is generated in PCbuild\amd64\
62+
library_dirs.append(pcbuild)
63+
print(f"Add PCbuild directory: {pcbuild}")
64+
65+
# Display information to help debugging
66+
for env_name in ('CC', 'CFLAGS', 'CPPFLAGS'):
67+
if env_name in os.environ:
68+
print(f"{env_name} env var: {os.environ[env_name]!r}")
69+
else:
70+
print(f"{env_name} env var: <missing>")
71+
print(f"extra_compile_args: {cppflags!r}")
4372

4473
cpp_ext = Extension(
4574
name,
4675
sources=[SOURCE],
4776
language='c++',
48-
extra_compile_args=cppflags)
77+
extra_compile_args=cppflags,
78+
include_dirs=include_dirs,
79+
library_dirs=library_dirs)
4980
setup(name='internal' + name, version='0.0', ext_modules=[cpp_ext])
5081

5182

0 commit comments

Comments
 (0)