mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-09-06 05:31:44 +00:00
Merge pull request #639 from xtfxme/as-cpyext-intellisurvey
Support building as a proper [C]Python extension, and/or by distutils [intellisurvey]
This commit is contained in:
@@ -12,3 +12,7 @@
|
||||
/t/ring/target
|
||||
|
||||
core/dot_h.c
|
||||
|
||||
/build/
|
||||
/dist/
|
||||
/uWSGI.egg-info/
|
||||
|
||||
+291
-41
@@ -1,75 +1,325 @@
|
||||
#include "../python/uwsgi_python.h"
|
||||
|
||||
//FIXME: [upstream:python] needs PyAPI_FUNC(void)
|
||||
extern void Py_GetArgcArgv(int *, char ***);
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
extern char **environ;
|
||||
|
||||
PyObject *u_run(PyObject *self, PyObject *args) {
|
||||
static int new_argc = -1;
|
||||
static int orig_argc = -1;
|
||||
static char **new_argv = NULL;
|
||||
static char **orig_argv = NULL;
|
||||
static char *new_argv_buf = NULL;
|
||||
|
||||
char **argv;
|
||||
size_t size = 2;
|
||||
int i;
|
||||
|
||||
if (PyTuple_Size(args) < 1) {
|
||||
return PyErr_Format(PyExc_ValueError, "you have to specify at least one uWSGI option to run() it");
|
||||
}
|
||||
PyObject *
|
||||
pyuwsgi_setup(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
if (new_argv) {
|
||||
PyErr_SetString(
|
||||
PyExc_RuntimeError,
|
||||
"uWSGI already setup"
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *the_arg = PyTuple_GetItem(args, 0);
|
||||
if (uwsgi.mywid) {
|
||||
PyErr_SetString(
|
||||
PyExc_RuntimeError,
|
||||
"uWSGI must be setup by master"
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyList_Check(the_arg)) {
|
||||
size = PyList_Size(the_arg) + 2;
|
||||
}
|
||||
else if (PyTuple_Check(the_arg)) {
|
||||
size = PyTuple_Size(the_arg) + 2;
|
||||
}
|
||||
else if (PyString_Check(the_arg)) {
|
||||
size = 3;
|
||||
}
|
||||
PyObject *iterator;
|
||||
|
||||
argv = uwsgi_malloc(sizeof(char *) * size);
|
||||
memset(argv, 0, sizeof(char *) * size);
|
||||
if (args == NULL || PyObject_Size(args) == 0) {
|
||||
PyObject *argv = PySys_GetObject("argv");
|
||||
if (argv == NULL)
|
||||
return NULL;
|
||||
|
||||
// will be overwritten
|
||||
argv[0] = "uwsgi";
|
||||
// during site.py maybe
|
||||
if (argv == Py_None) {
|
||||
argv = PyTuple_New(0);
|
||||
iterator = PyObject_GetIter(argv);
|
||||
Py_DECREF(argv);
|
||||
}
|
||||
else {
|
||||
iterator = PyObject_GetIter(argv);
|
||||
if (PyObject_Size(argv) > 0) {
|
||||
// forward past argv0
|
||||
PyObject *item = PyIter_Next(iterator);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (
|
||||
PyObject_Size(args) == 1
|
||||
&& !PyString_Check(PyTuple_GetItem(args, 0))
|
||||
) {
|
||||
iterator = PyObject_GetIter(PyTuple_GetItem(args, 0));
|
||||
}
|
||||
else {
|
||||
iterator = PyObject_GetIter(args);
|
||||
}
|
||||
|
||||
if (PyList_Check(the_arg)) {
|
||||
for(i=0;i<PyList_Size(the_arg);i++) {
|
||||
argv[i+1] = PyString_AsString( PyList_GetItem(the_arg, i) );
|
||||
}
|
||||
}
|
||||
else if (PyTuple_Check(the_arg)) {
|
||||
for(i=0;i<PyTuple_Size(the_arg);i++) {
|
||||
argv[i+1] = PyString_AsString( PyTuple_GetItem(the_arg, i) );
|
||||
}
|
||||
}
|
||||
else if (PyString_Check(the_arg)) {
|
||||
argv[1] = PyString_AsString( the_arg );
|
||||
}
|
||||
if (iterator == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi_init(size-1, argv, environ);
|
||||
size_t size = 1;
|
||||
//FIXME: ARGS prior to and including -c/-m are REQUIRED!
|
||||
PyObject *item = PyString_FromString(orig_argv[0]);
|
||||
PyObject *args_li = PyList_New(0);
|
||||
PyList_Append(args_li, item);
|
||||
size += strlen(orig_argv[0]) + 1;
|
||||
Py_DECREF(item);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
while ((item = PyIter_Next(iterator))) {
|
||||
//TODO: call str(...) on everything
|
||||
PyList_Append(args_li, item);
|
||||
size += PyObject_Length(item) + 1;
|
||||
Py_DECREF(item);
|
||||
}
|
||||
|
||||
Py_DECREF(iterator);
|
||||
|
||||
new_argc = PyObject_Length(args_li);
|
||||
new_argv = uwsgi_calloc(sizeof(char *) * (new_argc + 1));
|
||||
new_argv_buf = uwsgi_calloc(size);
|
||||
|
||||
int i = 0;
|
||||
char *new_argv_ptr = new_argv_buf;
|
||||
for(i=0; i < new_argc; i++) {
|
||||
PyObject *arg = PyList_GetItem(args_li, i);
|
||||
char *arg_str = PyString_AsString(arg);
|
||||
new_argv[i] = new_argv_ptr;
|
||||
strcpy(new_argv_ptr, arg_str);
|
||||
new_argv_ptr += strlen(arg_str) + 1;
|
||||
}
|
||||
|
||||
PyObject *args_tup = PyList_AsTuple(args_li);
|
||||
PyObject_SetAttrString(self, "NEW_ARGV", args_tup);
|
||||
Py_DECREF(args_tup);
|
||||
Py_DECREF(args_li);
|
||||
|
||||
// TODO: convention here is a goto methinks?
|
||||
if (PyErr_Occurred()) {
|
||||
free(new_argv_buf);
|
||||
free(new_argv);
|
||||
new_argv = 0;
|
||||
new_argc = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//TODO: ...???
|
||||
// actually do the thing!
|
||||
PyThreadState *_tstate = PyThreadState_Get();
|
||||
uwsgi_setup(orig_argc, orig_argv, environ);
|
||||
PyThreadState_Swap(_tstate);
|
||||
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
pyuwsgi_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
if (pyuwsgi_setup(self, args, kwds) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rc = uwsgi_run();
|
||||
|
||||
// never(?) here
|
||||
return Py_BuildValue("i", rc);
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
pyuwsgi_run(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
// backcompat
|
||||
if (new_argv == NULL &&
|
||||
pyuwsgi_setup(self, args, kwds) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rc = uwsgi_run();
|
||||
|
||||
// never(?) here
|
||||
return Py_BuildValue("i", rc);
|
||||
}
|
||||
|
||||
|
||||
PyMethodDef methods[] = {
|
||||
{"run", u_run, METH_VARARGS, "run the uWSGI server"},
|
||||
{"run",
|
||||
(PyCFunction) pyuwsgi_run,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"run(...)"
|
||||
"\n>>> 0"
|
||||
"\n"
|
||||
"\n * Call setup(...) if not configured"
|
||||
"\n * Begin uWSGI mainloop"
|
||||
"\n NOTE: will not return"
|
||||
"\n"
|
||||
},
|
||||
{"init",
|
||||
(PyCFunction) pyuwsgi_init,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"init(...)"
|
||||
"\n>>> 0"
|
||||
"\n"
|
||||
"\n * Call setup(...)"
|
||||
"\n * Begin uWSGI mainloop"
|
||||
"\n NOTE: will not return"
|
||||
"\n"
|
||||
},
|
||||
{"setup",
|
||||
(PyCFunction) pyuwsgi_setup,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"setup('--master', ...)"
|
||||
"\n>>> <module 'uwsgi' from \"uwsgi.so\">"
|
||||
"\n"
|
||||
"\n * Initialize uWSGI core with (...)"
|
||||
"\n MUST only call once [RuntimeException]"
|
||||
"\n MUST only call from master [RuntimeException]"
|
||||
"\n"
|
||||
},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
pyuwsgi_set_orig_argv(PyObject *self)
|
||||
{
|
||||
|
||||
// ask python for the original argc/argv saved in Py_Main()
|
||||
Py_GetArgcArgv(&orig_argc, &orig_argv);
|
||||
|
||||
// [re?]export to uwsgi.orig_argv
|
||||
PyObject *m_orig_argv;
|
||||
m_orig_argv = PyTuple_New(orig_argc);
|
||||
|
||||
int i = 0;
|
||||
int i_cm = -1;
|
||||
|
||||
for(i=0; i < orig_argc; i++) {
|
||||
char *arg = orig_argv[i];
|
||||
//XXX: _PyOS_optarg != 0 also indicates python quit early...
|
||||
//FIXME: [upstream:python] orig_argv could be mangled; reset
|
||||
// rel: http://bugs.python.org/issue8202
|
||||
orig_argv[i + 1] = arg + strlen(arg) + 1;
|
||||
|
||||
// look for -c or -m and record the offset
|
||||
if (i_cm < 0) {
|
||||
if (strcmp(arg, "-c") || strcmp(arg, "-m")) {
|
||||
// python's getopt would've failed had + 1 not exist
|
||||
i_cm = i + 1;
|
||||
}
|
||||
else if (!uwsgi_startswith(arg, "-c", 2) ||
|
||||
!uwsgi_startswith(arg, "-m", 2)) {
|
||||
//FIXME: ARGS prior to and including -c/-m are REQUIRED,
|
||||
// but NOT a part of the uWSGI argv! Needed to make
|
||||
// exec*() self-referential: exec*(...) -> uwsgi
|
||||
//
|
||||
// want: uwsgi.binary_argv[:] + uwsgi.argv[:]!
|
||||
// binary_argv = [binary_path] + args
|
||||
i_cm = i;
|
||||
}
|
||||
}
|
||||
|
||||
PyTuple_SetItem(m_orig_argv, i, PyString_FromString(arg));
|
||||
}
|
||||
|
||||
//TODO: howto properly detect uwsgi already running...
|
||||
// orig_argv == uwsgi.orig_argv (?)
|
||||
// ^^^ but if Py_Main not called, python/main.c:orig_argv unset
|
||||
// howto interact/detect things in general
|
||||
PyObject *m_new_argv = PyTuple_New(0);
|
||||
PyObject_SetAttrString(self, "NEW_ARGV", m_new_argv);
|
||||
PyObject_SetAttrString(self, "ORIG_ARGV", m_orig_argv);
|
||||
Py_DECREF(m_new_argv);
|
||||
Py_DECREF(m_orig_argv);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
pyuwsgi_init_as(char *mod_name)
|
||||
{
|
||||
|
||||
PyObject *m;
|
||||
|
||||
m = PyImport_GetModuleDict();
|
||||
if (m == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m = PyDict_GetItemString(m, mod_name);
|
||||
if (!m) {
|
||||
m = Py_InitModule(mod_name, NULL);
|
||||
}
|
||||
|
||||
if (orig_argc < 0) {
|
||||
pyuwsgi_set_orig_argv(m);
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i=0; methods[i].ml_name != NULL; i++) {
|
||||
PyObject *fun = PyObject_GetAttrString(m, methods[i].ml_name);
|
||||
if (fun != NULL) {
|
||||
// already exists
|
||||
Py_DECREF(fun);
|
||||
continue;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
|
||||
// rel: Python/modsupport.c:Py_InitModule4
|
||||
PyObject* name = PyString_FromString(methods[i].ml_name);
|
||||
// fun(self, ...)
|
||||
fun = PyCFunction_NewEx(&methods[i], m, name);
|
||||
Py_DECREF(name);
|
||||
// module.fun
|
||||
PyObject_SetAttrString(m, methods[i].ml_name, fun);
|
||||
Py_DECREF(fun);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initpyuwsgi()
|
||||
{
|
||||
(void) Py_InitModule("pyuwsgi", methods);
|
||||
(void) pyuwsgi_init_as("pyuwsgi");
|
||||
}
|
||||
|
||||
|
||||
int pyuwsgi_init() { return 0; }
|
||||
// allow the module to be called `uwsgi`
|
||||
PyMODINIT_FUNC
|
||||
inituwsgi()
|
||||
{
|
||||
(void) pyuwsgi_init_as("uwsgi");
|
||||
}
|
||||
|
||||
|
||||
void pyuwsgi_load()
|
||||
{
|
||||
if (new_argc > -1) {
|
||||
uwsgi.new_argc = new_argc;
|
||||
uwsgi.new_argv = new_argv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin pyuwsgi_plugin = {
|
||||
|
||||
.name = "pyuwsgi",
|
||||
.init = pyuwsgi_init,
|
||||
.on_load = pyuwsgi_load,
|
||||
};
|
||||
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
# encoding: utf-8
|
||||
|
||||
"""
|
||||
This is a hack allowing you installing
|
||||
uWSGI and uwsgidecorators via pip and easy_install
|
||||
since 1.9.11 it automatically detects pypy
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import errno
|
||||
import shlex
|
||||
import shutil
|
||||
import uwsgiconfig
|
||||
|
||||
from setuptools import setup
|
||||
from setuptools.dist import Distribution
|
||||
from setuptools.command.install import install
|
||||
from setuptools.command.install_lib import install_lib
|
||||
from setuptools.command.build_ext import build_ext
|
||||
from distutils.core import Extension
|
||||
|
||||
|
||||
class uWSGIBuildExt(build_ext):
|
||||
|
||||
UWSGI_NAME = 'uwsgi'
|
||||
UWSGI_PLUGIN = 'pyuwsgi'
|
||||
|
||||
def build_extensions(self):
|
||||
self.uwsgi_setup()
|
||||
#XXX: needs uwsgiconfig fix
|
||||
self.uwsgi_build()
|
||||
if 'UWSGI_USE_DISTUTILS' not in os.environ:
|
||||
#XXX: needs uwsgiconfig fix
|
||||
#uwsgiconfig.build_uwsgi(self.uwsgi_config)
|
||||
return
|
||||
|
||||
else:
|
||||
#XXX: needs uwsgiconfig fix
|
||||
os.unlink(self.uwsgi_config.get('bin_name'))
|
||||
|
||||
#FIXME: else build fails :(
|
||||
for baddie in set(self.compiler.compiler_so) & set((
|
||||
'-Wstrict-prototypes',
|
||||
)):
|
||||
self.compiler.compiler_so.remove(baddie)
|
||||
|
||||
build_ext.build_extensions(self)
|
||||
|
||||
def uwsgi_setup(self):
|
||||
default = (
|
||||
'__pypy__' in sys.builtin_module_names
|
||||
and 'pypy'
|
||||
or 'default'
|
||||
)
|
||||
profile = (
|
||||
os.environ.get('UWSGI_PROFILE')
|
||||
or 'buildconf/%s.ini' % default
|
||||
)
|
||||
|
||||
if not profile.endswith('.ini'):
|
||||
profile = profile + '.ini'
|
||||
if not '/' in profile:
|
||||
profile = 'buildconf/' + profile
|
||||
|
||||
#FIXME: update uwsgiconfig to properly set _EVERYTHING_!
|
||||
config = uwsgiconfig.uConf(profile)
|
||||
# insert in the beginning so UWSGI_PYTHON_NOLIB is exported
|
||||
# before the python plugin compiles
|
||||
ep = config.get('embedded_plugins').split(',')
|
||||
if self.UWSGI_PLUGIN in ep:
|
||||
ep.remove(self.UWSGI_PLUGIN)
|
||||
ep.insert(0, self.UWSGI_PLUGIN)
|
||||
config.set('embedded_plugins', ','.join(ep))
|
||||
config.set('as_shared_library', 'true')
|
||||
config.set('bin_name', self.get_ext_fullpath(self.UWSGI_NAME))
|
||||
try:
|
||||
os.makedirs(os.path.dirname(config.get('bin_name')))
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
self.uwsgi_profile = profile
|
||||
self.uwsgi_config = config
|
||||
|
||||
def uwsgi_build(self):
|
||||
uwsgiconfig.build_uwsgi(self.uwsgi_config)
|
||||
|
||||
#XXX: merge uwsgi_setup (see other comments)
|
||||
for ext in self.extensions:
|
||||
if ext.name == self.UWSGI_NAME:
|
||||
ext.sources = [s + '.c' for s in self.uwsgi_config.gcc_list]
|
||||
ext.library_dirs = self.uwsgi_config.include_path[:]
|
||||
ext.libraries = list()
|
||||
ext.extra_compile_args = list()
|
||||
|
||||
for x in uwsgiconfig.uniq_warnings(
|
||||
self.uwsgi_config.ldflags + self.uwsgi_config.libs,
|
||||
):
|
||||
for y in shlex.split(x):
|
||||
if y.startswith('-l'):
|
||||
ext.libraries.append(y[2:])
|
||||
elif y.startswith('-L'):
|
||||
ext.library_dirs.append(y[2:])
|
||||
|
||||
for x in self.uwsgi_config.cflags:
|
||||
for y in shlex.split(x):
|
||||
if y:
|
||||
ext.extra_compile_args.append(y)
|
||||
|
||||
|
||||
setup(
|
||||
name='uWSGI',
|
||||
license='GPL2',
|
||||
version=uwsgiconfig.uwsgi_version,
|
||||
author='Unbit',
|
||||
author_email='info@unbit.it',
|
||||
description='The uWSGI server',
|
||||
cmdclass={
|
||||
'build_ext': uWSGIBuildExt,
|
||||
},
|
||||
py_modules=[
|
||||
'uwsgidecorators',
|
||||
],
|
||||
ext_modules=[
|
||||
Extension(uWSGIBuildExt.UWSGI_NAME, sources=[]),
|
||||
],
|
||||
entry_points={
|
||||
'console_scripts': ['uwsgi=%s:run' % uWSGIBuildExt.UWSGI_NAME],
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user