55if [[ -n " ${RULES_PYTHON_BOOTSTRAP_VERBOSE:- } " ]]; then
66 set -x
77fi
8+ set -x
89
910# runfiles-relative path
1011STAGE2_BOOTSTRAP=" %stage2_bootstrap%"
1112
12- # runfiles-relative path to python interpreter to use
13+ # runfiles-relative path to python interpreter to use.
14+ # This is the `bin/python3` file in the binary's venv.
1315PYTHON_BINARY=' %python_binary%'
1416# The path that PYTHON_BINARY should symlink to.
1517# runfiles-relative path, absolute path, or single word.
@@ -18,8 +20,17 @@ PYTHON_BINARY_ACTUAL="%python_binary_actual%"
1820
1921# 0 or 1
2022IS_ZIPFILE=" %is_zipfile%"
21- # 0 or 1
23+ # 0 or 1.
24+ # If 1, then a venv will be created at runtime that replicates what would have
25+ # been the build-time structure.
2226RECREATE_VENV_AT_RUNTIME=" %recreate_venv_at_runtime%"
27+ # 0 or 1
28+ # If 1, then the path to python will be resolved by running
29+ # PYTHON_BINARY_ACTUAL to determine the actual underlying interpreter.
30+ RESOLVE_PYTHON_BINARY_AT_RUNTIME=" %resolve_python_binary_at_runtime%"
31+ # venv-relative path to the site-packages
32+ # e.g. lib/python3.12t/site-packages
33+ VENV_REL_SITE_PACKAGES=" %venv_rel_site_packages%"
2334
2435# array of strings
2536declare -a INTERPRETER_ARGS_FROM_TARGET=(
@@ -136,6 +147,7 @@ if [[ "$IS_ZIPFILE" == "1" ]]; then
136147 mkdir -p " $( dirname $python_exe ) "
137148 ln -s " $symlink_to " " $python_exe "
138149elif [[ " $RECREATE_VENV_AT_RUNTIME " == " 1" ]]; then
150+
139151 if [[ -n " $RULES_PYTHON_EXTRACT_ROOT " ]]; then
140152 use_exec=1
141153 # Use our runfiles path as a unique, reusable, location for the
@@ -167,19 +179,50 @@ elif [[ "$RECREATE_VENV_AT_RUNTIME" == "1" ]]; then
167179 exit 1
168180 fi
169181 fi
170- mkdir -p " $venv /bin"
182+
183+ runfiles_venv=" $RUNFILES_DIR /$( dirname $( dirname $PYTHON_BINARY ) ) "
184+
185+ # If the interpreter is a wrapper script that invokes Python, and
186+ # is prior to Python 3.11 (PYTHONEXECUTABLE environment variable), then
187+ # we can only trigger venv behavior by symlinking to the actual underlying
188+ # interpreter.
189+ # Additionally, if the build-time lib/pythonX.Y/site-packages path doesn't
190+ # match what the runtime interpreter is looking for (i.e. version mismatch
191+ # between build vs runtime), then pretend the version mismatch is OK :D,
192+ # and create the desired path in the temporary venv.
193+ if [[ " $RESOLVE_PYTHON_BINARY_AT_RUNTIME " == " 1" ]]; then
194+ {
195+ read -r resolved_py_exe
196+ read -r resolved_site_packages
197+ } < <( " $symlink_to " -I << EOF
198+ import sys, site, os
199+ print(sys.executable)
200+ print(site.getsitepackages(["$venv "])[-1])
201+ EOF
202+ )
203+ symlink_to=" $resolved_py_exe "
204+ runfiles_venv_site_packages=$runfiles_venv /$VENV_REL_SITE_PACKAGES
205+ venv_site_packages=" $resolved_site_packages "
206+ else
207+ # For simplicity, just symlink to the whole lib directory.
208+ runfiles_venv_site_packages=$runfiles_venv /lib
209+ venv_site_packages=$venv /lib
210+ fi
211+
171212 # Match the basename; some tools, e.g. pyvenv key off the executable name
172213 python_exe=" $venv /bin/$( basename $PYTHON_BINARY_ACTUAL ) "
173214 if [[ ! -e " $python_exe " ]]; then
215+ mkdir -p " $venv /bin"
174216 ln -s " $symlink_to " " $python_exe "
175217 fi
176- runfiles_venv=" $RUNFILES_DIR /$( dirname $( dirname $PYTHON_BINARY ) ) "
177218 if [[ ! -e " $venv /pyvenv.cfg" ]]; then
178219 ln -s " $runfiles_venv /pyvenv.cfg" " $venv /pyvenv.cfg"
179220 fi
180- if [[ ! -e " $venv /lib" ]]; then
181- ln -s " $runfiles_venv /lib" " $venv /lib"
221+ if [[ ! -e " $venv_site_packages " ]]; then
222+ mkdir -p $( dirname $venv_site_packages )
223+ ln -s " $runfiles_venv_site_packages " " $venv_site_packages "
182224 fi
225+
183226else
184227 use_exec=1
185228fi
0 commit comments