@@ -183,114 +183,93 @@ def _extract_tar(archive_path: pathlib.Path, prefix: str, target_dir: pathlib.Pa
183183####################
184184# libc management
185185####################
186-
187- ####################
188- # libc management
189- ####################
190-
191186GLIBC_VERSION = "2.34"
192187GLIBC_ROOT = pathlib .Path (f"/tmp/glibc-install-{ GLIBC_VERSION } " )
193188GLIBC_LIBDIR = GLIBC_ROOT / "lib"
194-
195- # Loader candidates: Fedora RPM may give us either ld-2.34.so or ld-linux-x86-64.so.2
196- GLIBC_LOADER_CANDIDATES = [
197- GLIBC_LIBDIR / f"ld-{ GLIBC_VERSION } .so" ,
198- GLIBC_LIBDIR / "ld-linux-x86-64.so.2" ,
199- ]
200- GLIBC_LOADER = next ((p for p in GLIBC_LOADER_CANDIDATES if p .exists ()), None )
201-
202189GLIBC_REEXEC_GUARD = "QNN_GLIBC_REEXEC"
203- MINIMUM_LIBC_VERSION = GLIBC_VERSION
204- GLIBC_CUSTOM = str (GLIBC_LIBDIR / "libc.so.6" )
190+ MINIMUM_LIBC_VERSION = GLIBC_VERSION # string like "2.34"
205191
206192
207193def _parse_version (v : str ) -> tuple [int , int ]:
208194 parts = v .split ("." )
209195 return int (parts [0 ]), int (parts [1 ]) if len (parts ) > 1 else 0
210196
211197
212- def check_glibc_exist_and_validate () -> bool :
213- """
214- Validate glibc in /tmp, fallback to system libc only if custom one not found.
215- """
216- candidates = [GLIBC_CUSTOM ]
198+ def _resolve_glibc_loader () -> pathlib .Path | None :
199+ for p in [
200+ GLIBC_LIBDIR / f"ld-{ GLIBC_VERSION } .so" ,
201+ GLIBC_LIBDIR / "ld-linux-x86-64.so.2" ,
202+ ]:
203+ if p .exists ():
204+ return p
205+ return None
217206
218- # Optional: keep fallbacks for debugging (not recommended in CI if you always stage custom)
219- candidates += [
220- "/lib64/libc.so.6" ,
221- "/lib/x86_64-linux-gnu/libc.so.6" ,
222- "/lib/libc.so.6" ,
223- ]
224207
225- for path in candidates :
226- if not pathlib .Path (path ).exists ():
227- continue
228- try :
229- output = subprocess .check_output (
230- [path , "--version" ], stderr = subprocess .STDOUT
231- )
232- first_line = output .decode ().split ("\n " , 1 )[0 ]
233- logger .debug (f"[QNN] glibc version for path { path } is: { first_line } " )
234-
235- match = re .search (r"version (\d+\.\d+)" , first_line )
236- if match :
237- version = match .group (1 )
238- if _parse_version (version ) >= _parse_version (MINIMUM_LIBC_VERSION ):
239- logger .info (f"[QNN] Using glibc { version } from { path } " )
240- return True
241- else :
242- logger .error (
243- f"[QNN] glibc version { version } too low at { path } . Need >= { MINIMUM_LIBC_VERSION } ."
244- )
245- else :
246- logger .error (f"[QNN] Could not parse glibc version from { first_line } " )
247- except Exception as e :
248- logger .error (f"[QNN] Failed to check { path } : { e } " )
208+ def _log_current_loader ():
209+ """Dump the loader and libc mappings from /proc/self/maps for debugging."""
210+ try :
211+ with open ("/proc/self/maps" ) as f :
212+ for line in f :
213+ if "ld-" in line or "libc.so" in line :
214+ logger .info ("[glibc] Loader map: %s" , line .strip ())
215+ except Exception as e :
216+ logger .warning ("[glibc] Failed to read /proc/self/maps: %s" , e )
249217
250- logger .error (
251- f"[QNN] glibc not found or too old. Minimum required: { MINIMUM_LIBC_VERSION } ."
252- )
253- return False
218+
219+ def _current_glibc_version () -> str :
220+ try :
221+ libc = ctypes .CDLL ("libc.so.6" )
222+ func = libc .gnu_get_libc_version
223+ func .restype = ctypes .c_char_p
224+ return func ().decode ()
225+ except Exception as e :
226+ return f"error:{ e } "
227+
228+
229+ def _run_under_custom_loader (argv : list [str ]) -> bytes :
230+ loader = _resolve_glibc_loader ()
231+ if not loader :
232+ raise FileNotFoundError (f"glibc loader not found in { GLIBC_LIBDIR } " )
233+ cmd = [str (loader ), "--library-path" , str (GLIBC_LIBDIR ), * argv ]
234+ return subprocess .check_output (cmd , stderr = subprocess .STDOUT )
254235
255236
256237def _check_tmp_glibc () -> bool :
257- """Check if staged glibc in /tmp was installed correctly and log its version."""
258238 libc_path = GLIBC_LIBDIR / "libc.so.6"
259239 if not libc_path .exists ():
260240 logger .error ("[glibc] Expected glibc at %s but file not found" , libc_path )
261241 return False
262-
263242 try :
264- out = subprocess .check_output (
265- [str (libc_path ), "--version" ], stderr = subprocess .STDOUT
266- )
243+ out = _run_under_custom_loader ([str (libc_path ), "--version" ])
267244 first_line = out .decode (errors = "ignore" ).split ("\n " , 1 )[0 ]
268245 logger .info ("[glibc] Found custom glibc at %s: %s" , libc_path , first_line )
269246 return True
270247 except Exception as e :
271- logger .error ("[glibc] Failed to run %s --version : %s" , libc_path , e )
248+ logger .error ("[glibc] Failed to run libc under staged loader : %s" , e )
272249 return False
273250
274251
275- def _current_glibc_version () -> str :
276- try :
277- libc = ctypes .CDLL ("libc.so.6" )
278- func = libc .gnu_get_libc_version
279- func .restype = ctypes .c_char_p
280- return func ().decode ()
281- except Exception as e :
282- return f"error:{ e } "
283-
284-
285- def _log_current_loader ():
286- """Dump the loader and libc mappings from /proc/self/maps for debugging."""
252+ def check_glibc_exist_and_validate () -> bool :
253+ libc = GLIBC_LIBDIR / "libc.so.6"
254+ if not libc .exists ():
255+ logger .error ("[QNN] staged libc missing at %s" , libc )
256+ return False
287257 try :
288- with open ("/proc/self/maps" ) as f :
289- for line in f :
290- if "ld-" in line or "libc.so" in line :
291- logger .info ("[glibc] Loader map: %s" , line .strip ())
258+ out = _run_under_custom_loader ([str (libc ), "--version" ])
259+ first = out .decode (errors = "ignore" ).split ("\n " , 1 )[0 ]
260+ m = re .search (r"version (\d+\.\d+)" , first )
261+ if not m :
262+ logger .error ("[QNN] could not parse glibc version from: %s" , first )
263+ return False
264+ ver = m .group (1 )
265+ if _parse_version (ver ) >= _parse_version (MINIMUM_LIBC_VERSION ):
266+ logger .info ("[QNN] Using glibc %s from %s" , ver , libc )
267+ return True
268+ logger .error ("[QNN] glibc %s < required %s" , ver , MINIMUM_LIBC_VERSION )
269+ return False
292270 except Exception as e :
293- logger .warning ("[glibc] Failed to read /proc/self/maps: %s" , e )
271+ logger .error ("[QNN] failed to validate staged glibc: %s" , e )
272+ return False
294273
295274
296275def _ensure_glibc_minimum (min_version : str = GLIBC_VERSION ):
@@ -302,21 +281,18 @@ def _ensure_glibc_minimum(min_version: str = GLIBC_VERSION):
302281 _log_current_loader ()
303282 return
304283
305- if not GLIBC_LOADER or not GLIBC_LOADER .exists ():
284+ loader = _resolve_glibc_loader ()
285+ if not loader :
306286 logger .error ("[glibc] Loader not found in %s" , GLIBC_LIBDIR )
307287 return
308288
309289 logger .info (
310- "[glibc] Forcing re-exec under loader %s with libdir %s" ,
311- GLIBC_LOADER ,
312- GLIBC_LIBDIR ,
290+ "[glibc] Forcing re-exec under loader %s with libdir %s" , loader , GLIBC_LIBDIR
313291 )
314-
315292 os .environ [GLIBC_REEXEC_GUARD ] = "1"
316293 os .execv (
317- str (GLIBC_LOADER ),
318- [str (GLIBC_LOADER ), "--library-path" , str (GLIBC_LIBDIR ), sys .executable ]
319- + sys .argv ,
294+ str (loader ),
295+ [str (loader ), "--library-path" , str (GLIBC_LIBDIR ), sys .executable ] + sys .argv ,
320296 )
321297
322298
@@ -521,13 +497,8 @@ def install_qnn_sdk() -> bool:
521497 True if both steps succeeded (or were already satisfied), else False.
522498 """
523499 logger .info ("[QNN] Starting SDK installation" )
524-
525500 _ensure_glibc_minimum (GLIBC_VERSION )
526-
527501 if not _check_tmp_glibc ():
528502 logger .error ("[glibc] Pre-installed glibc check failed. Exiting early." )
529503 return False
530-
531- if _ensure_libcxx_stack () and _ensure_qnn_sdk_lib ():
532- return True
533- return False
504+ return _ensure_libcxx_stack () and _ensure_qnn_sdk_lib ()
0 commit comments