(original) (raw)

changeset: 63961:4742e7aea2f5 user: Antoine Pitrou solipsis@pitrou.net date: Fri Aug 13 22:25:01 2010 +0000 files: .bzrignore .hgignore Include/Python.h Lib/site.py Makefile.pre.in Modules/getpath.c Modules/main.c setup.py description: Reimplement addbuilddir() in C inside getpath.c, so as to execute it at interpreter startup before importing any non-builtin modules. Should fix #9589. diff -r 291c9afab12c -r 4742e7aea2f5 .bzrignore --- a/.bzrignore Fri Aug 13 22:23:24 2010 +0000 +++ b/.bzrignore Fri Aug 13 22:25:01 2010 +0000 @@ -11,6 +11,7 @@ build Makefile.pre platform +pybuilddir.txt pyconfig.h libpython*.a python.exe diff -r 291c9afab12c -r 4742e7aea2f5 .hgignore --- a/.hgignore Fri Aug 13 22:23:24 2010 +0000 +++ b/.hgignore Fri Aug 13 22:25:01 2010 +0000 @@ -32,6 +32,7 @@ Parser/pgen$ ^core ^python-gdb.py +^pybuilddir.txt syntax: glob libpython*.a diff -r 291c9afab12c -r 4742e7aea2f5 Include/Python.h --- a/Include/Python.h Fri Aug 13 22:23:24 2010 +0000 +++ b/Include/Python.h Fri Aug 13 22:25:01 2010 +0000 @@ -129,8 +129,9 @@ /* _Py_Mangle is defined in compile.c */ PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name); -/* _Py_char2wchar lives in main.c */ +/* These functions live in main.c */ PyAPI_FUNC(wchar_t *) _Py_char2wchar(char *); +PyAPI_FUNC(FILE *) _Py_wfopen(const wchar_t *path, const wchar_t *mode); #ifdef __cplusplus } #endif diff -r 291c9afab12c -r 4742e7aea2f5 Lib/site.py --- a/Lib/site.py Fri Aug 13 22:23:24 2010 +0000 +++ b/Lib/site.py Fri Aug 13 22:25:01 2010 +0000 @@ -107,18 +107,6 @@ sys.path[:] = L return known_paths -# XXX This should not be part of site.py, since it is needed even when -# using the -S option for Python. See http://www.python.org/sf/586680 -def addbuilddir(): - """Append ./build/lib. in case we're running in the build dir - (especially for Guido :-)""" - from sysconfig import get_platform - s = "build/lib.%s-%.3s" % (get_platform(), sys.version) - if hasattr(sys, 'gettotalrefcount'): - s += '-pydebug' - s = os.path.join(os.path.dirname(sys.path.pop()), s) - sys.path.append(s) - def _init_pathinfo(): """Return a set containing all existing directory entries from sys.path""" @@ -529,9 +517,6 @@ abs_paths() known_paths = removeduppaths() - if (os.name == "posix" and sys.path and - os.path.basename(sys.path[-1]) == "Modules"): - addbuilddir() if ENABLE_USER_SITE is None: ENABLE_USER_SITE = check_enableusersite() known_paths = addusersitepackages(known_paths) diff -r 291c9afab12c -r 4742e7aea2f5 Makefile.pre.in --- a/Makefile.pre.in Fri Aug 13 22:23:24 2010 +0000 +++ b/Makefile.pre.in Fri Aug 13 22:25:01 2010 +0000 @@ -1213,6 +1213,7 @@ Modules/Setup Modules/Setup.local Modules/Setup.config \ Misc/python.pc -rm -f python*-gdb.py + -rm -f pybuilddir.txt find $(srcdir) '(' -name '*.fdc' -o -name '*~' \ -o -name '[@,#]*' -o -name '*.old' \ -o -name '*.orig' -o -name '*.rej' \ diff -r 291c9afab12c -r 4742e7aea2f5 Modules/getpath.c --- a/Modules/getpath.c Fri Aug 13 22:23:24 2010 +0000 +++ b/Modules/getpath.c Fri Aug 13 22:25:01 2010 +0000 @@ -394,12 +394,35 @@ return 1; } - /* Check to see if argv[0] is in the build directory */ + /* Check to see if argv[0] is in the build directory. "pybuilddir.txt" + is written by setup.py and contains the relative path to the location + of shared library modules. */ wcscpy(exec_prefix, argv0_path); - joinpath(exec_prefix, L"Modules/Setup"); + joinpath(exec_prefix, L"pybuilddir.txt"); if (isfile(exec_prefix)) { - reduce(exec_prefix); - return -1; + FILE *f = _Py_wfopen(exec_prefix, L"rb"); + if (f == NULL) + errno = 0; + else { + char buf[MAXPATHLEN+1]; + PyObject *decoded; + wchar_t rel_builddir_path[MAXPATHLEN+1]; + size_t n; + n = fread(buf, 1, MAXPATHLEN, f); + buf[n] = '\0'; + fclose(f); + decoded = PyUnicode_DecodeUTF8(buf, n, "surrogateescape"); + if (decoded != NULL) { + n = PyUnicode_AsWideChar(decoded, rel_builddir_path, MAXPATHLEN); + Py_DECREF(decoded); + if (n >= 0) { + rel_builddir_path[n] = L'\0'; + wcscpy(exec_prefix, argv0_path); + joinpath(exec_prefix, rel_builddir_path); + return -1; + } + } + } } /* Search from argv0_path, until root is found */ diff -r 291c9afab12c -r 4742e7aea2f5 Modules/main.c --- a/Modules/main.c Fri Aug 13 22:23:24 2010 +0000 +++ b/Modules/main.c Fri Aug 13 22:25:01 2010 +0000 @@ -101,10 +101,10 @@ PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n\ "; +FILE * +_Py_wfopen(const wchar_t *path, const wchar_t *mode) +{ #ifndef MS_WINDOWS -static FILE* -_wfopen(const wchar_t *path, const wchar_t *mode) -{ char cpath[PATH_MAX]; char cmode[10]; size_t r; @@ -119,8 +119,10 @@ return NULL; } return fopen(cpath, cmode); +#else + return _wfopen(path, mode); +#endif } -#endif static int @@ -640,7 +642,7 @@ } if (sts==-1 && filename!=NULL) { - if ((fp = _wfopen(filename, L"r")) == NULL) { + if ((fp = _Py_wfopen(filename, L"r")) == NULL) { char cfilename[PATH_MAX]; size_t r = wcstombs(cfilename, filename, PATH_MAX); if (r == PATH_MAX) diff -r 291c9afab12c -r 4742e7aea2f5 setup.py --- a/setup.py Fri Aug 13 22:23:24 2010 +0000 +++ b/setup.py Fri Aug 13 22:25:01 2010 +0000 @@ -22,6 +22,10 @@ # This global variable is used to hold the list of modules to be disabled. disabled_module_list = [] +# File which contains the directory for shared mods (for sys.path fixup +# when running from the build dir, see Modules/getpath.c) +_BUILDDIR_COOKIE = "pybuilddir.txt" + def add_dir_to_list(dirlist, dir): """Add the directory 'dir' to the list 'dirlist' (at the front) if 1) 'dir' is not already in 'dirlist' @@ -224,6 +228,16 @@ args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags self.compiler.set_executables(**args) + # Not only do we write the builddir cookie, but we manually install + # the shared modules directory if it isn't already in sys.path. + # Otherwise trying to import the extensions after building them + # will fail. + with open(_BUILDDIR_COOKIE, "wb") as f: + f.write(self.build_lib.encode('utf-8', 'surrogateescape')) + abs_build_lib = os.path.join(os.path.dirname(__file__), self.build_lib) + if abs_build_lib not in sys.path: + sys.path.append(abs_build_lib) + build_ext.build_extensions(self) longest = max([len(e.name) for e in self.extensions])/solipsis@pitrou.net