@@ -191,7 +191,6 @@ def _create_executable(
191191        hasattr (runtime_details .effective_runtime , "stage2_bootstrap_template" )):
192192        venv  =  _create_venv (
193193            ctx ,
194-             executable  =  executable ,
195194            output_prefix  =  base_executable_name ,
196195            imports  =  imports ,
197196            runtime_details  =  runtime_details ,
@@ -345,13 +344,34 @@ def _create_zip_main(ctx, *, stage2_bootstrap, runtime_details, venv):
345344    )
346345    return  output 
347346
347+ 
348+ # Return a relative path from one path to another, where both paths are each 
349+ # relative paths from a common root. 
350+ def  _relative_path (from_ , to ):
351+     from_parts  =  from_ .split ("/" )
352+     to_parts  =  to .split ("/" )
353+ 
354+     # Strip common "../" parts from both paths 
355+     # (no while loops in starlark :( ) 
356+     n  =  max (len (from_parts ), len (to_parts ))
357+     for  _  in  range (n ):
358+         if  from_parts [0 ] ==  ".."  and  to_parts [0 ] ==  ".." :
359+             from_parts .pop (0 )
360+             to_parts .pop (0 )
361+         else :
362+             break 
363+ 
364+     parent  =  "/" .join ([".." ] *  len (from_parts ))
365+     return  "/" .join ([parent ] +  to_parts )
366+ 
367+ 
348368# Create a venv the executable can use. 
349369# For venv details and the venv startup process, see: 
350370# * https://docs.python.org/3/library/venv.html 
351371# * https://snarky.ca/how-virtual-environments-work/ 
352372# * https://github.com/python/cpython/blob/main/Modules/getpath.py 
353373# * https://github.com/python/cpython/blob/main/Lib/site.py 
354- def  _create_venv (ctx , executable ,  output_prefix , imports , runtime_details ):
374+ def  _create_venv (ctx , output_prefix , imports , runtime_details ):
355375    venv  =  "_{}.venv" .format (output_prefix .lstrip ("_" ))
356376
357377    # The pyvenv.cfg file must be present to trigger the venv site hooks. 
@@ -369,13 +389,9 @@ def _create_venv(ctx, executable, output_prefix, imports, runtime_details):
369389        # in runfiles is always a symlink. An RBE implementation, for example, 
370390        # may choose to write what symlink() points to instead. 
371391        interpreter  =  ctx .actions .declare_symlink ("{}/bin/{}" .format (venv , py_exe_basename ))
372-         interpreter_actual_path  =  runtime .interpreter .short_path   # Always relative to .runfiles/${workspace} 
373- 
374-         escapes  =  2   # To escape out of ${target}.venv/bin 
375-         escapes  +=  executable .short_path .count ("/" )  # To escape into .runfiles/${workspace} 
376- 
377-         parent  =  "/" .join ([".." ] *  escapes )
378-         rel_path  =  parent  +  "/"  +  interpreter_actual_path 
392+         interpreter_actual_path  =  runtime .interpreter .short_path 
393+         venv_bin_dir  =  paths .dirname (interpreter .short_path )
394+         rel_path  =  _relative_path (from_ = venv_bin_dir , to = interpreter_actual_path )
379395        ctx .actions .symlink (output  =  interpreter , target_path  =  rel_path )
380396    else :
381397        py_exe_basename  =  paths .basename (runtime .interpreter_path )
0 commit comments