Permalink
Browse files

allow configuring pypy

- enables bundled libzmq on pypy
- allows setup.py configure to work on pypy

copies compiler config json to zmq.utils, so they can be loaded by the CFFI backend.
  • Loading branch information...
minrk committed Mar 7, 2014
1 parent 6e52efc commit 2c785d1cf695ee24d1300cbf7ad4c20e3e005f94
Showing with 87 additions and 27 deletions.
  1. +42 −23 setup.py
  2. +45 −4 zmq/backend/cffi/_cffi.py
View
@@ -77,6 +77,8 @@
# Flags
#-----------------------------------------------------------------------------
+pypy = 'PyPy' in sys.version
+
# reference points for zmq compatibility
min_zmq = (2,1,4)
target_zmq = bundled_version
@@ -255,11 +257,10 @@ def finalize_options(self):
def save_config(self, name, cfg):
"""write config to JSON"""
save_config(name, cfg, self.build_base)
+ save_config(name, cfg, os.path.join('zmq', 'utils'))
def init_settings_from_config(self):
"""set up compiler settings, based on config"""
- if 'PyPy' in sys.version:
- self.compiler_settings = {}
cfg = self.config
if cfg['libzmq_extension']:
@@ -406,8 +407,6 @@ def check_zmq_version(self):
def bundle_libsodium_extension(self, libzmq):
bundledir = "bundled"
- if "PyPy" in sys.version:
- fatal("Can't bundle libsodium as an Extension in PyPy (yet!)")
ext_modules = self.distribution.ext_modules
if ext_modules and any(m.name == 'zmq.libsodium' for m in ext_modules):
# I've already been run
@@ -463,8 +462,6 @@ def bundle_libsodium_extension(self, libzmq):
def bundle_libzmq_extension(self):
bundledir = "bundled"
- if "PyPy" in sys.version:
- fatal("Can't bundle libzmq as an Extension in PyPy (yet!)")
ext_modules = self.distribution.ext_modules
if ext_modules and any(m.name == 'zmq.libzmq' for m in ext_modules):
# I've already been run
@@ -605,16 +602,13 @@ def test_build(self, prefix, settings):
return detected
-
+
def finish_run(self):
self.save_config('config', self.config)
line()
def run(self):
cfg = self.config
- if 'PyPy' in sys.version:
- info("PyPy: Nothing to configure")
- return
if cfg['libzmq_extension']:
self.bundle_libzmq_extension()
@@ -1046,19 +1040,44 @@ def run(self):
ext.sources = sources
extensions.append(ext)
-if 'PyPy' in sys.version:
- try:
- from zmq.backend.cffi import ffi
- except ImportError:
- warn("Couldn't get CFFI extension")
- extensions = []
- else:
- extensions = [ffi.verifier.get_extension()]
+if pypy:
+ # add dummy extension, to ensure build_ext runs
+ dummy_ext = Extension('dummy', sources=[])
+ extensions = [dummy_ext]
+
+ bld_ext = cmdclass['build_ext']
+ class pypy_build_ext(bld_ext):
+ """hack to build pypy extension only after building bundled libzmq
+
+ otherwise it will fail when libzmq is bundled.
+ """
+ def build_extensions(self):
+ self.extensions.remove(dummy_ext)
+ bld_ext.build_extensions(self)
+ # build ffi extension after bundled libzmq,
+ # because it may depend on linking it
+ here = os.getcwd()
+ sys.path.insert(0, self.build_lib)
+ try:
+ from zmq.backend.cffi import ffi
+ except ImportError as e:
+ warn("Couldn't get CFFI extension: %s" % e)
+ else:
+ ext = ffi.verifier.get_extension()
+ self.extensions.append(ext)
+ self.build_extension(ext)
+ finally:
+ sys.path.pop(0)
+
+
+ # How many build_ext subclasses is this? 5? Gross.
+ cmdclass['build_ext'] = pypy_build_ext
+
-package_data = {'zmq':['*.pxd'],
- 'zmq.backend.cython':['*.pxd'],
- 'zmq.devices':['*.pxd'],
- 'zmq.utils':['*.pxd', '*.h'],
+package_data = {'zmq': ['*.pxd'],
+ 'zmq.backend.cython': ['*.pxd'],
+ 'zmq.devices': ['*.pxd'],
+ 'zmq.utils': ['*.pxd', '*.h', '*.json'],
}
package_data['zmq'].append('libzmq'+lib_ext)
@@ -1130,7 +1149,7 @@ def find_packages():
'Programming Language :: Python :: 3.3',
],
)
-if 'setuptools' in sys.modules and 'PyPy' in sys.version:
+if 'setuptools' in sys.modules and pypy:
setup_args['install_requires'] = [
'py',
'cffi',
View
@@ -14,10 +14,11 @@
# Imports
#-----------------------------------------------------------------------------
+import json
import os
+from os.path import dirname, join
from cffi import FFI
-import zmq.utils
from zmq.utils.constant_names import all_names, no_prefix
@@ -116,11 +117,47 @@
int get_ipc_path_max_len(void);
'''
+def load_compiler_config():
+ import zmq
+ zmq_dir = dirname(zmq.__file__)
+ zmq_parent = dirname(zmq_dir)
+
+ fname = join(zmq_dir, 'utils', 'compiler.json')
+ if os.path.exists(fname):
+ with open(fname) as f:
+ cfg = json.load(f)
+ else:
+ cfg = {}
+
+ cfg.setdefault("include_dirs", [])
+ cfg.setdefault("library_dirs", [])
+ cfg.setdefault("runtime_library_dirs", [])
+ cfg.setdefault("libraries", ["zmq"])
+
+ # cast to str, because cffi can't handle unicode paths (?!)
+ cfg['libraries'] = [str(lib) for lib in cfg['libraries']]
+ for key in ("include_dirs", "library_dirs", "runtime_library_dirs"):
+ # interpret paths relative to parent of zmq (like source tree)
+ abs_paths = []
+ for p in cfg[key]:
+ if p.startswith('zmq'):
+ p = join(zmq_parent, p)
+ abs_paths.append(str(p))
+ cfg[key] = abs_paths
+ return cfg
+
+cfg = load_compiler_config()
+
def zmq_version_info():
ffi_check = FFI()
ffi_check.cdef('void zmq_version(int *major, int *minor, int *patch);')
+ cfg = load_compiler_config()
C_check_version = ffi_check.verify('#include <zmq.h>',
- libraries=['c', 'zmq'])
+ libraries=cfg['libraries'],
+ include_dirs=cfg['include_dirs'],
+ library_dirs=cfg['library_dirs'],
+ runtime_library_dirs=cfg['runtime_library_dirs'],
+ )
major = ffi.new('int*')
minor = ffi.new('int*')
patch = ffi.new('int*')
@@ -169,7 +206,6 @@ def _make_defines(names):
ffi.cdef(functions)
-zmq_utils = os.path.dirname(zmq.utils.__file__)
C = ffi.verify('''
#include <stdio.h>
@@ -185,7 +221,12 @@ def _make_defines(names):
return sizeof(dummy->sun_path) - 1;
}
-''', libraries=['c', 'zmq'], include_dirs=[zmq_utils])
+''',
+ libraries=cfg['libraries'],
+ include_dirs=cfg['include_dirs'],
+ library_dirs=cfg['library_dirs'],
+ runtime_library_dirs=cfg['runtime_library_dirs'],
+)
nsp = new_sizet_pointer = lambda length: ffi.new('size_t*', length)

0 comments on commit 2c785d1

Please sign in to comment.