autoPatchelfHook: add keep_libc flag (#332617)

* autoPatchelfHook: add keep_libc flag

- Add keep_libc flag to disable the default libc handling. Intended
to be used by systemd.
- Add autoPatchelfFlags to autoPatchelfHook for passing arguments to
the autoPatchelf script

This reverts part of the change made in #307068 / 80be926.

Fixes #332533

authored by squalus and committed by GitHub 0a3ed67f 1582d762

+29 -6
+24 -6
pkgs/build-support/setup-hooks/auto-patchelf.py
··· 197 found: bool = False # Whether it was found somewhere 198 199 200 - def auto_patchelf_file(path: Path, runtime_deps: list[Path], append_rpaths: list[Path] = [], extra_args: list[str] = []) -> list[Dependency]: 201 try: 202 with open_elf(path) as elf: 203 ··· 257 # 1. If a candidate is an absolute path, it is already a 258 # valid dependency if that path exists, and nothing needs 259 # to be done. It should be an error if that path does not exist. 260 - # 2. If a candidate is found in our library dependencies, that 261 # dependency should be added to rpath. 262 - # 3. If a candidate is found in libc, it will be correctly 263 - # resolved by the dynamic linker automatically. 264 # 265 # These conditions are checked in this order, because #2 266 # and #3 may both be true. In that case, we still want to 267 # add the dependency to rpath, as the original binary 268 # presumably had it and this should be preserved. 269 270 if candidate.is_absolute() and candidate.is_file(): 271 was_found = True 272 break 273 elif found_dependency := find_dependency(candidate.name, file_arch, file_osabi): 274 rpath.append(found_dependency) 275 dependencies.append(Dependency(path, candidate, found=True)) 276 print(f" {candidate} -> found: {found_dependency}") 277 was_found = True 278 break 279 - elif (libc_lib / candidate).is_file(): 280 was_found = True 281 break 282 ··· 306 recursive: bool = True, 307 ignore_missing: list[str] = [], 308 append_rpaths: list[Path] = [], 309 extra_args: list[str] = []) -> None: 310 311 if not paths_to_patch: ··· 319 dependencies = [] 320 for path in chain.from_iterable(glob(p, '*', recursive) for p in paths_to_patch): 321 if not path.is_symlink() and path.is_file(): 322 - dependencies += auto_patchelf_file(path, runtime_deps, append_rpaths, extra_args) 323 324 missing = [dep for dep in dependencies if not dep.found] 325 ··· 378 help="Paths to append to all runtime paths unconditionally", 379 ) 380 parser.add_argument( 381 "--extra-args", 382 # Undocumented Python argparse feature: consume all remaining arguments 383 # as values for this one. This means this argument should always be passed ··· 398 args.recursive, 399 args.ignore_missing, 400 append_rpaths=args.append_rpaths, 401 extra_args=args.extra_args) 402 403
··· 197 found: bool = False # Whether it was found somewhere 198 199 200 + def auto_patchelf_file(path: Path, runtime_deps: list[Path], append_rpaths: list[Path] = [], keep_libc: bool = False, extra_args: list[str] = []) -> list[Dependency]: 201 try: 202 with open_elf(path) as elf: 203 ··· 257 # 1. If a candidate is an absolute path, it is already a 258 # valid dependency if that path exists, and nothing needs 259 # to be done. It should be an error if that path does not exist. 260 + # 2. If a candidate is found within libc, it should be dropped 261 + # and resolved automatically by the dynamic linker, unless 262 + # keep_libc is enabled. 263 + # 3. If a candidate is found in our library dependencies, that 264 # dependency should be added to rpath. 265 + # 4. If all of the above fail, libc dependencies should still be 266 + # considered found. This is in contrast to step 2, because 267 + # enabling keep_libc should allow libc to be found in step 3 268 + # if possible to preserve its presence in rpath. 269 # 270 # These conditions are checked in this order, because #2 271 # and #3 may both be true. In that case, we still want to 272 # add the dependency to rpath, as the original binary 273 # presumably had it and this should be preserved. 274 + 275 + is_libc = (libc_lib / candidate).is_file() 276 277 if candidate.is_absolute() and candidate.is_file(): 278 was_found = True 279 break 280 + elif is_libc and not keep_libc: 281 + was_found = True 282 + break 283 elif found_dependency := find_dependency(candidate.name, file_arch, file_osabi): 284 rpath.append(found_dependency) 285 dependencies.append(Dependency(path, candidate, found=True)) 286 print(f" {candidate} -> found: {found_dependency}") 287 was_found = True 288 break 289 + elif is_libc and keep_libc: 290 was_found = True 291 break 292 ··· 316 recursive: bool = True, 317 ignore_missing: list[str] = [], 318 append_rpaths: list[Path] = [], 319 + keep_libc: bool = False, 320 extra_args: list[str] = []) -> None: 321 322 if not paths_to_patch: ··· 330 dependencies = [] 331 for path in chain.from_iterable(glob(p, '*', recursive) for p in paths_to_patch): 332 if not path.is_symlink() and path.is_file(): 333 + dependencies += auto_patchelf_file(path, runtime_deps, append_rpaths, keep_libc, extra_args) 334 335 missing = [dep for dep in dependencies if not dep.found] 336 ··· 389 help="Paths to append to all runtime paths unconditionally", 390 ) 391 parser.add_argument( 392 + "--keep-libc", 393 + dest="keep_libc", 394 + action="store_true", 395 + help="Attempt to search for and relink libc dependencies.", 396 + ) 397 + parser.add_argument( 398 "--extra-args", 399 # Undocumented Python argparse feature: consume all remaining arguments 400 # as values for this one. This means this argument should always be passed ··· 415 args.recursive, 416 args.ignore_missing, 417 append_rpaths=args.append_rpaths, 418 + keep_libc=args.keep_libc, 419 extra_args=args.extra_args) 420 421
+3
pkgs/build-support/setup-hooks/auto-patchelf.sh
··· 58 local appendRunpathsArray=( "${appendRunpaths[@]}" ) 59 local runtimeDependenciesArray=( "${runtimeDependencies[@]}" ) 60 local patchelfFlagsArray=( "${patchelfFlags[@]}" ) 61 else 62 readarray -td' ' ignoreMissingDepsArray < <(echo -n "$autoPatchelfIgnoreMissingDeps") 63 local appendRunpathsArray=($appendRunpaths) 64 local runtimeDependenciesArray=($runtimeDependencies) 65 local patchelfFlagsArray=($patchelfFlags) 66 fi 67 68 # Check if ignoreMissingDepsArray contains "1" and if so, replace it with ··· 85 "${extraAutoPatchelfLibs[@]}" \ 86 --runtime-dependencies "${runtimeDependenciesArray[@]/%//lib}" \ 87 --append-rpaths "${appendRunpathsArray[@]}" \ 88 --extra-args "${patchelfFlagsArray[@]}" 89 } 90
··· 58 local appendRunpathsArray=( "${appendRunpaths[@]}" ) 59 local runtimeDependenciesArray=( "${runtimeDependencies[@]}" ) 60 local patchelfFlagsArray=( "${patchelfFlags[@]}" ) 61 + local autoPatchelfFlagsArray=( "${autoPatchelfFlags[@]}" ) 62 else 63 readarray -td' ' ignoreMissingDepsArray < <(echo -n "$autoPatchelfIgnoreMissingDeps") 64 local appendRunpathsArray=($appendRunpaths) 65 local runtimeDependenciesArray=($runtimeDependencies) 66 local patchelfFlagsArray=($patchelfFlags) 67 + local autoPatchelfFlagsArray=($autoPatchelfFlags) 68 fi 69 70 # Check if ignoreMissingDepsArray contains "1" and if so, replace it with ··· 87 "${extraAutoPatchelfLibs[@]}" \ 88 --runtime-dependencies "${runtimeDependenciesArray[@]/%//lib}" \ 89 --append-rpaths "${appendRunpathsArray[@]}" \ 90 + "${autoPatchelfFlagsArray[@]}" \ 91 --extra-args "${patchelfFlagsArray[@]}" 92 } 93
+2
pkgs/os-specific/linux/systemd/default.nix
··· 336 ] 337 ; 338 339 buildInputs = 340 [ 341 libxcrypt
··· 336 ] 337 ; 338 339 + autoPatchelfFlags = [ "--keep-libc" ]; 340 + 341 buildInputs = 342 [ 343 libxcrypt