test_cppext.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. # gh-91321: Build a basic C++ test extension to check that the Python C API is
  2. # compatible with C++ and does not emit C++ compiler warnings.
  3. import os.path
  4. import sys
  5. import unittest
  6. import subprocess
  7. import sysconfig
  8. from test import support
  9. from test.support import os_helper
  10. MS_WINDOWS = (sys.platform == 'win32')
  11. SETUP_TESTCPPEXT = support.findfile('setup_testcppext.py')
  12. @support.requires_subprocess()
  13. class TestCPPExt(unittest.TestCase):
  14. def test_build_cpp11(self):
  15. self.check_build(False, '_testcpp11ext')
  16. def test_build_cpp03(self):
  17. self.check_build(True, '_testcpp03ext')
  18. # With MSVC, the linker fails with: cannot open file 'python311.lib'
  19. # https://github.com/python/cpython/pull/32175#issuecomment-1111175897
  20. @unittest.skipIf(MS_WINDOWS, 'test fails on Windows')
  21. # Building and running an extension in clang sanitizing mode is not
  22. # straightforward
  23. @unittest.skipIf(
  24. '-fsanitize' in (sysconfig.get_config_var('PY_CFLAGS') or ''),
  25. 'test does not work with analyzing builds')
  26. # the test uses venv+pip: skip if it's not available
  27. @support.requires_venv_with_pip()
  28. def check_build(self, std_cpp03, extension_name):
  29. # Build in a temporary directory
  30. with os_helper.temp_cwd():
  31. self._check_build(std_cpp03, extension_name)
  32. def _check_build(self, std_cpp03, extension_name):
  33. venv_dir = 'env'
  34. verbose = support.verbose
  35. # Create virtual environment to get setuptools
  36. cmd = [sys.executable, '-X', 'dev', '-m', 'venv', venv_dir]
  37. if verbose:
  38. print()
  39. print('Run:', ' '.join(cmd))
  40. subprocess.run(cmd, check=True)
  41. # Get the Python executable of the venv
  42. python_exe = 'python'
  43. if sys.executable.endswith('.exe'):
  44. python_exe += '.exe'
  45. if MS_WINDOWS:
  46. python = os.path.join(venv_dir, 'Scripts', python_exe)
  47. else:
  48. python = os.path.join(venv_dir, 'bin', python_exe)
  49. def run_cmd(operation, cmd):
  50. if verbose:
  51. print('Run:', ' '.join(cmd))
  52. subprocess.run(cmd, check=True)
  53. else:
  54. proc = subprocess.run(cmd,
  55. stdout=subprocess.PIPE,
  56. stderr=subprocess.STDOUT,
  57. text=True)
  58. if proc.returncode:
  59. print(proc.stdout, end='')
  60. self.fail(
  61. f"{operation} failed with exit code {proc.returncode}")
  62. # Build the C++ extension
  63. cmd = [python, '-X', 'dev',
  64. SETUP_TESTCPPEXT, 'build_ext', '--verbose']
  65. if std_cpp03:
  66. cmd.append('-std=c++03')
  67. run_cmd('Build', cmd)
  68. # Install the C++ extension
  69. cmd = [python, '-X', 'dev',
  70. SETUP_TESTCPPEXT, 'install']
  71. run_cmd('Install', cmd)
  72. # Do a reference run. Until we test that running python
  73. # doesn't leak references (gh-94755), run it so one can manually check
  74. # -X showrefcount results against this baseline.
  75. cmd = [python,
  76. '-X', 'dev',
  77. '-X', 'showrefcount',
  78. '-c', 'pass']
  79. run_cmd('Reference run', cmd)
  80. # Import the C++ extension
  81. cmd = [python,
  82. '-X', 'dev',
  83. '-X', 'showrefcount',
  84. '-c', f"import {extension_name}"]
  85. run_cmd('Import', cmd)
  86. if __name__ == "__main__":
  87. unittest.main()