@@ -140,6 +140,9 @@ This is mutually exclusive with {obj}`main`.
140
140
141
141
:::{versionadded} 1.3.0
142
142
:::
143
+ :::{versionchanged} VERSION_NEXT_FEATURE
144
+ Support added for {obj}`--bootstrap_impl=system_python`.
145
+ :::
143
146
""" ,
144
147
),
145
148
"pyc_collection" : lambda : attrb .String (
@@ -332,9 +335,10 @@ def _create_executable(
332
335
# BuiltinPyRuntimeInfo providers, which is likely to come from
333
336
# @bazel_tools//tools/python:autodetecting_toolchain, the toolchain used
334
337
# for workspace builds when no rules_python toolchain is configured.
335
- if (BootstrapImplFlag . get_value ( ctx ) == BootstrapImplFlag . SCRIPT and
338
+ if (
336
339
runtime_details .effective_runtime and
337
- hasattr (runtime_details .effective_runtime , "stage2_bootstrap_template" )):
340
+ hasattr (runtime_details .effective_runtime , "stage2_bootstrap_template" )
341
+ ):
338
342
venv = _create_venv (
339
343
ctx ,
340
344
output_prefix = base_executable_name ,
@@ -351,7 +355,11 @@ def _create_executable(
351
355
runtime_details = runtime_details ,
352
356
venv = venv ,
353
357
)
354
- extra_runfiles = ctx .runfiles ([stage2_bootstrap ] + venv .files_without_interpreter )
358
+ extra_runfiles = ctx .runfiles (
359
+ [stage2_bootstrap ] + (
360
+ venv .files_without_interpreter if venv else []
361
+ ),
362
+ )
355
363
zip_main = _create_zip_main (
356
364
ctx ,
357
365
stage2_bootstrap = stage2_bootstrap ,
@@ -460,7 +468,7 @@ def _create_executable(
460
468
461
469
# The interpreter is added this late in the process so that it isn't
462
470
# added to the zipped files.
463
- if venv :
471
+ if venv and venv . interpreter :
464
472
extra_runfiles = extra_runfiles .merge (ctx .runfiles ([venv .interpreter ]))
465
473
return create_executable_result_struct (
466
474
extra_files_to_build = depset (extra_files_to_build ),
@@ -469,7 +477,10 @@ def _create_executable(
469
477
)
470
478
471
479
def _create_zip_main (ctx , * , stage2_bootstrap , runtime_details , venv ):
472
- python_binary = runfiles_root_path (ctx , venv .interpreter .short_path )
480
+ if venv .interpreter :
481
+ python_binary = runfiles_root_path (ctx , venv .interpreter .short_path )
482
+ else :
483
+ python_binary = ""
473
484
python_binary_actual = venv .interpreter_actual_path
474
485
475
486
# The location of this file doesn't really matter. It's added to
@@ -529,62 +540,66 @@ def relative_path(from_, to):
529
540
# * https://github.com/python/cpython/blob/main/Modules/getpath.py
530
541
# * https://github.com/python/cpython/blob/main/Lib/site.py
531
542
def _create_venv (ctx , output_prefix , imports , runtime_details ):
543
+ create_full_venv = BootstrapImplFlag .get_value (ctx ) == BootstrapImplFlag .SCRIPT
532
544
venv = "_{}.venv" .format (output_prefix .lstrip ("_" ))
533
545
534
- # The pyvenv.cfg file must be present to trigger the venv site hooks.
535
- # Because it's paths are expected to be absolute paths, we can't reliably
536
- # put much in it. See https://github.com/python/cpython/issues/83650
537
- pyvenv_cfg = ctx .actions .declare_file ("{}/pyvenv.cfg" .format (venv ))
538
- ctx .actions .write (pyvenv_cfg , "" )
546
+ if create_full_venv :
547
+ # The pyvenv.cfg file must be present to trigger the venv site hooks.
548
+ # Because it's paths are expected to be absolute paths, we can't reliably
549
+ # put much in it. See https://github.com/python/cpython/issues/83650
550
+ pyvenv_cfg = ctx .actions .declare_file ("{}/pyvenv.cfg" .format (venv ))
551
+ ctx .actions .write (pyvenv_cfg , "" )
552
+ else :
553
+ pyvenv_cfg = None
539
554
540
555
runtime = runtime_details .effective_runtime
541
556
542
557
venvs_use_declare_symlink_enabled = (
543
558
VenvsUseDeclareSymlinkFlag .get_value (ctx ) == VenvsUseDeclareSymlinkFlag .YES
544
559
)
545
560
recreate_venv_at_runtime = False
546
- bin_dir = "{}/bin" .format (venv )
547
-
548
- if not venvs_use_declare_symlink_enabled or not runtime .supports_build_time_venv :
549
- recreate_venv_at_runtime = True
550
- if runtime .interpreter :
551
- interpreter_actual_path = runfiles_root_path (ctx , runtime .interpreter .short_path )
552
- else :
553
- interpreter_actual_path = runtime .interpreter_path
554
561
555
- py_exe_basename = paths .basename (interpreter_actual_path )
562
+ if runtime .interpreter :
563
+ interpreter_actual_path = runfiles_root_path (ctx , runtime .interpreter .short_path )
564
+ else :
565
+ interpreter_actual_path = runtime .interpreter_path
556
566
557
- # When the venv symlinks are disabled, the $venv/bin/python3 file isn't
558
- # needed or used at runtime. However, the zip code uses the interpreter
559
- # File object to figure out some paths.
560
- interpreter = ctx .actions .declare_file ("{}/{}" .format (bin_dir , py_exe_basename ))
561
- ctx .actions .write (interpreter , "actual:{}" .format (interpreter_actual_path ))
567
+ bin_dir = "{}/bin" .format (venv )
562
568
563
- elif runtime . interpreter :
569
+ if create_full_venv :
564
570
# Some wrappers around the interpreter (e.g. pyenv) use the program
565
571
# name to decide what to do, so preserve the name.
566
- py_exe_basename = paths .basename (runtime . interpreter . short_path )
572
+ py_exe_basename = paths .basename (interpreter_actual_path )
567
573
568
- # Even though ctx.actions.symlink() is used, using
569
- # declare_symlink() is required to ensure that the resulting file
570
- # in runfiles is always a symlink. An RBE implementation, for example,
571
- # may choose to write what symlink() points to instead.
572
- interpreter = ctx .actions .declare_symlink ("{}/{}" .format (bin_dir , py_exe_basename ))
574
+ if not venvs_use_declare_symlink_enabled or not runtime .supports_build_time_venv :
575
+ recreate_venv_at_runtime = True
573
576
574
- interpreter_actual_path = runfiles_root_path (ctx , runtime .interpreter .short_path )
575
- rel_path = relative_path (
576
- # dirname is necessary because a relative symlink is relative to
577
- # the directory the symlink resides within.
578
- from_ = paths .dirname (runfiles_root_path (ctx , interpreter .short_path )),
579
- to = interpreter_actual_path ,
580
- )
577
+ # When the venv symlinks are disabled, the $venv/bin/python3 file isn't
578
+ # needed or used at runtime. However, the zip code uses the interpreter
579
+ # File object to figure out some paths.
580
+ interpreter = ctx .actions .declare_file ("{}/{}" .format (bin_dir , py_exe_basename ))
581
+ ctx .actions .write (interpreter , "actual:{}" .format (interpreter_actual_path ))
581
582
582
- ctx .actions .symlink (output = interpreter , target_path = rel_path )
583
+ elif runtime .interpreter :
584
+ # Even though ctx.actions.symlink() is used, using
585
+ # declare_symlink() is required to ensure that the resulting file
586
+ # in runfiles is always a symlink. An RBE implementation, for example,
587
+ # may choose to write what symlink() points to instead.
588
+ interpreter = ctx .actions .declare_symlink ("{}/{}" .format (bin_dir , py_exe_basename ))
589
+
590
+ rel_path = relative_path (
591
+ # dirname is necessary because a relative symlink is relative to
592
+ # the directory the symlink resides within.
593
+ from_ = paths .dirname (runfiles_root_path (ctx , interpreter .short_path )),
594
+ to = interpreter_actual_path ,
595
+ )
596
+
597
+ ctx .actions .symlink (output = interpreter , target_path = rel_path )
598
+ else :
599
+ interpreter = ctx .actions .declare_symlink ("{}/{}" .format (bin_dir , py_exe_basename ))
600
+ ctx .actions .symlink (output = interpreter , target_path = runtime .interpreter_path )
583
601
else :
584
- py_exe_basename = paths .basename (runtime .interpreter_path )
585
- interpreter = ctx .actions .declare_symlink ("{}/{}" .format (bin_dir , py_exe_basename ))
586
- ctx .actions .symlink (output = interpreter , target_path = runtime .interpreter_path )
587
- interpreter_actual_path = runtime .interpreter_path
602
+ interpreter = None
588
603
589
604
if runtime .interpreter_version_info :
590
605
version = "{}.{}" .format (
@@ -626,14 +641,29 @@ def _create_venv(ctx, output_prefix, imports, runtime_details):
626
641
}
627
642
venv_symlinks = _create_venv_symlinks (ctx , venv_dir_map )
628
643
644
+ files_without_interpreter = [pth , site_init ] + venv_symlinks
645
+ if pyvenv_cfg :
646
+ files_without_interpreter .append (pyvenv_cfg )
647
+
629
648
return struct (
649
+ # File or None; the `bin/python3` executable in the venv.
650
+ # None if a full venv isn't created.
630
651
interpreter = interpreter ,
652
+ # bool; True if the venv should be recreated at runtime
631
653
recreate_venv_at_runtime = recreate_venv_at_runtime ,
632
654
# Runfiles root relative path or absolute path
633
655
interpreter_actual_path = interpreter_actual_path ,
634
- files_without_interpreter = [ pyvenv_cfg , pth , site_init ] + venv_symlinks ,
656
+ files_without_interpreter = files_without_interpreter ,
635
657
# string; venv-relative path to the site-packages directory.
636
658
venv_site_packages = venv_site_packages ,
659
+ # string; runfiles-root relative path to venv root.
660
+ venv_root = runfiles_root_path (
661
+ ctx ,
662
+ paths .join (
663
+ py_internal .get_label_repo_runfiles_path (ctx .label ),
664
+ venv ,
665
+ ),
666
+ ),
637
667
)
638
668
639
669
def _create_venv_symlinks (ctx , venv_dir_map ):
@@ -746,7 +776,7 @@ def _create_stage2_bootstrap(
746
776
main_py ,
747
777
imports ,
748
778
runtime_details ,
749
- venv = None ):
779
+ venv ):
750
780
output = ctx .actions .declare_file (
751
781
# Prepend with underscore to prevent pytest from trying to
752
782
# process the bootstrap for files starting with `test_`
@@ -758,17 +788,10 @@ def _create_stage2_bootstrap(
758
788
template = runtime .stage2_bootstrap_template
759
789
760
790
if main_py :
761
- main_py_path = "{}/{}" . format (ctx . workspace_name , main_py .short_path )
791
+ main_py_path = runfiles_root_path (ctx , main_py .short_path )
762
792
else :
763
793
main_py_path = ""
764
794
765
- # The stage2 bootstrap uses the venv site-packages location to fix up issues
766
- # that occur when the toolchain doesn't support the build-time venv.
767
- if venv and not runtime .supports_build_time_venv :
768
- venv_rel_site_packages = venv .venv_site_packages
769
- else :
770
- venv_rel_site_packages = ""
771
-
772
795
ctx .actions .expand_template (
773
796
template = template ,
774
797
output = output ,
@@ -779,7 +802,8 @@ def _create_stage2_bootstrap(
779
802
"%main%" : main_py_path ,
780
803
"%main_module%" : ctx .attr .main_module ,
781
804
"%target%" : str (ctx .label ),
782
- "%venv_rel_site_packages%" : venv_rel_site_packages ,
805
+ "%venv_rel_site_packages%" : venv .venv_site_packages ,
806
+ "%venv_root%" : venv .venv_root ,
783
807
"%workspace_name%" : ctx .workspace_name ,
784
808
},
785
809
is_executable = True ,
@@ -800,7 +824,10 @@ def _create_stage1_bootstrap(
800
824
runtime = runtime_details .effective_runtime
801
825
802
826
if venv :
803
- python_binary_path = runfiles_root_path (ctx , venv .interpreter .short_path )
827
+ if venv .interpreter :
828
+ python_binary_path = runfiles_root_path (ctx , venv .interpreter .short_path )
829
+ else :
830
+ python_binary_path = ""
804
831
else :
805
832
python_binary_path = runtime_details .executable_interpreter_path
806
833
0 commit comments