3
3
import re
4
4
import shlex
5
5
import sys
6
+ import sysconfig
6
7
import time
7
8
8
9
from test import support
22
23
strip_py_suffix , count , format_duration ,
23
24
printlist , get_temp_dir , get_work_dir , exit_timeout ,
24
25
display_header , cleanup_temp_dir , print_warning ,
26
+ is_cross_compiled , get_host_runner ,
25
27
MS_WINDOWS , EXIT_TIMEOUT )
26
28
27
29
@@ -71,10 +73,9 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False):
71
73
self .want_rerun : bool = ns .rerun
72
74
self .want_run_leaks : bool = ns .runleaks
73
75
74
- ci_mode = (ns .fast_ci or ns .slow_ci )
76
+ self . ci_mode : bool = (ns .fast_ci or ns .slow_ci )
75
77
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 )
78
79
79
80
# Select tests
80
81
if ns .match_tests :
@@ -431,7 +432,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
431
432
if (self .want_header
432
433
or not (self .pgo or self .quiet or self .single_test_run
433
434
or tests or self .cmdline_args )):
434
- display_header (self .use_resources )
435
+ display_header (self .use_resources , self . python_cmd )
435
436
436
437
if self .randomize :
437
438
print ("Using random seed" , self .random_seed )
@@ -489,8 +490,56 @@ def run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
489
490
# processes.
490
491
return self ._run_tests (selected , tests )
491
492
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"
494
543
495
544
# Unbuffered stdout and stderr
496
545
if not sys .stdout .write_through :
@@ -504,32 +553,27 @@ def _add_python_opts(self):
504
553
if sys .flags .bytes_warning < 2 :
505
554
python_opts .append ('-bb' )
506
555
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 :
510
557
# Ignore PYTHON* environment variables
511
558
if not sys .flags .ignore_environment :
512
559
python_opts .append ('-E' )
513
560
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 ):
520
562
# Make sure that messages before execv() are logged
521
563
sys .stdout .flush ()
522
564
sys .stderr .flush ()
523
565
524
566
cmd_text = shlex .join (cmd )
525
567
try :
568
+ print (f"+ { cmd_text } " , flush = True )
569
+
526
570
if hasattr (os , 'execv' ) and not MS_WINDOWS :
527
571
os .execv (cmd [0 ], cmd )
528
572
# On success, execv() do no return.
529
573
# On error, it raises an OSError.
530
574
else :
531
575
import subprocess
532
- with subprocess .Popen (cmd ) as proc :
576
+ with subprocess .Popen (cmd , env = environ ) as proc :
533
577
try :
534
578
proc .wait ()
535
579
except KeyboardInterrupt :
@@ -548,6 +592,28 @@ def _add_python_opts(self):
548
592
f"Command: { cmd_text } " )
549
593
# continue executing main()
550
594
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
+
551
617
def _init (self ):
552
618
# Set sys.stdout encoder error handler to backslashreplace,
553
619
# similar to sys.stderr error handler, to avoid UnicodeEncodeError
0 commit comments