python-build-standalone icon indicating copy to clipboard operation
python-build-standalone copied to clipboard

Scripts in install/bin break if symlinked

Open mr-real opened this issue 2 years ago • 1 comments

Latest build (cpython-3.8.17+20230826-x86_64-apple-darwin-pgo+lto-full) Scripts in install/bin directory (e.g. pip) find interpreter by looking in the same directory as $0. Meanwhile, if such a script gets symlinked and a symlink is executed, $0 points to the symlink instead of its destination. (This is true for the chain of symlinks as well, each symlink in a chan will point at itself with $0.)

Because of that, symlinks of the scripts try to run the Python binary colocated with the symlink itself (which may not exist or may be a wrong Python distribution) rather than with the script behind a symlink.

mr-real avatar Sep 10 '23 06:09 mr-real

I've stumbled upon this issue myself, that is why I've written a small rust binary that when started resolves the executable (itself), canonicalizes that path (i.e. it can be any number of symlinks to it), and then executes the proper ./bin/python tool. (In my case it supports both Linux and Darwin installs side-by-side, but you can adjust for your needs.)

// rustc --crate-type bin -O -C target-feature=+crt-static -C relocation-model=static -o ./launcher--linux -- ./launcher.rs
// rustc --crate-type bin -O -o ./launcher--darwin -- ./launcher.rs


use std::{env, process, os::unix::process::CommandExt as _};


fn main () -> ! {
	
	let _executable = env::current_exe () .expect ("[10d63289]");
	let _executable = _executable.canonicalize () .expect ("[a0240181]");
	
	let _dirname = _executable.parent () .expect ("[4287ad94]");
	let _basename = _executable.file_name () .expect ("[ef7a04be]") .to_str () .expect ("[c31acf97]");
	let _target = match _basename {
		"launcher--linux" => "linux",
		"launcher--darwin" => "darwin",
		_ => panic! ("[d03e07b5] {}", _executable.display ()),
	};
	
	let _python = _dirname.join (_target) .join ("bin") .join ("python3.9");
	let _python = _python.canonicalize () .expect ("[ee9ea82d]");
	
	let _command = process::Command::new (_python) .args (env::args_os () .skip (1)) .exec ();
	unreachable! ("[54118a1e]");
}

cipriancraciun avatar Sep 11 '23 05:09 cipriancraciun