Commit 9610e1a1 authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #1417 from gevent/issue1411

Clean up configuring for embedded CFFI modules.
parents c604d1d2 68438844
...@@ -73,6 +73,7 @@ deps/libev/Makefile ...@@ -73,6 +73,7 @@ deps/libev/Makefile
deps/libev/config.log deps/libev/config.log
deps/libev/config.h deps/libev/config.h
deps/libev/config.status deps/libev/config.status
deps/libev/configure-output.txt
deps/libev/libtool deps/libev/libtool
deps/libev/stamp-h1 deps/libev/stamp-h1
deps/libev/.libs deps/libev/.libs
......
...@@ -14,6 +14,7 @@ import os.path ...@@ -14,6 +14,7 @@ import os.path
from _setuputils import Extension from _setuputils import Extension
from _setuputils import system from _setuputils import system
from _setuputils import dep_abspath
from _setuputils import quoted_dep_abspath from _setuputils import quoted_dep_abspath
from _setuputils import WIN from _setuputils import WIN
from _setuputils import make_universal_header from _setuputils import make_universal_header
...@@ -26,41 +27,38 @@ from _setuputils import should_embed ...@@ -26,41 +27,38 @@ from _setuputils import should_embed
LIBEV_EMBED = should_embed('libev') LIBEV_EMBED = should_embed('libev')
# Configure libev in place; but cp the config.h to the old directory; # Configure libev in place
# if we're building a CPython extension, the old directory will be
# the build/temp.XXX/libev/ directory. If we're building from a
# source checkout on pypy, OLDPWD will be the location of setup.py
# and the PyPy branch will clean it up.
libev_configure_command = ' '.join([ libev_configure_command = ' '.join([
"(cd ", quoted_dep_abspath('libev'), "(cd ", quoted_dep_abspath('libev'),
" && sh ./configure ", " && sh ./configure > configure-output.txt",
" && cp config.h \"$OLDPWD\"",
")", ")",
'> configure-output.txt'
]) ])
def configure_libev(bext, ext): def configure_libev(build_command=None, extension=None): # pylint:disable=unused-argument
# build_command is an instance of ConfiguringBuildExt.
# extension is an instance of the setuptools Extension object.
#
# This is invoked while `build_command` is in the middle of its `run()`
# method.
# Both of these arguments are unused here so that we can use this function
# both from a build command and from libev/_corecffi_build.py
if WIN: if WIN:
return return
bdir = os.path.join(bext.build_temp, 'libev') libev_path = dep_abspath('libev')
ext.include_dirs.insert(0, bdir) config_path = os.path.join(libev_path, 'config.h')
if os.path.exists(config_path):
print("Not configuring libev, 'config.h' already exists")
return
if not os.path.isdir(bdir): system(libev_configure_command)
os.makedirs(bdir) if sys.platform == 'darwin':
make_universal_header(config_path,
'SIZEOF_LONG', 'SIZEOF_SIZE_T', 'SIZEOF_TIME_T')
cwd = os.getcwd()
os.chdir(bdir)
try:
if os.path.exists('config.h'):
return
system(libev_configure_command)
if sys.platform == 'darwin':
make_universal_header('config.h',
'SIZEOF_LONG', 'SIZEOF_SIZE_T', 'SIZEOF_TIME_T')
finally:
os.chdir(cwd)
def build_extension(): def build_extension():
# Return the un-cythonized extension. # Return the un-cythonized extension.
...@@ -99,5 +97,6 @@ def build_extension(): ...@@ -99,5 +97,6 @@ def build_extension():
else: else:
CORE.define_macros += [('LIBEV_EMBED', '0')] CORE.define_macros += [('LIBEV_EMBED', '0')]
CORE.libraries.append('ev') CORE.libraries.append('ev')
CORE.configure = lambda *args: print("libev not embedded, not configuring")
return CORE return CORE
...@@ -233,6 +233,28 @@ ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, IOErro ...@@ -233,6 +233,28 @@ ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, IOErro
class ConfiguringBuildExt(build_ext): class ConfiguringBuildExt(build_ext):
# CFFI subclasses this class with its own, that overrides run()
# and invokes a `pre_run` method, if defined. The run() method is
# called only once from setup.py (this class is only instantiated
# once per invocation of setup()); run() in turn calls
# `build_extension` for every defined extension.
# For extensions we control, we let them define a `configure`
# callable attribute, and we invoke that before building. But we
# can't control the Extension object that CFFI creates. The best
# we can do is provide a global hook that we can invoke in pre_run().
gevent_pre_run_actions = ()
@classmethod
def gevent_add_pre_run_action(cls, action):
# Actions should be idempotent.
cls.gevent_pre_run_actions += (action,)
def finalize_options(self):
self.parallel = True # pylint: disable=attribute-defined-outside-init
build_ext.finalize_options(self)
def gevent_prepare(self, ext): def gevent_prepare(self, ext):
configure = getattr(ext, 'configure', None) configure = getattr(ext, 'configure', None)
if configure: if configure:
...@@ -247,6 +269,13 @@ class ConfiguringBuildExt(build_ext): ...@@ -247,6 +269,13 @@ class ConfiguringBuildExt(build_ext):
raise BuildFailed() raise BuildFailed()
raise raise
def pre_run(self, *_args):
# Called only from CFFI.
# With mulitple extensions, this probably gets called multiple
# times.
for action in self.gevent_pre_run_actions:
action()
class Extension(_Extension): class Extension(_Extension):
# This class exists currently mostly to make pylint # This class exists currently mostly to make pylint
...@@ -362,6 +391,7 @@ class GeventClean(clean): ...@@ -362,6 +391,7 @@ class GeventClean(clean):
'config.h', 'config.h',
'config.log', 'config.log',
'config.status', 'config.status',
'configure-output.txt',
'.libs' '.libs'
): ):
yield os.path.join('deps', dep, f) yield os.path.join('deps', dep, f)
......
...@@ -15,7 +15,6 @@ from setuptools import find_packages ...@@ -15,7 +15,6 @@ from setuptools import find_packages
from _setuputils import read from _setuputils import read
from _setuputils import read_version from _setuputils import read_version
from _setuputils import system
from _setuputils import PYPY, WIN from _setuputils import PYPY, WIN
from _setuputils import ConfiguringBuildExt from _setuputils import ConfiguringBuildExt
from _setuputils import GeventClean from _setuputils import GeventClean
...@@ -43,8 +42,6 @@ if PYPY and sys.pypy_version_info[:3] < (2, 6, 1): # pylint:disable=no-member ...@@ -43,8 +42,6 @@ if PYPY and sys.pypy_version_info[:3] < (2, 6, 1): # pylint:disable=no-member
__version__ = read_version() __version__ = read_version()
from _setuplibev import libev_configure_command
from _setuplibev import LIBEV_EMBED
from _setuplibev import build_extension as build_libev_extension from _setuplibev import build_extension as build_libev_extension
from _setupares import ARES from _setupares import ARES
...@@ -307,18 +304,6 @@ EXTRA_RECOMMENDED = [ ...@@ -307,18 +304,6 @@ EXTRA_RECOMMENDED = [
CFFI_DEP, CFFI_DEP,
] + EXTRA_DNSPYTHON + EXTRA_EVENTS + EXTRA_MONITOR ] + EXTRA_DNSPYTHON + EXTRA_EVENTS + EXTRA_MONITOR
# If we are running info / help commands, or we're being imported by
# tools like pyroma, we don't need to build anything
_BUILDING = True
if ((len(sys.argv) >= 2
and ('--help' in sys.argv[1:]
or sys.argv[1] in ('--help-commands',
'egg_info',
'--version',
'clean',
'--long-description')))
or __name__ != '__main__'):
_BUILDING = False
def make_long_description(): def make_long_description():
readme = read('README.rst') readme = read('README.rst')
...@@ -332,27 +317,7 @@ def make_long_description(): ...@@ -332,27 +317,7 @@ def make_long_description():
return readme return readme
def run_setup(ext_modules, run_make): def run_setup(ext_modules):
if run_make:
if (not LIBEV_EMBED and not WIN and cffi_modules) or PYPY:
# We're not embedding libev but we do want
# to build the CFFI module. We need to configure libev
# because the CORE Extension won't.
# TODO: Generalize this.
if LIBEV_CFFI_MODULE in cffi_modules and not WIN:
system(libev_configure_command)
# This changed to the libev directory, and ran configure .
# It then copied the generated config.h back to the previous
# directory, which happened to be beside us. In the embedded case,
# we're building in a different directory, so it copied it back to build
# directory, but here, we're building in the embedded directory, so
# it gave us useless files.
bad_file = None
for bad_file in ('config.h', 'configure-output.txt'):
if os.path.exists(bad_file):
os.remove(bad_file)
del bad_file
setup( setup(
name='gevent', name='gevent',
version=__version__, version=__version__,
...@@ -452,11 +417,10 @@ if os.getenv('READTHEDOCS'): ...@@ -452,11 +417,10 @@ if os.getenv('READTHEDOCS'):
os.environ['PATH'] = new_path os.environ['PATH'] = new_path
try: try:
run_setup(EXT_MODULES, run_make=_BUILDING) run_setup(EXT_MODULES)
except BuildFailed: except BuildFailed:
if ARES not in EXT_MODULES or not ARES.optional: if ARES not in EXT_MODULES or not ARES.optional:
raise raise
EXT_MODULES.remove(ARES)
run_setup(EXT_MODULES, run_make=_BUILDING)
if ARES not in EXT_MODULES and __name__ == '__main__' and _BUILDING:
sys.stderr.write('\nWARNING: The gevent.ares extension has been disabled.\n') sys.stderr.write('\nWARNING: The gevent.ares extension has been disabled.\n')
EXT_MODULES.remove(ARES)
run_setup(EXT_MODULES)
...@@ -15,6 +15,7 @@ from cffi import FFI ...@@ -15,6 +15,7 @@ from cffi import FFI
sys.path.append(".") sys.path.append(".")
try: try:
import _setuplibev import _setuplibev
import _setuputils
except ImportError: except ImportError:
print("This file must be imported with setup.py in the current working dir.") print("This file must be imported with setup.py in the current working dir.")
raise raise
...@@ -27,7 +28,7 @@ __all__ = [] ...@@ -27,7 +28,7 @@ __all__ = []
ffi = FFI() ffi = FFI()
distutils_ext = _setuplibev.build_extension()
def read_source(name): def read_source(name):
with open(os.path.join(thisdir, name), 'r') as f: with open(os.path.join(thisdir, name), 'r') as f:
...@@ -47,13 +48,18 @@ _cdef = _cdef.replace('#define GEVENT_ST_NLINK_T int', ...@@ -47,13 +48,18 @@ _cdef = _cdef.replace('#define GEVENT_ST_NLINK_T int',
_cdef = _cdef.replace('GEVENT_ST_NLINK_T', 'nlink_t') _cdef = _cdef.replace('GEVENT_ST_NLINK_T', 'nlink_t')
if _setuplibev.LIBEV_EMBED: if _setuplibev.LIBEV_EMBED:
# Arrange access to the loop internals
_cdef += """ _cdef += """
struct ev_loop { struct ev_loop {
int backend_fd; int backend_fd;
int activecnt; int activecnt;
...; ...;
}; };
""" """
# arrange to be configured.
_setuputils.ConfiguringBuildExt.gevent_add_pre_run_action(distutils_ext.configure)
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
# We must have the vfd_open, etc, functions on # We must have the vfd_open, etc, functions on
...@@ -71,9 +77,6 @@ void vfd_free(int); ...@@ -71,9 +77,6 @@ void vfd_free(int);
# source goes to the C compiler # source goes to the C compiler
_source = read_source('_corecffi_source.c') _source = read_source('_corecffi_source.c')
distutils_ext = _setuplibev.build_extension()
macros = list(distutils_ext.define_macros) macros = list(distutils_ext.define_macros)
try: try:
# We need the data pointer. # We need the data pointer.
......
...@@ -26,7 +26,7 @@ __all__ = [] ...@@ -26,7 +26,7 @@ __all__ = []
WIN = sys.platform.startswith('win32') WIN = sys.platform.startswith('win32')
LIBUV_EMBED = _setuputils.should_embed('libuv') LIBUV_EMBED = _setuputils.should_embed('libuv')
print("Embedding libuv?", LIBUV_EMBED)
ffi = FFI() ffi = FFI()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment