pkgsrc-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

www/py-mod_wsgi: workaround for failing library path detection



Hi,

an annoying "feature" of embedded python is that in order to derive the
base path to find its libraries, it searches for an executable named
"python".

pkgsrc does not provide a "python" executable (or symlink), only the
versioned ones like "python2.7".

On Ubuntu 14.04, the base system has a "python" executable at
/usr/bin/python, at version 2.7.5.

The embedded python in wsgi from pkgsrc therefore does not find the
pkgsrc libraries, resulting in an endless startup loop spewing messages
like

    Traceback (most recent call last):
      File "/usr/lib/python2.7/site.py", line 563, in <module>
        main()
      File "/usr/lib/python2.7/site.py", line 545, in main
        known_paths = addusersitepackages(known_paths)
      File "/usr/lib/python2.7/site.py", line 272, in addusersitepackages
        user_site = getusersitepackages()
      File "/usr/lib/python2.7/site.py", line 247, in getusersitepackages
        user_base = getuserbase() # this will also set USER_BASE
      File "/usr/lib/python2.7/site.py", line 237, in getuserbase
        USER_BASE = get_config_var('userbase')
      File "/usr/lib/python2.7/sysconfig.py", line 578, in get_config_var
        return get_config_vars().get(name)
      File "/usr/lib/python2.7/sysconfig.py", line 524, in get_config_vars
        _init_posix(_CONFIG_VARS)
      File "/usr/lib/python2.7/sysconfig.py", line 408, in _init_posix
        from _sysconfigdata import build_time_vars
      File "/usr/lib/python2.7/_sysconfigdata.py", line 6, in <module>
        from _sysconfigdata_nd import *
    ImportError: No module named _sysconfigdata_nd

in the apache error log.


Attached is a fix that derives the python executable path at compile
time (in setup.py) and the wsgi module then sets that path at runtime
before the python interpreter is initialized.


Regards
Matthias Ferdinand
$NetBSD$

--- setup.py.orig	2015-05-21 11:25:36.000000000 +0000
+++ setup.py
@@ -215,6 +215,12 @@ EXTRA_INCLUDES = get_apxs_config('EXTRA_
 EXTRA_CPPFLAGS = get_apxs_config('EXTRA_CPPFLAGS').split()
 EXTRA_CFLAGS = get_apxs_config('EXTRA_CFLAGS').split()
 
+# try to define the path to the python executable, to avoid collisions
+PYTHON_EXE = sys.executable
+if PYTHON_EXE != 'None' and PYTHON_EXE != '':
+    EXTRA_CFLAGS.append('-DPYTHON_EXE="' + PYTHON_EXE + '"')
+
+
 # Write out apxs_config.py which caches various configuration related to
 # Apache. For the case of using our own Apache build, this needs to
 # calculate values dynamically based on where binaries were installed.
$NetBSD$

--- src/server/wsgi_interp.c.orig	2015-06-01 06:40:08.000000000 +0000
+++ src/server/wsgi_interp.c
@@ -2249,6 +2249,51 @@ void wsgi_python_init(apr_pool_t *p)
         _wputenv(L"PYTHONIOENCODING=cp1252:backslashreplace");
 #endif
 
+        /* If ProgramName is not set, Py_Initialize will search $PATH
+         * for a "python" executable (usually a symlink to the versioned
+         * binary name) that fits its own version and derives the
+         * library search paths to use from this location.
+         *
+         *
+         * Note: this executable is not actually executed, it is only
+         * the location of the binary that is used.
+         *
+         * https://docs.python.org/2/c-api/init.html#c.Py_SetProgramName
+         * ------------------------------------------------------------
+         * void Py_SetProgramName(char *name)
+         *     This function should be called before Py_Initialize() is
+         *     called for the first time, if it is called at all. It
+         *     tells the interpreter the value of the argv[0] argument
+         *     to the main() function of the program. This is used by
+         *     Py_GetPath() and some other functions below to find the
+         *     Python run-time libraries relative to the interpreter
+         *     executable. The default value is 'python'. The argument
+         *     should point to a zero-terminated character string in
+         *     static storage whose contents will not change for the
+         *     duration of the program's execution. No code in the
+         *     Python interpreter will change the contents of this
+         *     storage.
+         * ------------------------------------------------------------
+         *
+         * pkgsrc python packages do not provide a "python" symlink,
+         * just the versioned binary name, e.g. "python2.7".
+         * The embedded python interpreter in WSGI might find a
+         * "python" executable at other places in $PATH, even of the
+         * correct version but with different libraries (i.e. some might
+         * be missing). WSGI then will fail to properly initialize,
+         * rendering all of apache unusable.
+         *
+         * https://groups.google.com/forum/?_escaped_fragment_=topic/modwsgi/Rmgj8IcHC18#!topic/modwsgi/Rmgj8IcHC18
+         * states that Py_SetProgramName does not work on OSX or Windows
+         */
+#define stringify_literal( x ) # x
+#if defined(PYTHON_EXE) && !defined(WIN32)
+        Py_SetProgramName(stringify_literal(PYTHON_EXE));
+        ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
+                     "mod_wsgi (pid=%d): Py_SetProgramName(%s)", getpid(), stringify_literal(PYTHON_EXE));
+#endif
+
+
         /* Initialise Python. */
 
         ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,


Home | Main Index | Thread Index | Old Index