From 7d50fe14b8c98c3714f0c593d268e0c1409f71a1 Mon Sep 17 00:00:00 2001 From: qbisi Date: Sun, 14 Sep 2025 09:40:33 +0800 Subject: [PATCH 1/3] makeWrapper: delete unused option --resolve-argv0 Partially reverts https://github.com/NixOS/nixpkgs/pull/297628. The --resolve-argv0 option in makeWrapper does nothing, and no packages use it. --- doc/stdenv/stdenv.chapter.md | 3 ++- pkgs/build-support/setup-hooks/make-wrapper.sh | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 24536c35b2c3f..96ddee90548da 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -1279,7 +1279,8 @@ someVar=$(stripHash $name) ### `wrapProgram` \ \ {#fun-wrapProgram} -Convenience function for `makeWrapper` that replaces `` with a wrapper that executes the original program. It takes all the same arguments as `makeWrapper`, except for `--inherit-argv0` (used by the `makeBinaryWrapper` implementation) and `--argv0` (used by both `makeWrapper` and `makeBinaryWrapper` wrapper implementations). +Convenience function for `makeWrapper` that replaces `` with a wrapper that executes the original program. It takes all the same arguments as `makeWrapper`, except for `--inherit-argv0` (used by the `makeBinaryWrapper` implementation), `--resolve-argv0` +(also used by `makeBinaryWrapper`), and `--argv0` (used by both `makeWrapper` and `makeBinaryWrapper` wrapper implementations). If you will apply it multiple times, it will overwrite the wrapper file and you will end up with double wrapping, which should be avoided. diff --git a/pkgs/build-support/setup-hooks/make-wrapper.sh b/pkgs/build-support/setup-hooks/make-wrapper.sh index 0fb5aac50a7ac..52d711bee70f9 100644 --- a/pkgs/build-support/setup-hooks/make-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-wrapper.sh @@ -15,7 +15,6 @@ assertExecutable() { # (if unset or empty, defaults to EXECUTABLE) # --inherit-argv0 : the executable inherits argv0 from the wrapper. # (use instead of --argv0 '$0') -# --resolve-argv0 : if argv0 doesn't include a / character, resolve it against PATH # --set VAR VAL : add VAR with value VAL to the executable's environment # --set-default VAR VAL : like --set, but only adds VAR if not already set in # the environment @@ -188,9 +187,6 @@ makeShellWrapper() { elif [[ "$p" == "--inherit-argv0" ]]; then # Whichever comes last of --argv0 and --inherit-argv0 wins argv0='$0' - elif [[ "$p" == "--resolve-argv0" ]]; then - # this is noop in shell wrappers, since bash will always resolve $0 - resolve_argv0=1 else die "makeWrapper doesn't understand the arg $p" fi From 0b17d472fe769a61b7d59674af9ab9cd3771ce91 Mon Sep 17 00:00:00 2001 From: qbisi Date: Sun, 14 Sep 2025 08:31:02 +0800 Subject: [PATCH 2/3] makeBinaryWrapper: adjust --resolve-argv0 option The --resolve-argv0 option was originally introduced in https://github.com/NixOS/nixpkgs/pull/297628 for wrapping Python executables. No other packages currently use it. This commit adjusts the behavior of --resolve-argv0: it now also resolves the dirname of argv0 to its realpath. This ensures that python venvs always resolve sys.base_prefix to the Nix store path (e.g., /nix/store/xxx-python3-env), regardless of how the Nix python environment's python is invoked. --- .../makeBinaryWrapper/make-binary-wrapper.sh | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh b/pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh index c860048d10a28..2c10007fd9b8e 100644 --- a/pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh +++ b/pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh @@ -17,9 +17,10 @@ assertExecutable() { # ARGS: # --argv0 NAME : set the name of the executed process to NAME # (if unset or empty, defaults to EXECUTABLE) -# --inherit-argv0 : the executable inherits argv0 from the wrapper. +# --inherit-argv0 : the executable inherits argv0 from the wrapper # (use instead of --argv0 '$0') -# --resolve-argv0 : if argv0 doesn't include a / character, resolve it against PATH +# --resolve-argv0 : if argv0 doesn't include a / character, resolve it against PATH; then +# always replace its directory with the canonical real path # --set VAR VAL : add VAR with value VAL to the executable's environment # --set-default VAR VAL : like --set, but only adds VAR if not already set in # the environment @@ -189,6 +190,9 @@ makeCWrapper() { # this gets processed after other argv0 flags uses_stdio=1 uses_string=1 + uses_libgen=1 + uses_limits=1 + uses_unistd=1 resolve_argv0=1 ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message @@ -207,6 +211,9 @@ makeCWrapper() { [ -z "$uses_assert" ] || printf '%s\n' "#include " [ -z "$uses_stdio" ] || printf '%s\n' "#include " [ -z "$uses_string" ] || printf '%s\n' "#include " + [ -z "$uses_libgen" ] || printf '%s\n' "#include " + [ -z "$uses_limits" ] || printf '%s\n' "#include " + [ -z "$uses_unistd" ] || printf '%s\n' "#include " [ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)" [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" @@ -352,35 +359,64 @@ void set_env_suffix(char *env, char *sep, char *suffix) { resolveArgv0Fn() { printf '%s' "\ +char *canonicalize_path(char *path) +{ + char *tmp1 = strdup(path); + char *tmp2 = strdup(path); + if (tmp1 == NULL || tmp2 == NULL) { + free(tmp1); + free(tmp2); + return path; + } + + char *base = basename(tmp1); + char *dir = dirname(tmp2); + + char realdir[PATH_MAX]; + const char *dir_final = realpath(dir, realdir) ? realdir : dir; + + char *res = malloc(strlen(dir_final) + strlen(base) + 2); + if (res == NULL) { + free(tmp1); + free(tmp2); + return path; + } + sprintf(res, \"%s/%s\", dir_final, base); + + free(tmp1); + free(tmp2); + return res; +} + char *resolve_argv0(char *argv0) { if (strchr(argv0, '/') != NULL) { - return argv0; + return canonicalize_path(argv0); } char *path = getenv(\"PATH\"); if (path == NULL) { - return argv0; + return canonicalize_path(argv0); } char *path_copy = strdup(path); if (path_copy == NULL) { - return argv0; + return canonicalize_path(argv0); } char *dir = strtok(path_copy, \":\"); while (dir != NULL) { char *candidate = malloc(strlen(dir) + strlen(argv0) + 2); if (candidate == NULL) { free(path_copy); - return argv0; + return canonicalize_path(argv0); } sprintf(candidate, \"%s/%s\", dir, argv0); if (access(candidate, X_OK) == 0) { free(path_copy); - return candidate; + return canonicalize_path(candidate); } free(candidate); dir = strtok(NULL, \":\"); } free(path_copy); - return argv0; + return canonicalize_path(argv0); } " } From bef0564b5308fc4bdbec09f21c2ab050d47bf64c Mon Sep 17 00:00:00 2001 From: qbisi Date: Fri, 3 Oct 2025 12:33:34 +0800 Subject: [PATCH 3/3] python: fix venv creation --- .../interpreters/python/wrapper.nix | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/pkgs/development/interpreters/python/wrapper.nix b/pkgs/development/interpreters/python/wrapper.nix index 6b6f97b74f3dd..914e4b354c49a 100644 --- a/pkgs/development/interpreters/python/wrapper.nix +++ b/pkgs/development/interpreters/python/wrapper.nix @@ -2,6 +2,7 @@ lib, stdenv, buildEnv, + runCommand, makeBinaryWrapper, # manually pased @@ -22,7 +23,11 @@ let env = let - paths = requiredPythonModules (extraLibs ++ [ python ]); + paths = requiredPythonModules (extraLibs ++ [ python ]) ++ [ + (runCommand "bin" { } '' + mkdir -p $out/bin + '') + ]; pythonPath = "${placeholder "out"}/${python.sitePackages}"; pythonExecutable = "${placeholder "out"}/bin/${python.executable}"; in @@ -36,21 +41,27 @@ let nativeBuildInputs = [ makeBinaryWrapper ]; postBuild = '' - if [ -L "$out/bin" ]; then - unlink "$out/bin" - fi - mkdir -p "$out/bin" - for path in ${lib.concatStringsSep " " paths}; do if [ -d "$path/bin" ]; then cd "$path/bin" for prg in *; do - if [ -f "$prg" ]; then + if [ -f "$prg" ] && [ -x "$prg" ]; then rm -f "$out/bin/$prg" - if [ -x "$prg" ]; then - makeWrapper "$path/bin/$prg" "$out/bin/$prg" --set NIX_PYTHONPREFIX "$out" --set NIX_PYTHONEXECUTABLE ${pythonExecutable} --set NIX_PYTHONPATH ${pythonPath} ${ - lib.optionalString (!permitUserSite) ''--set PYTHONNOUSERSITE "true"'' - } ${lib.concatStringsSep " " makeWrapperArgs} + if [ "$prg" = "${python.executable}" ]; then + makeWrapper "${python.interpreter}" "$out/bin/$prg" \ + --inherit-argv0 \ + --resolve-argv0 \ + ${lib.optionalString (!permitUserSite) ''--set PYTHONNOUSERSITE "true"''} \ + ${lib.concatStringsSep " " makeWrapperArgs} + elif [ "$(readlink "$prg")" = "${python.executable}" ]; then + ln -s "${python.executable}" "$out/bin/$prg" + else + makeWrapper "$path/bin/$prg" "$out/bin/$prg" \ + --set NIX_PYTHONPREFIX "$out" \ + --set NIX_PYTHONEXECUTABLE ${pythonExecutable} \ + --set NIX_PYTHONPATH ${pythonPath} \ + ${lib.optionalString (!permitUserSite) ''--set PYTHONNOUSERSITE "true"''} \ + ${lib.concatStringsSep " " makeWrapperArgs} fi fi done