···19# (if unset or empty, defaults to EXECUTABLE)
20# --inherit-argv0 : the executable inherits argv0 from the wrapper.
21# (use instead of --argv0 '$0')
022# --set VAR VAL : add VAR with value VAL to the executable's environment
23# --set-default VAR VAL : like --set, but only adds VAR if not already set in
24# the environment
···87makeCWrapper() {
88 local argv0 inherit_argv0 n params cmd main flagsBefore flagsAfter flags executable length
89 local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf
090 executable=$(escapeStringLiteral "$1")
91 params=("$@")
92 length=${#params[*]}
···169 # Whichever comes last of --argv0 and --inherit-argv0 wins
170 inherit_argv0=1
171 ;;
000000172 *) # Using an error macro, we will make sure the compiler gives an understandable error message
173 main="$main#error makeCWrapper: Unknown argument ${p}"$'\n'
174 ;;
···176 done
177 [[ -z "$flagsBefore" && -z "$flagsAfter" ]] || main="$main"${main:+$'\n'}$(addFlags "$flagsBefore" "$flagsAfter")$'\n'$'\n'
178 [ -z "$inherit_argv0" ] && main="${main}argv[0] = \"${argv0:-${executable}}\";"$'\n'
0179 main="${main}return execv(\"${executable}\", argv);"$'\n'
180181 [ -z "$uses_asprintf" ] || printf '%s\n' "#define _GNU_SOURCE /* See feature_test_macros(7) */"
···183 printf '%s\n' "#include <stdlib.h>"
184 [ -z "$uses_assert" ] || printf '%s\n' "#include <assert.h>"
185 [ -z "$uses_stdio" ] || printf '%s\n' "#include <stdio.h>"
0186 [ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)"
187 [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)"
188 [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)"
0189 printf '\n%s' "int main(int argc, char **argv) {"
190 printf '\n%s' "$(indent4 "$main")"
191 printf '\n%s\n' "}"
···334 } else {
335 assert_success(setenv(env, suffix, 1));
336 }
00000000000000000000000000000000000337}
338"
339}
···19# (if unset or empty, defaults to EXECUTABLE)
20# --inherit-argv0 : the executable inherits argv0 from the wrapper.
21# (use instead of --argv0 '$0')
22+# --resolve-argv0 : if argv0 doesn't include a / character, resolve it against PATH
23# --set VAR VAL : add VAR with value VAL to the executable's environment
24# --set-default VAR VAL : like --set, but only adds VAR if not already set in
25# the environment
···88makeCWrapper() {
89 local argv0 inherit_argv0 n params cmd main flagsBefore flagsAfter flags executable length
90 local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf
91+ local resolve_path
92 executable=$(escapeStringLiteral "$1")
93 params=("$@")
94 length=${#params[*]}
···171 # Whichever comes last of --argv0 and --inherit-argv0 wins
172 inherit_argv0=1
173 ;;
174+ --resolve-argv0)
175+ # this gets processed after other argv0 flags
176+ uses_stdio=1
177+ uses_string=1
178+ resolve_argv0=1
179+ ;;
180 *) # Using an error macro, we will make sure the compiler gives an understandable error message
181 main="$main#error makeCWrapper: Unknown argument ${p}"$'\n'
182 ;;
···184 done
185 [[ -z "$flagsBefore" && -z "$flagsAfter" ]] || main="$main"${main:+$'\n'}$(addFlags "$flagsBefore" "$flagsAfter")$'\n'$'\n'
186 [ -z "$inherit_argv0" ] && main="${main}argv[0] = \"${argv0:-${executable}}\";"$'\n'
187+ [ -z "$resolve_argv0" ] || main="${main}argv[0] = resolve_argv0(argv[0]);"$'\n'
188 main="${main}return execv(\"${executable}\", argv);"$'\n'
189190 [ -z "$uses_asprintf" ] || printf '%s\n' "#define _GNU_SOURCE /* See feature_test_macros(7) */"
···192 printf '%s\n' "#include <stdlib.h>"
193 [ -z "$uses_assert" ] || printf '%s\n' "#include <assert.h>"
194 [ -z "$uses_stdio" ] || printf '%s\n' "#include <stdio.h>"
195+ [ -z "$uses_string" ] || printf '%s\n' "#include <string.h>"
196 [ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)"
197 [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)"
198 [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)"
199+ [ -z "$resolve_argv0" ] || printf '\n%s\n' "$(resolveArgv0Fn)"
200 printf '\n%s' "int main(int argc, char **argv) {"
201 printf '\n%s' "$(indent4 "$main")"
202 printf '\n%s\n' "}"
···345 } else {
346 assert_success(setenv(env, suffix, 1));
347 }
348+}
349+"
350+}
351+352+resolveArgv0Fn() {
353+ printf '%s' "\
354+char *resolve_argv0(char *argv0) {
355+ if (strchr(argv0, '/') != NULL) {
356+ return argv0;
357+ }
358+ char *path = getenv(\"PATH\");
359+ if (path == NULL) {
360+ return argv0;
361+ }
362+ char *path_copy = strdup(path);
363+ if (path_copy == NULL) {
364+ return argv0;
365+ }
366+ char *dir = strtok(path_copy, \":\");
367+ while (dir != NULL) {
368+ char *candidate = malloc(strlen(dir) + strlen(argv0) + 2);
369+ if (candidate == NULL) {
370+ free(path_copy);
371+ return argv0;
372+ }
373+ sprintf(candidate, \"%s/%s\", dir, argv0);
374+ if (access(candidate, X_OK) == 0) {
375+ free(path_copy);
376+ return candidate;
377+ }
378+ free(candidate);
379+ dir = strtok(NULL, \":\");
380+ }
381+ free(path_copy);
382+ return argv0;
383}
384"
385}
+4
pkgs/build-support/setup-hooks/make-wrapper.sh
···15# (if unset or empty, defaults to EXECUTABLE)
16# --inherit-argv0 : the executable inherits argv0 from the wrapper.
17# (use instead of --argv0 '$0')
018# --set VAR VAL : add VAR with value VAL to the executable's environment
19# --set-default VAR VAL : like --set, but only adds VAR if not already set in
20# the environment
···177 elif [[ "$p" == "--inherit-argv0" ]]; then
178 # Whichever comes last of --argv0 and --inherit-argv0 wins
179 argv0='$0'
000180 else
181 die "makeWrapper doesn't understand the arg $p"
182 fi
···15# (if unset or empty, defaults to EXECUTABLE)
16# --inherit-argv0 : the executable inherits argv0 from the wrapper.
17# (use instead of --argv0 '$0')
18+# --resolve-argv0 : if argv0 doesn't include a / character, resolve it against PATH
19# --set VAR VAL : add VAR with value VAL to the executable's environment
20# --set-default VAR VAL : like --set, but only adds VAR if not already set in
21# the environment
···178 elif [[ "$p" == "--inherit-argv0" ]]; then
179 # Whichever comes last of --argv0 and --inherit-argv0 wins
180 argv0='$0'
181+ elif [[ "$p" == "--resolve-argv0" ]]; then
182+ # this is noop in shell wrappers, since bash will always resolve $0
183+ resolve_argv0=1
184 else
185 die "makeWrapper doesn't understand the arg $p"
186 fi
···1-"""
2-This is a Nix-specific module for discovering modules built with Nix.
3-4-The module recursively adds paths that are on `NIX_PYTHONPATH` to `sys.path`. In
5-order to process possible `.pth` files `site.addsitedir` is used.
6-7-The paths listed in `PYTHONPATH` are added to `sys.path` afterwards, but they
8-will be added before the entries we add here and thus take precedence.
9-10-Note the `NIX_PYTHONPATH` environment variable is unset in order to prevent leakage.
11-12-Similarly, this module listens to the environment variable `NIX_PYTHONEXECUTABLE`
13-and sets `sys.executable` to its value.
14-"""
15-import site
16-import sys
17-import os
18-import functools
19-20-paths = os.environ.pop('NIX_PYTHONPATH', None)
21-if paths:
22- functools.reduce(lambda k, p: site.addsitedir(p, k), paths.split(':'), site._init_pathinfo())
23-24-# Check whether we are in a venv or virtualenv.
25-# For Python 3 we check whether our `base_prefix` is different from our current `prefix`.
26-# For Python 2 we check whether the non-standard `real_prefix` is set.
27-# https://stackoverflow.com/questions/1871549/determine-if-python-is-running-inside-virtualenv
28-in_venv = (sys.version_info.major == 3 and sys.prefix != sys.base_prefix) or (sys.version_info.major == 2 and hasattr(sys, "real_prefix"))
29-30-if not in_venv:
31- executable = os.environ.pop('NIX_PYTHONEXECUTABLE', None)
32- prefix = os.environ.pop('NIX_PYTHONPREFIX', None)
33-34- if 'PYTHONEXECUTABLE' not in os.environ and executable is not None:
35- sys.executable = executable
36- if prefix is not None:
37- # Sysconfig does not like it when sys.prefix is set to None
38- sys.prefix = sys.exec_prefix = prefix
39- site.PREFIXES.insert(0, prefix)
···3839 @unittest.skipIf(IS_PYPY or sys.version_info.major==2, "Python 2 does not have base_prefix")
40 def test_base_prefix(self):
41- if IS_VENV or IS_NIXENV or IS_VIRTUALENV:
42 self.assertNotEqual(sys.prefix, sys.base_prefix)
43 else:
44 self.assertEqual(sys.prefix, sys.base_prefix)
···3839 @unittest.skipIf(IS_PYPY or sys.version_info.major==2, "Python 2 does not have base_prefix")
40 def test_base_prefix(self):
41+ if IS_VENV or IS_VIRTUALENV:
42 self.assertNotEqual(sys.prefix, sys.base_prefix)
43 else:
44 self.assertEqual(sys.prefix, sys.base_prefix)
+9-1
pkgs/development/interpreters/python/wrapper.nix
···35 fi
36 mkdir -p "$out/bin"
370038 for path in ${lib.concatStringsSep " " paths}; do
39 if [ -d "$path/bin" ]; then
40 cd "$path/bin"
···42 if [ -f "$prg" ]; then
43 rm -f "$out/bin/$prg"
44 if [ -x "$prg" ]; then
45- 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}
00000046 fi
47 fi
48 done
···35 fi
36 mkdir -p "$out/bin"
3738+ rm -f $out/bin/.*-wrapped
39+40 for path in ${lib.concatStringsSep " " paths}; do
41 if [ -d "$path/bin" ]; then
42 cd "$path/bin"
···44 if [ -f "$prg" ]; then
45 rm -f "$out/bin/$prg"
46 if [ -x "$prg" ]; then
47+ if [ -f ".$prg-wrapped" ]; then
48+ echo "#!${pythonExecutable}" > "$out/bin/$prg"
49+ sed -e '1d' -e '3d' ".$prg-wrapped" >> "$out/bin/$prg"
50+ chmod +x "$out/bin/$prg"
51+ else
52+ makeWrapper "$path/bin/$prg" "$out/bin/$prg" --inherit-argv0 --resolve-argv0 ${lib.optionalString (!permitUserSite) ''--set PYTHONNOUSERSITE "true"''} ${lib.concatStringsSep " " makeWrapperArgs}
53+ fi
54 fi
55 fi
56 done