33import re
44import shlex
55import sys
6+ import sysconfig
67import time
78
89from test import support
2223 strip_py_suffix , count , format_duration ,
2324 printlist , get_temp_dir , get_work_dir , exit_timeout ,
2425 display_header , cleanup_temp_dir , print_warning ,
26+ is_cross_compiled , get_host_runner ,
2527 MS_WINDOWS , EXIT_TIMEOUT )
2628
2729
@@ -71,10 +73,9 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False):
7173 self .want_rerun : bool = ns .rerun
7274 self .want_run_leaks : bool = ns .runleaks
7375
74- ci_mode = (ns .fast_ci or ns .slow_ci )
76+ self . ci_mode : bool = (ns .fast_ci or ns .slow_ci )
7577 self .want_add_python_opts : bool = (_add_python_opts
76- and ns ._add_python_opts
77- and ci_mode )
78+ and ns ._add_python_opts )
7879
7980 # Select tests
8081 if ns .match_tests :
@@ -431,7 +432,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
431432 if (self .want_header
432433 or not (self .pgo or self .quiet or self .single_test_run
433434 or tests or self .cmdline_args )):
434- display_header (self .use_resources )
435+ display_header (self .use_resources , self . python_cmd )
435436
436437 if self .randomize :
437438 print ("Using random seed" , self .random_seed )
@@ -489,8 +490,56 @@ def run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
489490 # processes.
490491 return self ._run_tests (selected , tests )
491492
492- def _add_python_opts (self ):
493- python_opts = []
493+ def _add_cross_compile_opts (self , regrtest_opts ):
494+ # WASM/WASI buildbot builders pass multiple PYTHON environment
495+ # variables such as PYTHONPATH and _PYTHON_HOSTRUNNER.
496+ keep_environ = bool (self .python_cmd )
497+ environ = None
498+
499+ # Are we using cross-compilation?
500+ cross_compile = is_cross_compiled ()
501+
502+ # Get HOSTRUNNER
503+ hostrunner = get_host_runner ()
504+
505+ if cross_compile :
506+ # emulate -E, but keep PYTHONPATH + cross compile env vars,
507+ # so test executable can load correct sysconfigdata file.
508+ keep = {
509+ '_PYTHON_PROJECT_BASE' ,
510+ '_PYTHON_HOST_PLATFORM' ,
511+ '_PYTHON_SYSCONFIGDATA_NAME' ,
512+ 'PYTHONPATH'
513+ }
514+ old_environ = os .environ
515+ new_environ = {
516+ name : value for name , value in os .environ .items ()
517+ if not name .startswith (('PYTHON' , '_PYTHON' )) or name in keep
518+ }
519+ # Only set environ if at least one variable was removed
520+ if new_environ != old_environ :
521+ environ = new_environ
522+ keep_environ = True
523+
524+ if cross_compile and hostrunner :
525+ if self .num_workers == 0 :
526+ # For now use only two cores for cross-compiled builds;
527+ # hostrunner can be expensive.
528+ regrtest_opts .extend (['-j' , '2' ])
529+
530+ # If HOSTRUNNER is set and -p/--python option is not given, then
531+ # use hostrunner to execute python binary for tests.
532+ if not self .python_cmd :
533+ buildpython = sysconfig .get_config_var ("BUILDPYTHON" )
534+ python_cmd = f"{ hostrunner } { buildpython } "
535+ regrtest_opts .extend (["--python" , python_cmd ])
536+ keep_environ = True
537+
538+ return (environ , keep_environ )
539+
540+ def _add_ci_python_opts (self , python_opts , keep_environ ):
541+ # --fast-ci and --slow-ci add options to Python:
542+ # "-u -W default -bb -E"
494543
495544 # Unbuffered stdout and stderr
496545 if not sys .stdout .write_through :
@@ -504,32 +553,27 @@ def _add_python_opts(self):
504553 if sys .flags .bytes_warning < 2 :
505554 python_opts .append ('-bb' )
506555
507- # WASM/WASI buildbot builders pass multiple PYTHON environment
508- # variables such as PYTHONPATH and _PYTHON_HOSTRUNNER.
509- if not self .python_cmd :
556+ if not keep_environ :
510557 # Ignore PYTHON* environment variables
511558 if not sys .flags .ignore_environment :
512559 python_opts .append ('-E' )
513560
514- if not python_opts :
515- return
516-
517- cmd = [* sys .orig_argv , "--dont-add-python-opts" ]
518- cmd [1 :1 ] = python_opts
519-
561+ def _execute_python (self , cmd , environ ):
520562 # Make sure that messages before execv() are logged
521563 sys .stdout .flush ()
522564 sys .stderr .flush ()
523565
524566 cmd_text = shlex .join (cmd )
525567 try :
568+ print (f"+ { cmd_text } " , flush = True )
569+
526570 if hasattr (os , 'execv' ) and not MS_WINDOWS :
527571 os .execv (cmd [0 ], cmd )
528572 # On success, execv() do no return.
529573 # On error, it raises an OSError.
530574 else :
531575 import subprocess
532- with subprocess .Popen (cmd ) as proc :
576+ with subprocess .Popen (cmd , env = environ ) as proc :
533577 try :
534578 proc .wait ()
535579 except KeyboardInterrupt :
@@ -548,6 +592,28 @@ def _add_python_opts(self):
548592 f"Command: { cmd_text } " )
549593 # continue executing main()
550594
595+ def _add_python_opts (self ):
596+ python_opts = []
597+ regrtest_opts = []
598+
599+ environ , keep_environ = self ._add_cross_compile_opts (regrtest_opts )
600+ if self .ci_mode :
601+ self ._add_ci_python_opts (python_opts , keep_environ )
602+
603+ if (not python_opts ) and (not regrtest_opts ) and (environ is None ):
604+ # Nothing changed: nothing to do
605+ return
606+
607+ # Create new command line
608+ cmd = list (sys .orig_argv )
609+ if python_opts :
610+ cmd [1 :1 ] = python_opts
611+ if regrtest_opts :
612+ cmd .extend (regrtest_opts )
613+ cmd .append ("--dont-add-python-opts" )
614+
615+ self ._execute_python (cmd , environ )
616+
551617 def _init (self ):
552618 # Set sys.stdout encoder error handler to backslashreplace,
553619 # similar to sys.stderr error handler, to avoid UnicodeEncodeError
0 commit comments