@@ -12,7 +12,7 @@ use std::fs::canonicalize;
1212use std:: io:: Write ;
1313use std:: os:: unix:: fs:: PermissionsExt ;
1414use std:: os:: unix:: process:: ExitStatusExt ;
15- use std:: path:: Path ;
15+ use std:: path:: { Path , PathBuf } ;
1616use std:: { env:: consts:: ARCH , process:: Command } ;
1717use tempfile:: TempPath ;
1818
@@ -73,11 +73,98 @@ fn create_run_script() -> anyhow::Result<TempPath> {
7373 Ok ( script_file. into_temp_path ( ) )
7474}
7575
76+ /// By default, uv only symlinks the python3 executable which will cause the library lookups of
77+ /// valgrind or ldd to fail:
78+ /// ```no_run
79+ /// > ldd .venv/bin/python3
80+ /// /home/project/.venv/bin/../lib/libpython3.13.so.1.0 => not found
81+ /// ```
82+ ///
83+ /// To fix this, we have to also add the symlink to the `libpython` shared object.
84+ fn symlink_libcpython ( cwd : Option < & String > ) -> anyhow:: Result < ( ) > {
85+ let run_cmd = |cmd : & str , args : & [ & str ] | -> anyhow:: Result < String > {
86+ let mut cmd = Command :: new ( cmd) ;
87+
88+ if let Some ( cwd) = cwd {
89+ cmd. current_dir ( cwd) ;
90+ }
91+
92+ let output = cmd. args ( args) . output ( ) ?;
93+ if !output. status . success ( ) {
94+ let stderr = String :: from_utf8 ( output. stderr ) ?;
95+ bail ! ( "Failed to execute command: {}" , stderr) ;
96+ }
97+
98+ let output = String :: from_utf8 ( output. stdout ) ?;
99+ Ok ( output. trim ( ) . to_string ( ) )
100+ } ;
101+
102+ // 1. find the python installation and version
103+ let venv_python =
104+ run_cmd ( "uv" , & [ "python" , "find" ] ) . context ( "Failed to find uv python executable" ) ?;
105+ let system_python = std:: fs:: canonicalize ( & venv_python) ?;
106+ debug ! (
107+ "Python executables: {} (venv), {} (system)" ,
108+ venv_python,
109+ system_python. display( )
110+ ) ;
111+
112+ // 2. Resolve the symlink, then find the python dir
113+ let python_dir = |py_exe : & Path | {
114+ py_exe
115+ . parent ( )
116+ . and_then ( |p| p. parent ( ) )
117+ . context ( "Failed to find python dir" )
118+ . map ( |p| p. to_path_buf ( ) )
119+ } ;
120+
121+ let system_python_dir = python_dir ( & system_python) ?;
122+ let venv_python_dir = python_dir ( & PathBuf :: from ( venv_python) ) ?;
123+ debug ! (
124+ "Python dirs: {} (venv), {} (system)" ,
125+ venv_python_dir. display( ) ,
126+ system_python_dir. display( ) ,
127+ ) ;
128+
129+ // 3. Find the libpython in the system dir
130+ let mut libpython_name = None ;
131+ for entry in std:: fs:: read_dir ( system_python_dir. join ( "lib" ) ) ?. filter_map ( Result :: ok) {
132+ let filename = entry. file_name ( ) . to_string_lossy ( ) . to_string ( ) ;
133+ if filename. starts_with ( "libpython" ) && filename. ends_with ( ".so.1.0" ) {
134+ libpython_name = Some ( filename) ;
135+ break ;
136+ }
137+ }
138+ let libpython_name = libpython_name. context ( "Failed to find libpython shared object" ) ?;
139+
140+ // Ensure the lib directory exists
141+ let venv_lib = venv_python_dir. join ( "lib" ) ;
142+ std:: fs:: create_dir_all ( & venv_lib) ?;
143+
144+ // 4. Create a symlink in .venv/lib/
145+ let libpython_path = |python_dir : & Path | python_dir. join ( "lib" ) . join ( & * libpython_name) ;
146+ let original_path = libpython_path ( & system_python_dir) ;
147+ let link_path = libpython_path ( & venv_python_dir) ;
148+ match std:: os:: unix:: fs:: symlink ( original_path, link_path) {
149+ Err ( error) if error. kind ( ) != std:: io:: ErrorKind :: AlreadyExists => {
150+ bail ! ( "Failed to create symlink: {}" , error)
151+ }
152+ _ => { }
153+ }
154+
155+ Ok ( ( ) )
156+ }
157+
76158pub async fn measure (
77159 config : & Config ,
78160 profile_folder : & Path ,
79161 mongo_tracer : & Option < MongoTracer > ,
80162) -> Result < ( ) > {
163+ // Ensure that valgrind can find the libpython library when using uv:
164+ if config. command . contains ( "uv run" ) {
165+ symlink_libcpython ( config. working_directory . as_ref ( ) ) ?;
166+ }
167+
81168 // Create the command
82169 let mut cmd = Command :: new ( "setarch" ) ;
83170 cmd. arg ( ARCH ) . arg ( "-R" ) ;
0 commit comments