17db96d56Sopenharmony_ci# gh-91321: Build a basic C++ test extension to check that the Python C API is 27db96d56Sopenharmony_ci# compatible with C++ and does not emit C++ compiler warnings. 37db96d56Sopenharmony_ciimport os.path 47db96d56Sopenharmony_ciimport sys 57db96d56Sopenharmony_ciimport unittest 67db96d56Sopenharmony_ciimport subprocess 77db96d56Sopenharmony_ciimport sysconfig 87db96d56Sopenharmony_cifrom test import support 97db96d56Sopenharmony_cifrom test.support import os_helper 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ciMS_WINDOWS = (sys.platform == 'win32') 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ciSETUP_TESTCPPEXT = support.findfile('setup_testcppext.py') 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ci@support.requires_subprocess() 197db96d56Sopenharmony_ciclass TestCPPExt(unittest.TestCase): 207db96d56Sopenharmony_ci def test_build_cpp11(self): 217db96d56Sopenharmony_ci self.check_build(False, '_testcpp11ext') 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ci def test_build_cpp03(self): 247db96d56Sopenharmony_ci self.check_build(True, '_testcpp03ext') 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ci # With MSVC, the linker fails with: cannot open file 'python311.lib' 277db96d56Sopenharmony_ci # https://github.com/python/cpython/pull/32175#issuecomment-1111175897 287db96d56Sopenharmony_ci @unittest.skipIf(MS_WINDOWS, 'test fails on Windows') 297db96d56Sopenharmony_ci # Building and running an extension in clang sanitizing mode is not 307db96d56Sopenharmony_ci # straightforward 317db96d56Sopenharmony_ci @unittest.skipIf( 327db96d56Sopenharmony_ci '-fsanitize' in (sysconfig.get_config_var('PY_CFLAGS') or ''), 337db96d56Sopenharmony_ci 'test does not work with analyzing builds') 347db96d56Sopenharmony_ci # the test uses venv+pip: skip if it's not available 357db96d56Sopenharmony_ci @support.requires_venv_with_pip() 367db96d56Sopenharmony_ci def check_build(self, std_cpp03, extension_name): 377db96d56Sopenharmony_ci # Build in a temporary directory 387db96d56Sopenharmony_ci with os_helper.temp_cwd(): 397db96d56Sopenharmony_ci self._check_build(std_cpp03, extension_name) 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci def _check_build(self, std_cpp03, extension_name): 427db96d56Sopenharmony_ci venv_dir = 'env' 437db96d56Sopenharmony_ci verbose = support.verbose 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ci # Create virtual environment to get setuptools 467db96d56Sopenharmony_ci cmd = [sys.executable, '-X', 'dev', '-m', 'venv', venv_dir] 477db96d56Sopenharmony_ci if verbose: 487db96d56Sopenharmony_ci print() 497db96d56Sopenharmony_ci print('Run:', ' '.join(cmd)) 507db96d56Sopenharmony_ci subprocess.run(cmd, check=True) 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci # Get the Python executable of the venv 537db96d56Sopenharmony_ci python_exe = 'python' 547db96d56Sopenharmony_ci if sys.executable.endswith('.exe'): 557db96d56Sopenharmony_ci python_exe += '.exe' 567db96d56Sopenharmony_ci if MS_WINDOWS: 577db96d56Sopenharmony_ci python = os.path.join(venv_dir, 'Scripts', python_exe) 587db96d56Sopenharmony_ci else: 597db96d56Sopenharmony_ci python = os.path.join(venv_dir, 'bin', python_exe) 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci def run_cmd(operation, cmd): 627db96d56Sopenharmony_ci if verbose: 637db96d56Sopenharmony_ci print('Run:', ' '.join(cmd)) 647db96d56Sopenharmony_ci subprocess.run(cmd, check=True) 657db96d56Sopenharmony_ci else: 667db96d56Sopenharmony_ci proc = subprocess.run(cmd, 677db96d56Sopenharmony_ci stdout=subprocess.PIPE, 687db96d56Sopenharmony_ci stderr=subprocess.STDOUT, 697db96d56Sopenharmony_ci text=True) 707db96d56Sopenharmony_ci if proc.returncode: 717db96d56Sopenharmony_ci print(proc.stdout, end='') 727db96d56Sopenharmony_ci self.fail( 737db96d56Sopenharmony_ci f"{operation} failed with exit code {proc.returncode}") 747db96d56Sopenharmony_ci 757db96d56Sopenharmony_ci # Build the C++ extension 767db96d56Sopenharmony_ci cmd = [python, '-X', 'dev', 777db96d56Sopenharmony_ci SETUP_TESTCPPEXT, 'build_ext', '--verbose'] 787db96d56Sopenharmony_ci if std_cpp03: 797db96d56Sopenharmony_ci cmd.append('-std=c++03') 807db96d56Sopenharmony_ci run_cmd('Build', cmd) 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci # Install the C++ extension 837db96d56Sopenharmony_ci cmd = [python, '-X', 'dev', 847db96d56Sopenharmony_ci SETUP_TESTCPPEXT, 'install'] 857db96d56Sopenharmony_ci run_cmd('Install', cmd) 867db96d56Sopenharmony_ci 877db96d56Sopenharmony_ci # Do a reference run. Until we test that running python 887db96d56Sopenharmony_ci # doesn't leak references (gh-94755), run it so one can manually check 897db96d56Sopenharmony_ci # -X showrefcount results against this baseline. 907db96d56Sopenharmony_ci cmd = [python, 917db96d56Sopenharmony_ci '-X', 'dev', 927db96d56Sopenharmony_ci '-X', 'showrefcount', 937db96d56Sopenharmony_ci '-c', 'pass'] 947db96d56Sopenharmony_ci run_cmd('Reference run', cmd) 957db96d56Sopenharmony_ci 967db96d56Sopenharmony_ci # Import the C++ extension 977db96d56Sopenharmony_ci cmd = [python, 987db96d56Sopenharmony_ci '-X', 'dev', 997db96d56Sopenharmony_ci '-X', 'showrefcount', 1007db96d56Sopenharmony_ci '-c', f"import {extension_name}"] 1017db96d56Sopenharmony_ci run_cmd('Import', cmd) 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ciif __name__ == "__main__": 1057db96d56Sopenharmony_ci unittest.main() 106