@@ -187,36 +187,24 @@ def _extract_tar(archive_path: pathlib.Path, prefix: str, target_dir: pathlib.Pa
187187GLIBC_ROOT = pathlib .Path (f"/tmp/glibc-install-{ GLIBC_VERSION } " )
188188GLIBC_LIBDIR = GLIBC_ROOT / "lib"
189189GLIBC_REEXEC_GUARD = "QNN_GLIBC_REEXEC"
190- MINIMUM_LIBC_VERSION = GLIBC_VERSION # string like "2.34"
190+ MINIMUM_LIBC_VERSION = GLIBC_VERSION
191+
192+ RPM_URL = (
193+ "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/35/"
194+ "Everything/x86_64/os/Packages/g/glibc-2.34-7.fc35.x86_64.rpm"
195+ )
196+ RPM_PATH = pathlib .Path ("/tmp/glibc.rpm" )
197+ WORKDIR = pathlib .Path ("/tmp/glibc-extracted" )
191198
192199
193200def _parse_version (v : str ) -> tuple [int , int ]:
201+ """Turn '2.34' → (2,34) so it can be compared."""
194202 parts = v .split ("." )
195203 return int (parts [0 ]), int (parts [1 ]) if len (parts ) > 1 else 0
196204
197205
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
206-
207-
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 )
217-
218-
219206def _current_glibc_version () -> str :
207+ """Return system glibc version string (via ctypes)."""
220208 try :
221209 libc = ctypes .CDLL ("libc.so.6" )
222210 func = libc .gnu_get_libc_version
@@ -226,68 +214,81 @@ def _current_glibc_version() -> str:
226214 return f"error:{ e } "
227215
228216
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 )
235-
236-
237- def _check_tmp_glibc () -> bool :
238- libc_path = GLIBC_LIBDIR / "libc.so.6"
239- if not libc_path .exists ():
240- logger .error ("[glibc] Expected glibc at %s but file not found" , libc_path )
241- return False
242- try :
243- out = _run_under_custom_loader ([str (libc_path ), "--version" ])
244- first_line = out .decode (errors = "ignore" ).split ("\n " , 1 )[0 ]
245- logger .info ("[glibc] Found custom glibc at %s: %s" , libc_path , first_line )
246- return True
247- except Exception as e :
248- logger .error ("[glibc] Failed to run libc under staged loader: %s" , e )
249- return False
217+ def _resolve_glibc_loader () -> pathlib .Path | None :
218+ """Return staged ld.so path if available."""
219+ for p in [
220+ GLIBC_LIBDIR / f"ld-{ GLIBC_VERSION } .so" ,
221+ GLIBC_LIBDIR / "ld-linux-x86-64.so.2" ,
222+ ]:
223+ if p .exists ():
224+ return p
225+ return None
250226
251227
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
257- try :
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
270- except Exception as e :
271- logger .error ("[QNN] failed to validate staged glibc: %s" , e )
272- return False
228+ def _stage_prebuilt_glibc ():
229+ """Download + extract Fedora 35 glibc RPM into /tmp."""
230+ logger .info (">>> Staging prebuilt glibc-%s from Fedora 35 RPM" , GLIBC_VERSION )
231+ GLIBC_LIBDIR .mkdir (parents = True , exist_ok = True )
232+
233+ # Download
234+ subprocess .check_call (["curl" , "-fsSL" , RPM_URL , "-o" , str (RPM_PATH )])
235+
236+ # Extract
237+ if WORKDIR .exists ():
238+ shutil .rmtree (WORKDIR )
239+ WORKDIR .mkdir (parents = True )
240+ subprocess .check_call (["bsdtar" , "-C" , str (WORKDIR ), "-xf" , str (RPM_PATH )])
241+
242+ # Copy runtime libs
243+ staged = [
244+ "ld-linux-x86-64.so.2" ,
245+ "libc.so.6" ,
246+ "libdl.so.2" ,
247+ "libpthread.so.0" ,
248+ "librt.so.1" ,
249+ "libm.so.6" ,
250+ "libutil.so.1" ,
251+ ]
252+ for lib in staged :
253+ src = WORKDIR / "lib64" / lib
254+ if src .exists ():
255+ shutil .copy2 (src , GLIBC_LIBDIR / lib )
256+ logger .info ("[glibc] Staged %s" , lib )
257+ else :
258+ logger .warning ("[glibc] Missing %s in RPM" , lib )
273259
274260
275- def _ensure_glibc_minimum (min_version : str = GLIBC_VERSION ):
261+ def ensure_glibc_minimum (min_version : str = GLIBC_VERSION ):
262+ """
263+ Ensure process runs under glibc >= min_version.
264+ - If system glibc is new enough → skip.
265+ - Else → stage Fedora RPM and re-exec under staged loader.
266+ """
276267 current = _current_glibc_version ()
277- logger .info ("[glibc] Current loaded glibc (via ctypes) : %s" , current )
268+ logger .info ("[glibc] Current loaded glibc: %s" , current )
278269
270+ # If system glibc already sufficient → skip everything
271+ m = re .match (r"(\d+\.\d+)" , current )
272+ if m and _parse_version (m .group (1 )) >= _parse_version (min_version ):
273+ logger .info ("[glibc] System glibc >= %s, no staging needed." , min_version )
274+ return
275+
276+ # Avoid infinite loop
279277 if os .environ .get (GLIBC_REEXEC_GUARD ) == "1" :
280- logger .info ("[glibc] Already re-exec'd once; continuing under current loader." )
281- _log_current_loader ()
278+ logger .info ("[glibc] Already re-exec'd once, continuing." )
282279 return
283280
281+ # Stage prebuilt if not already staged
282+ if not (GLIBC_LIBDIR / "libc.so.6" ).exists ():
283+ _stage_prebuilt_glibc ()
284+
284285 loader = _resolve_glibc_loader ()
285286 if not loader :
286287 logger .error ("[glibc] Loader not found in %s" , GLIBC_LIBDIR )
287288 return
288289
289290 logger .info (
290- "[glibc] Forcing re-exec under loader %s with libdir %s" , loader , GLIBC_LIBDIR
291+ "[glibc] Re-execing under loader %s with libdir %s" , loader , GLIBC_LIBDIR
291292 )
292293 os .environ [GLIBC_REEXEC_GUARD ] = "1"
293294 os .execv (
0 commit comments