diff --git a/.gitignore b/.gitignore index 1890c1da5..c8794cba3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,14 @@ *.pyc -*.c +zmq/*/*.c build dist conf +bundled_libzmq *.egg-info *.so *.pyd *.dll +*.dylib docs/source/api/generated docs/gh-pages setup.cfg diff --git a/MANIFEST.in b/MANIFEST.in index 58ec44665..f9b0747d9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,12 +7,12 @@ include setup.cfg.template include setup.py include setupegg.py include zmqversion.py -include buildutils.py graft docs prune docs/build prune docs/gh-pages +graft buildutils graft examples graft zmq graft perf diff --git a/buildutils.py b/buildutils.py deleted file mode 100644 index 868d42f80..000000000 --- a/buildutils.py +++ /dev/null @@ -1,261 +0,0 @@ -"""Detect zmq version""" -#----------------------------------------------------------------------------- -# Copyright (C) 2011 Brian Granger, Min Ragan-Kelley -# -# This file is part of pyzmq, copied and adapted from h5py. -# h5py source used under the New BSD license -# -# h5py: -# -# Distributed under the terms of the New BSD License. The full license is in -# the file COPYING.BSD, distributed as part of this software. -#----------------------------------------------------------------------------- - -import shutil -import sys -import os -import logging -import pickle -import platform -from distutils import ccompiler -from distutils.sysconfig import customize_compiler -from subprocess import Popen, PIPE - -try: - from configparser import ConfigParser -except: - from ConfigParser import ConfigParser - -pjoin = os.path.join - -#----------------------------------------------------------------------------- -# Logging (adapted from h5py: http://h5py.googlecode.com) -#----------------------------------------------------------------------------- -logger = logging.getLogger() -logger.addHandler(logging.StreamHandler(sys.stderr)) - -def debug(what): - pass - -def fatal(instring, code=1): - logger.error("Fatal: "+instring) - exit(code) - -def warn(instring): - logger.error("Warning: "+instring) - - -#----------------------------------------------------------------------------- -# Utility functions (adapted from h5py: http://h5py.googlecode.com) -#----------------------------------------------------------------------------- - -def detect_zmq(basedir, **compiler_attrs): - """Compile, link & execute a test program, in empty directory `basedir`. - - The C compiler will be updated with any keywords given via setattr. - - Parameters - ---------- - - basedir : path - The location where the test program will be compiled and run - **compiler_attrs : dict - Any extra compiler attributes, which will be set via ``setattr(cc)``. - - Returns - ------- - - A dict of properties for zmq compilation, with the following two keys: - - vers : tuple - The ZMQ version as a tuple of ints, e.g. (2,2,0) - options : dict - The compiler options used to compile the test function, e.g. `include_dirs`, - `library_dirs`, `libs`, etc. - """ - - cc = ccompiler.new_compiler() - customize_compiler(cc) - for name, val in compiler_attrs.items(): - setattr(cc, name, val) - - cfile = pjoin(basedir, 'vers.c') - efile = pjoin(basedir, 'vers') - - f = open(cfile, 'w') - try: - f.write( -r""" -#include -#include "zmq.h" - -int main(void){ - int major, minor, patch; - zmq_version(&major, &minor, &patch); - fprintf(stdout, "vers: %d.%d.%d\n", major, minor, patch); - return 0; -} -""") - finally: - f.close() - - cpreargs = lpreargs = None - if sys.platform == 'darwin': - # use appropriate arch for comiler - if platform.architecture()[0]=='32bit': - cpreargs = ['-arch','i386'] - lpreargs = ['-arch', 'i386', '-undefined', 'dynamic_lookup'] - else: - # allow for missing UB arch, since it will still work: - lpreargs = ['-undefined', 'dynamic_lookup'] - - objs = cc.compile([cfile],extra_preargs=cpreargs) - cc.link_executable(objs, efile, extra_preargs=lpreargs) - - result = Popen(efile, stdout=PIPE, stderr=PIPE) - so, se = result.communicate() - # for py3k: - so = so.decode() - se = se.decode() - if result.returncode: - msg = "Error running version detection script:\n%s\n%s" % (so,se) - logging.error(msg) - raise IOError(msg) - - handlers = {'vers': lambda val: tuple(int(v) for v in val.split('.'))} - - props = {} - for line in (x for x in so.split('\n') if x): - key, val = line.split(':') - props[key] = handlers[key](val) - - props['options'] = compiler_attrs - return props - -def localpath(*args): - plist = [os.path.dirname(__file__)]+list(args) - return os.path.abspath(pjoin(*plist)) - -def loadpickle(name): - """ Load object from pickle file, or None if it can't be opened """ - name = pjoin('conf', name) - try: - f = open(name,'rb') - except IOError: - # raise - return None - try: - return pickle.load(f) - except Exception: - # raise - return None - finally: - f.close() - -def savepickle(name, data): - """ Save to pickle file, exiting if it can't be written """ - if not os.path.exists('conf'): - os.mkdir('conf') - name = pjoin('conf', name) - try: - f = open(name, 'wb') - except IOError: - fatal("Can't open pickle file \"%s\" for writing" % name) - try: - pickle.dump(data, f, 0) - finally: - f.close() - -def v_str(v_tuple): - """turn (2,0,1) into '2.0.1'.""" - return ".".join(str(x) for x in v_tuple) - -def get_eargs(): - """ Look for options in environment vars """ - - settings = {} - - zmq = os.environ.get("ZMQ_DIR", '') - if zmq != '': - debug("Found environ var ZMQ_DIR=%s" % zmq) - settings['zmq'] = zmq - - return settings - -def get_cfg_args(): - """ Look for options in setup.cfg """ - - settings = {} - zmq = '' - if not os.path.exists('setup.cfg'): - return settings - cfg = ConfigParser() - cfg.read('setup.cfg') - if 'build_ext' in cfg.sections() and \ - cfg.has_option('build_ext', 'include_dirs'): - includes = cfg.get('build_ext', 'include_dirs') - include = includes.split(os.pathsep)[0] - if include.endswith('include') and os.path.isdir(include): - zmq = include[:-8] - if zmq != '': - debug("Found ZMQ=%s in setup.cfg" % zmq) - settings['zmq'] = zmq - - return settings - -def get_cargs(): - """ Look for global options in the command line """ - settings = loadpickle('buildconf.pickle') - if settings is None: settings = {} - for arg in sys.argv[:]: - if arg.find('--zmq=') == 0: - zmq = arg.split('=')[-1] - if zmq.lower() == 'default': - settings.pop('zmq', None) - else: - settings['zmq'] = zmq - sys.argv.remove(arg) - savepickle('buildconf.pickle', settings) - return settings - -def discover_settings(): - """ Discover custom settings for ZMQ path""" - settings = get_cfg_args() # lowest priority - settings.update(get_eargs()) - settings.update(get_cargs()) # highest priority - return settings.get('zmq') - -def copy_and_patch_libzmq(ZMQ, libzmq): - """copy libzmq into source dir, and patch it if necessary. - - This command is necessary prior to running a bdist on Linux or OS X. - """ - if sys.platform.startswith('win'): - return - # copy libzmq into zmq for bdist - local = localpath('zmq',libzmq) - if ZMQ is None and not os.path.exists(local): - fatal("Please specify zmq prefix via `setup.py configure --zmq=/path/to/zmq` " - "or copy libzmq into zmq/ manually prior to running bdist.") - try: - # resolve real file through symlinks - lib = os.path.realpath(pjoin(ZMQ, 'lib', libzmq)) - print ("copying %s -> %s"%(lib, local)) - shutil.copy(lib, local) - except Exception: - if not os.path.exists(local): - fatal("Could not copy libzmq into zmq/, which is necessary for bdist. " - "Please specify zmq prefix via `setup.py configure --zmq=/path/to/zmq` " - "or copy libzmq into zmq/ manually.") - - if sys.platform == 'darwin': - # patch install_name on darwin, instead of using rpath - cmd = ['install_name_tool', '-id', '@loader_path/../%s'%libzmq, local] - try: - p = Popen(cmd, stdout=PIPE,stderr=PIPE) - except OSError: - fatal("install_name_tool not found, cannot patch libzmq for bundling.") - out,err = p.communicate() - if p.returncode: - fatal("Could not patch bundled libzmq install_name: %s"%err, p.returncode) - diff --git a/buildutils/__init__.py b/buildutils/__init__.py new file mode 100644 index 000000000..df449d23e --- /dev/null +++ b/buildutils/__init__.py @@ -0,0 +1,9 @@ +"""utilities for building pyzmq. + +Largely adapted from h5py +""" + +from .msg import * +from .config import * +from .detect import * +from .bundle import * diff --git a/buildutils/bundle.py b/buildutils/bundle.py new file mode 100644 index 000000000..eb1fb02ae --- /dev/null +++ b/buildutils/bundle.py @@ -0,0 +1,207 @@ +"""utilities for fetching build dependencies.""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 Min Ragan-Kelley +# +# This file is part of pyzmq +# +# Distributed under the terms of the New BSD License. The full license is in +# the file COPYING.BSD, distributed as part of this software. +# +# This bundling code is largely adapted from pyzmq-static's get.sh by +# Brandon Craig-Rhodes, which is itself BSD licensed. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +import os +import shutil +import sys +import tarfile +from subprocess import Popen, PIPE + +try: + # py2 + from urllib2 import urlopen +except ImportError: + # py3 + from urllib.request import urlopen + +from .msg import fatal, debug, info, warn + +pjoin = os.path.join + +#----------------------------------------------------------------------------- +# Constants +#----------------------------------------------------------------------------- + +bundled_version = (2,2,0) +libzmq = "zeromq-%i.%i.%i.tar.gz" % (bundled_version) +libzmq_url = "http://download.zeromq.org/" + libzmq +util = "util-linux-2.21.tar.gz" +util_url = "http://www.kernel.org/pub/linux/utils/util-linux/v2.21/" + util + +HERE = os.path.dirname(__file__) +ROOT = os.path.dirname(HERE) + +#----------------------------------------------------------------------------- +# functions +#----------------------------------------------------------------------------- + + +def untgz(archive): + return archive.replace('.tar.gz', '') + +def localpath(*args): + """construct an absolute path from a list relative to the root pyzmq directory""" + plist = [ROOT] + list(args) + return os.path.abspath(pjoin(*plist)) + +def fetch_archive(savedir, url, fname, force=False): + """download an archive to a specific location""" + dest = pjoin(savedir, fname) + if os.path.exists(dest) and not force: + info("already have %s" % fname) + return dest + info("fetching %s into %s" % (url, savedir)) + if not os.path.exists(savedir): + os.makedirs(savedir) + req = urlopen(url) + with open(dest, 'wb') as f: + f.write(req.read()) + return dest + +def fetch_libzmq(savedir): + """download and extract libzmq""" + dest = pjoin(savedir, 'zeromq') + if os.path.exists(dest): + info("already have %s" % dest) + return + fname = fetch_archive(savedir, libzmq_url, libzmq) + tf = tarfile.open(fname) + with_version = pjoin(savedir, tf.firstmember.path) + tf.extractall(savedir) + tf.close() + # remove version suffix: + shutil.move(with_version, dest) + +def stage_platform_hpp(zmqroot): + """stage platform.hpp into libzmq sources + + Tries ./configure first (except on Windows), + then falls back on included platform.hpp previously generated. + """ + + platform_hpp = pjoin(zmqroot, 'src', 'platform.hpp') + if os.path.exists(platform_hpp): + info("already have platform.hpp") + return + if os.name == 'nt': + # stage msvc platform header + platform_dir = pjoin(zmqroot, 'builds', 'msvc') + else: + info("attempting ./configure to generate platform.hpp") + + p = Popen('./configure', cwd=zmqroot, shell=True, + stdout=PIPE, stderr=PIPE, + ) + o,e = p.communicate() + if p.returncode: + warn("failed to configure libzmq:\n%s" % e) + if sys.platform == 'darwin': + platform_dir = pjoin(HERE, 'include_darwin') + elif sys.platform.startswith('freebsd'): + platform_dir = pjoin(HERE, 'include_freebsd') + else: + platform_dir = pjoin(HERE, 'include_linux') + else: + return + + info("staging platform.hpp from: %s" % platform_dir) + shutil.copy(pjoin(platform_dir, 'platform.hpp'), platform_hpp) + + +def fetch_uuid(savedir): + """download, extract, and patch libuuid sources""" + dest = pjoin(savedir, 'uuid') + if os.path.exists(dest): + info("already have %s" % dest) + return + + fname = fetch_archive(savedir, util_url, util) + tf = tarfile.open(fname) + util_name = untgz(util) + uuid_path = util_name+'/libuuid/src' + uuid = filter( + lambda m: m.name.startswith(uuid_path) and not m.name.endswith("nt.c"), + tf.getmembers() + ) + # uuid_members = map(tf.getmember, uuid_names) + tf.extractall(savedir, uuid) + if os.path.exists(dest): + shutil.rmtree(dest) + shutil.move(pjoin(savedir, util_name, 'libuuid', 'src'), dest) + shutil.rmtree(pjoin(savedir, util_name)) + + patch_uuid(dest) + + +def patch_uuid(uuid_dir): + """patch uuid.h with a few defines + + from pyzmq-static + """ + info("patching gen_uuid.c") + gen_uuid = pjoin(uuid_dir, "gen_uuid.c") + with open(gen_uuid) as f: + lines = f.readlines() + + if 'pyzmq-patch' in lines[0]: + info("already patched") + return + else: + lines.insert(0, "// end pyzmq-patch\n") + for h in ('UNISTD', 'STDLIB', 'SYS_FILE'): + lines.insert(0, "#define HAVE_%s_H\n" % h) + lines.insert(0, "// begin pyzmq-patch\n") + + with open(gen_uuid, 'w') as f: + f.writelines(lines) + + + +def copy_and_patch_libzmq(ZMQ, libzmq): + """copy libzmq into source dir, and patch it if necessary. + + This command is necessary prior to running a bdist on Linux or OS X. + """ + if sys.platform.startswith('win'): + return + # copy libzmq into zmq for bdist + local = localpath('zmq',libzmq) + if ZMQ is None and not os.path.exists(local): + fatal("Please specify zmq prefix via `setup.py configure --zmq=/path/to/zmq` " + "or copy libzmq into zmq/ manually prior to running bdist.") + try: + # resolve real file through symlinks + lib = os.path.realpath(pjoin(ZMQ, 'lib', libzmq)) + print ("copying %s -> %s"%(lib, local)) + shutil.copy(lib, local) + except Exception: + if not os.path.exists(local): + fatal("Could not copy libzmq into zmq/, which is necessary for bdist. " + "Please specify zmq prefix via `setup.py configure --zmq=/path/to/zmq` " + "or copy libzmq into zmq/ manually.") + + if sys.platform == 'darwin': + # patch install_name on darwin, instead of using rpath + cmd = ['install_name_tool', '-id', '@loader_path/../%s'%libzmq, local] + try: + p = Popen(cmd, stdout=PIPE,stderr=PIPE) + except OSError: + fatal("install_name_tool not found, cannot patch libzmq for bundling.") + out,err = p.communicate() + if p.returncode: + fatal("Could not patch bundled libzmq install_name: %s"%err, p.returncode) + diff --git a/buildutils/config.py b/buildutils/config.py new file mode 100644 index 000000000..ec1e62d25 --- /dev/null +++ b/buildutils/config.py @@ -0,0 +1,111 @@ +"""Config functions""" +#----------------------------------------------------------------------------- +# Copyright (C) 2011 Brian Granger, Min Ragan-Kelley +# +# This file is part of pyzmq, copied and adapted from h5py. +# h5py source used under the New BSD license +# +# h5py: +# +# Distributed under the terms of the New BSD License. The full license is in +# the file COPYING.BSD, distributed as part of this software. +#----------------------------------------------------------------------------- + +import sys +import os +import json + +try: + from configparser import ConfigParser +except: + from ConfigParser import ConfigParser + +pjoin = os.path.join +from .msg import debug, fatal, warn + +#----------------------------------------------------------------------------- +# Utility functions (adapted from h5py: http://h5py.googlecode.com) +#----------------------------------------------------------------------------- + + +def load_config(name): + """Load config dict from JSON""" + fname = pjoin('conf', name+'.json') + if not os.path.exists(fname): + return None + try: + with open(fname) as f: + cfg = json.load(f) + except Exception as e: + warn("Couldn't load %s: %s" % (fname, e)) + cfg = None + return cfg + + +def save_config(name, data): + """Save config dict to JSON""" + if not os.path.exists('conf'): + os.mkdir('conf') + fname = pjoin('conf', name+'.json') + with open(fname, 'w') as f: + json.dump(data, f, indent=2) + + +def v_str(v_tuple): + """turn (2,0,1) into '2.0.1'.""" + return ".".join(str(x) for x in v_tuple) + +def get_eargs(): + """ Look for options in environment vars """ + + settings = {} + + zmq = os.environ.get("ZMQ_DIR", '') + if zmq != '': + debug("Found environ var ZMQ_DIR=%s" % zmq) + settings['zmq'] = zmq + + return settings + +def get_cfg_args(): + """ Look for options in setup.cfg """ + + settings = {} + zmq = '' + if not os.path.exists('setup.cfg'): + return settings + cfg = ConfigParser() + cfg.read('setup.cfg') + if 'build_ext' in cfg.sections() and \ + cfg.has_option('build_ext', 'include_dirs'): + includes = cfg.get('build_ext', 'include_dirs') + include = includes.split(os.pathsep)[0] + if include.endswith('include') and os.path.isdir(include): + zmq = include[:-8] + if zmq != '': + debug("Found ZMQ=%s in setup.cfg" % zmq) + settings['zmq'] = zmq + + return settings + +def get_cargs(): + """ Look for global options in the command line """ + settings = load_config('buildconf') + if settings is None: settings = {} + for arg in sys.argv[:]: + if arg.find('--zmq=') == 0: + zmq = arg.split('=')[-1] + if zmq.lower() in ('default', 'auto', ''): + settings.pop('zmq', None) + else: + settings['zmq'] = zmq + sys.argv.remove(arg) + save_config('buildconf', settings) + return settings + +def discover_settings(): + """ Discover custom settings for ZMQ path""" + settings = get_cfg_args() # lowest priority + settings.update(get_eargs()) + settings.update(get_cargs()) # highest priority + return settings.get('zmq') diff --git a/buildutils/detect.py b/buildutils/detect.py new file mode 100644 index 000000000..ed95d041c --- /dev/null +++ b/buildutils/detect.py @@ -0,0 +1,96 @@ +"""Detect zmq version""" +#----------------------------------------------------------------------------- +# Copyright (C) 2011 Brian Granger, Min Ragan-Kelley +# +# This file is part of pyzmq, copied and adapted from h5py. +# h5py source used under the New BSD license +# +# h5py: +# +# Distributed under the terms of the New BSD License. The full license is in +# the file COPYING.BSD, distributed as part of this software. +#----------------------------------------------------------------------------- + +import shutil +import sys +import os +import logging +import platform +from distutils import ccompiler +from distutils.sysconfig import customize_compiler +from subprocess import Popen, PIPE + +pjoin = os.path.join + +#----------------------------------------------------------------------------- +# Utility functions (adapted from h5py: http://h5py.googlecode.com) +#----------------------------------------------------------------------------- + +def detect_zmq(basedir, **compiler_attrs): + """Compile, link & execute a test program, in empty directory `basedir`. + + The C compiler will be updated with any keywords given via setattr. + + Parameters + ---------- + + basedir : path + The location where the test program will be compiled and run + **compiler_attrs : dict + Any extra compiler attributes, which will be set via ``setattr(cc)``. + + Returns + ------- + + A dict of properties for zmq compilation, with the following two keys: + + vers : tuple + The ZMQ version as a tuple of ints, e.g. (2,2,0) + settings : dict + The compiler options used to compile the test function, e.g. `include_dirs`, + `library_dirs`, `libs`, etc. + """ + + cc = ccompiler.new_compiler() + customize_compiler(cc) + for name, val in compiler_attrs.items(): + setattr(cc, name, val) + + cfile = pjoin(basedir, 'vers.c') + efile = pjoin(basedir, 'vers') + + shutil.copy(pjoin(os.path.dirname(__file__), 'vers.c'), cfile) + + cpreargs = lpreargs = None + if sys.platform == 'darwin': + # use appropriate arch for compiler + if platform.architecture()[0]=='32bit': + cpreargs = ['-arch','i386'] + lpreargs = ['-arch', 'i386', '-undefined', 'dynamic_lookup'] + else: + # allow for missing UB arch, since it will still work: + lpreargs = ['-undefined', 'dynamic_lookup'] + + objs = cc.compile([cfile],extra_preargs=cpreargs) + cc.link_executable(objs, efile, extra_preargs=lpreargs) + + result = Popen(efile, stdout=PIPE, stderr=PIPE) + so, se = result.communicate() + # for py3k: + so = so.decode() + se = se.decode() + if result.returncode: + msg = "Error running version detection script:\n%s\n%s" % (so,se) + logging.error(msg) + raise IOError(msg) + + handlers = {'vers': lambda val: tuple(int(v) for v in val.split('.'))} + + props = {} + for line in (x for x in so.split('\n') if x): + key, val = line.split(':') + props[key] = handlers[key](val) + + props['settings'] = compiler_attrs + return props + diff --git a/buildutils/include_darwin/platform.hpp b/buildutils/include_darwin/platform.hpp new file mode 100644 index 000000000..212cfabee --- /dev/null +++ b/buildutils/include_darwin/platform.hpp @@ -0,0 +1,229 @@ +/* src/platform.hpp. Generated from platform.hpp.in by configure. */ +/* src/platform.hpp.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `freeifaddrs' function. */ +#define HAVE_FREEIFADDRS 1 + +/* Define to 1 if you have the `getifaddrs' function. */ +#define HAVE_GETIFADDRS 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IFADDRS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +/* #undef HAVE_LIBCRYPTO */ + +/* Define to 1 if you have the `iphlpapi' library (-liphlpapi). */ +/* #undef HAVE_LIBIPHLPAPI */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the `rpcrt4' library (-lrpcrt4). */ +/* #undef HAVE_LIBRPCRT4 */ + +/* Define to 1 if you have the `rt' library (-lrt). */ +/* #undef HAVE_LIBRT */ + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define to 1 if you have the `uuid' library (-luuid). */ +/* #undef HAVE_LIBUUID */ + +/* Define to 1 if you have the `ws2_32' library (-lws2_32). */ +/* #undef HAVE_LIBWS2_32 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the `perror' function. */ +#define HAVE_PERROR 1 + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if stdbool.h conforms to C99. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if the system has the type `_Bool'. */ +/* #undef HAVE__BOOL */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "zeromq" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "zeromq-dev@lists.zeromq.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "zeromq" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "zeromq 2.1.11" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "zeromq" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.1.11" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Version number of package */ +#define VERSION "2.1.11" + +/* Force to use mutexes */ +/* #undef ZMQ_FORCE_MUTEXES */ + +/* Have AIX OS */ +/* #undef ZMQ_HAVE_AIX */ + +/* Have Cygwin */ +/* #undef ZMQ_HAVE_CYGWIN */ + +/* Have FreeBSD OS */ +/* #undef ZMQ_HAVE_FREEBSD */ + +/* Have HPUX OS */ +/* #undef ZMQ_HAVE_HPUX */ + +/* Have ifaddrs.h header. */ +#define ZMQ_HAVE_IFADDRS 1 + +/* Have Linux OS */ +/* #undef ZMQ_HAVE_LINUX */ + +/* Have MinGW32 */ +/* #undef ZMQ_HAVE_MINGW32 */ + +/* Have NetBSD OS */ +/* #undef ZMQ_HAVE_NETBSD */ + +/* Have OpenBSD OS */ +/* #undef ZMQ_HAVE_OPENBSD */ + +/* Have OpenPGM extension */ +/* #undef ZMQ_HAVE_OPENPGM */ + +/* Have DarwinOSX OS */ +#define ZMQ_HAVE_OSX 1 + +/* Have QNX Neutrino OS */ +/* #undef ZMQ_HAVE_QNXNTO */ + +/* Have Solaris OS */ +/* #undef ZMQ_HAVE_SOLARIS */ + +/* Have Windows OS */ +/* #undef ZMQ_HAVE_WINDOWS */ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +/* #undef volatile */ diff --git a/buildutils/include_freebsd/platform.hpp b/buildutils/include_freebsd/platform.hpp new file mode 100644 index 000000000..7b88ff107 --- /dev/null +++ b/buildutils/include_freebsd/platform.hpp @@ -0,0 +1,226 @@ +/* src/platform.hpp. Generated from platform.hpp.in by configure. */ +/* src/platform.hpp.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `freeifaddrs' function. */ +#define HAVE_FREEIFADDRS 1 + +/* Define to 1 if you have the `getifaddrs' function. */ +#define HAVE_GETIFADDRS 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IFADDRS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +/* #undef HAVE_LIBCRYPTO */ + +/* Define to 1 if you have the `iphlpapi' library (-liphlpapi). */ +/* #undef HAVE_LIBIPHLPAPI */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the `rpcrt4' library (-lrpcrt4). */ +/* #undef HAVE_LIBRPCRT4 */ + +/* Define to 1 if you have the `rt' library (-lrt). */ +/* #undef HAVE_LIBRT */ + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define to 1 if you have the `uuid' library (-luuid). */ +/* #undef HAVE_LIBUUID */ + +/* Define to 1 if you have the `ws2_32' library (-lws2_32). */ +/* #undef HAVE_LIBWS2_32 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the `perror' function. */ +#define HAVE_PERROR 1 + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if stdbool.h conforms to C99. */ +/* #undef HAVE_STDBOOL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if the system has the type `_Bool'. */ +/* #undef HAVE__BOOL */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "zeromq" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "zeromq-dev@lists.zeromq.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "zeromq" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "zeromq 2.1.11" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "zeromq" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.1.11" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Version number of package */ +#define VERSION "2.1.11" + +/* Force to use mutexes */ +/* #undef ZMQ_FORCE_MUTEXES */ + +/* Have AIX OS */ +/* #undef ZMQ_HAVE_AIX */ + +/* Have Cygwin */ +/* #undef ZMQ_HAVE_CYGWIN */ + +/* Have FreeBSD OS */ +#define ZMQ_HAVE_FREEBSD 1 + +/* Have HPUX OS */ +/* #undef ZMQ_HAVE_HPUX */ + +/* Have ifaddrs.h header. */ +#define ZMQ_HAVE_IFADDRS 1 + +/* Have Linux OS */ +/* #undef ZMQ_HAVE_LINUX */ + +/* Have MinGW32 */ +/* #undef ZMQ_HAVE_MINGW32 */ + +/* Have NetBSD OS */ +/* #undef ZMQ_HAVE_NETBSD */ + +/* Have OpenBSD OS */ +/* #undef ZMQ_HAVE_OPENBSD */ + +/* Have OpenPGM extension */ +/* #undef ZMQ_HAVE_OPENPGM */ + +/* Have DarwinOSX OS */ +/* #undef ZMQ_HAVE_OSX */ + +/* Have QNX Neutrino OS */ +/* #undef ZMQ_HAVE_QNXNTO */ + +/* Have Solaris OS */ +/* #undef ZMQ_HAVE_SOLARIS */ + +/* Have Windows OS */ +/* #undef ZMQ_HAVE_WINDOWS */ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +/* #undef volatile */ diff --git a/buildutils/include_linux/platform.hpp b/buildutils/include_linux/platform.hpp new file mode 100644 index 000000000..89632e6ad --- /dev/null +++ b/buildutils/include_linux/platform.hpp @@ -0,0 +1,229 @@ +/* src/platform.hpp. Generated from platform.hpp.in by configure. */ +/* src/platform.hpp.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `freeifaddrs' function. */ +#define HAVE_FREEIFADDRS 1 + +/* Define to 1 if you have the `getifaddrs' function. */ +#define HAVE_GETIFADDRS 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IFADDRS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +/* #undef HAVE_LIBCRYPTO */ + +/* Define to 1 if you have the `iphlpapi' library (-liphlpapi). */ +/* #undef HAVE_LIBIPHLPAPI */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the `rpcrt4' library (-lrpcrt4). */ +/* #undef HAVE_LIBRPCRT4 */ + +/* Define to 1 if you have the `rt' library (-lrt). */ +#define HAVE_LIBRT 1 + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define to 1 if you have the `uuid' library (-luuid). */ +#define HAVE_LIBUUID 1 + +/* Define to 1 if you have the `ws2_32' library (-lws2_32). */ +/* #undef HAVE_LIBWS2_32 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the `perror' function. */ +#define HAVE_PERROR 1 + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if stdbool.h conforms to C99. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if the system has the type `_Bool'. */ +/* #undef HAVE__BOOL */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "zeromq" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "zeromq-dev@lists.zeromq.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "zeromq" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "zeromq 2.1.11" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "zeromq" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.1.11" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Version number of package */ +#define VERSION "2.1.11" + +/* Force to use mutexes */ +/* #undef ZMQ_FORCE_MUTEXES */ + +/* Have AIX OS */ +/* #undef ZMQ_HAVE_AIX */ + +/* Have Cygwin */ +/* #undef ZMQ_HAVE_CYGWIN */ + +/* Have FreeBSD OS */ +/* #undef ZMQ_HAVE_FREEBSD */ + +/* Have HPUX OS */ +/* #undef ZMQ_HAVE_HPUX */ + +/* Have ifaddrs.h header. */ +#define ZMQ_HAVE_IFADDRS 1 + +/* Have Linux OS */ +#define ZMQ_HAVE_LINUX 1 + +/* Have MinGW32 */ +/* #undef ZMQ_HAVE_MINGW32 */ + +/* Have NetBSD OS */ +/* #undef ZMQ_HAVE_NETBSD */ + +/* Have OpenBSD OS */ +/* #undef ZMQ_HAVE_OPENBSD */ + +/* Have OpenPGM extension */ +/* #undef ZMQ_HAVE_OPENPGM */ + +/* Have DarwinOSX OS */ +/* #undef ZMQ_HAVE_OSX */ + +/* Have QNX Neutrino OS */ +/* #undef ZMQ_HAVE_QNXNTO */ + +/* Have Solaris OS */ +/* #undef ZMQ_HAVE_SOLARIS */ + +/* Have Windows OS */ +/* #undef ZMQ_HAVE_WINDOWS */ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +/* #undef volatile */ diff --git a/buildutils/initlibzmq.c b/buildutils/initlibzmq.c new file mode 100644 index 000000000..ec299f0a9 --- /dev/null +++ b/buildutils/initlibzmq.c @@ -0,0 +1,45 @@ +/* +This file is from pyzmq-static by Brandon Craig-Rhodes, +and used under the BSD license + +py3compat from http://wiki.python.org/moin/PortingExtensionModulesToPy3k + +Provide the init function that Python expects +when we compile libzmq by pretending it is a Python extension. +*/ +#include "Python.h" + +static PyMethodDef Methods[] = { + {NULL, NULL, 0, NULL} +}; + +#if PY_MAJOR_VERSION >= 3 + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libzmq", + NULL, + -1, + Methods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC +PyInit_libzmq(void) +{ + PyObject *module = PyModule_Create(&moduledef); + return module; +} + +#else // py2 + +PyMODINIT_FUNC +initlibzmq(void) +{ + (void) Py_InitModule("libzmq", Methods); +} + +#endif diff --git a/buildutils/msg.py b/buildutils/msg.py new file mode 100644 index 000000000..704e1924e --- /dev/null +++ b/buildutils/msg.py @@ -0,0 +1,43 @@ +"""logging""" +#----------------------------------------------------------------------------- +# Copyright (C) 2011 Brian Granger, Min Ragan-Kelley +# +# This file is part of pyzmq, copied and adapted from h5py. +# h5py source used under the New BSD license +# +# h5py: +# +# Distributed under the terms of the New BSD License. The full license is in +# the file COPYING.BSD, distributed as part of this software. +#----------------------------------------------------------------------------- + +from __future__ import division + +import sys +import logging + +#----------------------------------------------------------------------------- +# Logging (adapted from h5py: http://h5py.googlecode.com) +#----------------------------------------------------------------------------- + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) +logger.addHandler(logging.StreamHandler(sys.stderr)) + +def debug(msg): + logger.debug(msg) + +def info(msg): + logger.info(msg) + +def fatal(msg, code=1): + logger.error("Fatal: " + msg) + exit(code) + +def warn(msg): + logger.error("Warning: " + msg) + +def line(c='*', width=48): + print(c * (width // len(c))) + diff --git a/buildutils/vers.c b/buildutils/vers.c new file mode 100644 index 000000000..362564f38 --- /dev/null +++ b/buildutils/vers.c @@ -0,0 +1,11 @@ +// check libzmq version + +#include +#include "zmq.h" + +int main(int argc, char **argv){ + int major, minor, patch; + zmq_version(&major, &minor, &patch); + fprintf(stdout, "vers: %d.%d.%d\n", major, minor, patch); + return 0; +} diff --git a/setup.py b/setup.py index 48c4b36ca..4806233f0 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,4 @@ #!/usr/bin/env python - - #----------------------------------------------------------------------------- # Copyright (c) 2012 Brian Granger, Min Ragan-Kelley # @@ -13,6 +11,11 @@ # h5py source used under the New BSD license # # h5py: +# +# The code to bundle libzmq as an Extension is from pyzmq-static +# pyzmq-static source used under the New BSD license +# +# pyzmq-static: #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- @@ -25,8 +28,17 @@ import re import shutil import sys +import time from traceback import print_exc +if sys.version_info < (2,6): + print("ERROR: PyZMQ >= 2.2.0 requires Python 2.6 or later. \n" + + " PyZMQ 2.1.11 was the last release to support Python 2.5." + ) + sys.exit(1) + + +import distutils from distutils.core import setup, Command from distutils.ccompiler import get_default_compiler from distutils.extension import Extension @@ -53,12 +65,17 @@ nose = None # local script imports: -from buildutils import (discover_settings, v_str, localpath, savepickle, loadpickle, detect_zmq, - warn, fatal, copy_and_patch_libzmq) +from buildutils import ( + discover_settings, v_str, save_config, load_config, detect_zmq, + warn, fatal, debug, line, copy_and_patch_libzmq, localpath, + fetch_uuid, fetch_libzmq, stage_platform_hpp, + bundled_version, + ) #----------------------------------------------------------------------------- # Flags #----------------------------------------------------------------------------- + # ignore unused-function and strict-aliasing warnings, of which there # will be many from the Cython generated code: # note that this is only for gcc-style compilers @@ -88,37 +105,57 @@ ZMQ = discover_settings() -if ZMQ is not None and not os.path.exists(ZMQ): +if ZMQ is not None and ZMQ != "bundled" and not os.path.exists(ZMQ): warn("ZMQ directory \"%s\" does not appear to exist" % ZMQ) -# bundle_libzmq flag for whether libzmq will be included in pyzmq: +# bundle_libzmq_dylib flag for whether external libzmq library will be included in pyzmq: if sys.platform.startswith('win'): - bundle_libzmq = True -elif ZMQ is not None: - bundle_libzmq = doing_bdist + bundle_libzmq_dylib = True +elif ZMQ is not None and ZMQ != "bundled": + bundle_libzmq_dylib = doing_bdist else: - bundle_libzmq = False + bundle_libzmq_dylib = False # --- compiler settings ------------------------------------------------- +def bundled_settings(): + settings = { + 'libraries' : [], + 'include_dirs' : ["bundled/zeromq/include"], + 'library_dirs' : [], + 'define_macros' : [], + } + # add pthread on freebsd + # is this necessary? + if sys.platform.startswith('freebsd'): + settings['libraries'].append('pthread') + elif sys.platform.startswith('win'): + # link against libzmq in build dir: + plat = distutils.util.get_platform() + temp = 'temp.%s-%s' % (plat, sys.version[0:3]) + settings['libraries'].append('libzmq') + settings['library_dirs'].append(pjoin('build', temp, 'Release', 'buildutils')) + + return settings + + def settings_from_prefix(zmq=None): """load appropriate library/include settings from ZMQ prefix""" + + settings = { + 'libraries' : [], + 'include_dirs' : [], + 'library_dirs' : [], + 'define_macros' : [], + } if sys.platform.startswith('win'): - settings = { - 'libraries' : ['libzmq'], - 'include_dirs' : [], - 'library_dirs' : [], - } + settings['libraries'].append('libzmq') + if zmq is not None: settings['include_dirs'] += [pjoin(zmq, 'include')] settings['library_dirs'] += [pjoin(zmq, 'lib')] else: - settings = { - 'libraries' : ['zmq'], - 'include_dirs' : [], - 'library_dirs' : [], - 'define_macros' : [('PYZMQ_POSIX', 1)], - } + settings['libraries'].append('zmq') # add pthread on freebsd if sys.platform.startswith('freebsd'): @@ -132,7 +169,7 @@ def settings_from_prefix(zmq=None): settings['include_dirs'] += ['/opt/local/include'] settings['library_dirs'] += ['/opt/local/lib'] - if bundle_libzmq: + if bundle_libzmq_dylib: # bdist should link against bundled libzmq settings['library_dirs'] = ['zmq'] if sys.platform == 'darwin': @@ -144,13 +181,24 @@ def settings_from_prefix(zmq=None): elif sys.platform != 'darwin': settings['runtime_library_dirs'] = [os.path.abspath(x) for x in settings['library_dirs']] - # suppress common warnings + return settings +def init_settings(zmq=None): + if zmq == 'bundled': + settings = bundled_settings() + else: + settings = settings_from_prefix(zmq) + + if not sys.platform.startswith('win'): + settings['define_macros'].append(('PYZMQ_POSIX', 1)) + + # suppress common warnings + extra_flags = [] if ignore_common_warnings: for warning in ('unused-function', 'strict-aliasing'): extra_flags.append('-Wno-'+warning) - + settings['extra_compile_args'] = extra_flags # include internal directories @@ -158,7 +206,8 @@ def settings_from_prefix(zmq=None): return settings -COMPILER_SETTINGS = settings_from_prefix(ZMQ) + +COMPILER_SETTINGS = init_settings(ZMQ) #----------------------------------------------------------------------------- @@ -207,20 +256,24 @@ def erase_tempdir(self): pass def getcached(self): - return loadpickle('configure.pickle') + return load_config('configure') def check_zmq_version(self): zmq = self.zmq - if zmq is not None and not os.path.isdir(zmq): + if zmq is not None and zmq is not "bundled" and not os.path.isdir(zmq): fatal("Custom zmq directory \"%s\" does not exist" % zmq) config = self.getcached() - if config is None or config['options'] != self.settings: + if not config or config.get('settings') != self.settings: self.run() config = self.config else: self.config = config + line() + if self.zmq == "bundled": + return + vers = config['vers'] vs = v_str(vers) if vers < min_zmq: @@ -233,10 +286,10 @@ def check_zmq_version(self): warn("Detected ZMQ version: %s, but pyzmq targets zmq %s."%( vs, pyzmq_version)) warn("libzmq features and fixes introduced after %s will be unavailable."%vs) - print('*'*42) + line() elif vs >= '3.0': warn("Detected ZMQ version: %s. pyzmq's support for libzmq-dev is experimental."%vs) - print('*'*42) + line() if sys.platform.startswith('win'): # fetch libzmq.dll into local dir @@ -251,10 +304,125 @@ def check_zmq_version(self): "Please specify zmq prefix via configure --zmq=/path/to/zmq or copy " "libzmq into zmq/ manually.") - def run(self): + + def bundle_libzmq_extension(self): + bundledir = "bundled" + if self.distribution.ext_modules[0].name == 'zmq.libzmq': + # I've already been run + return + + line() + print ("Using bundled libzmq") + + # fetch sources for libzmq extension: + if not os.path.exists(bundledir): + os.makedirs(bundledir) + if not sys.platform.startswith(('darwin', 'freebsd', 'win')): + fetch_uuid(bundledir) + + fetch_libzmq(bundledir) + + stage_platform_hpp(pjoin(bundledir, 'zeromq')) + + # construct the Extension: + + ext = Extension( + 'zmq.libzmq', + sources = [pjoin('buildutils', 'initlibzmq.c')] + + glob(pjoin(bundledir, 'zeromq', 'src', '*.cpp')), + include_dirs = [ + pjoin(bundledir, 'zeromq', 'include'), + ], + ) + + if sys.platform.startswith('win'): + # include defines from zeromq msvc project: + ext.define_macros.append(('FD_SETSIZE', 1024)) + + # When compiling the C++ code inside of libzmq itself, we want to + # avoid "warning C4530: C++ exception handler used, but unwind + # semantics are not enabled. Specify /EHsc". + + ext.extra_compile_args.append('/EHsc') + + # And things like sockets come from libraries that must be named. + + ext.libraries.append('rpcrt4') + ext.libraries.append('ws2_32') + elif not sys.platform.startswith(('darwin', 'freebsd')): + # add uuid as both `uuid/uuid.h` and `uuid.h`: + ext.include_dirs.append(pjoin(bundledir, 'uuid')) + ext.include_dirs.append(bundledir) + ext.sources.extend(glob(pjoin(bundledir, 'uuid', '*.c'))) + + # insert the extension: + self.distribution.ext_modules.insert(0, ext) + + # update other extensions, with bundled settings + settings = init_settings("bundled") + + for ext in self.distribution.ext_modules[1:]: + for attr, value in settings.items(): + setattr(ext, attr, value) + + save_config("buildconf", dict(zmq="bundled")) + + return dict(vers=bundled_version, settings=settings) + + + def fallback_on_bundled(self): + """Couldn't build, fallback after waiting a while""" + + line() + + print ('\n'.join([ + "Failed to build or run libzmq detection test.", + "", + "If you expected pyzmq to link against an installed libzmq, please check to make sure:", + "", + " * You have a C compiler installed", + " * A development version of Python is installed (including headers)", + " * A development version of ZMQ >= %s is installed (including headers)" % v_str(min_zmq), + " * If ZMQ is not in a default location, supply the argument --zmq=", + " * If you did recently install ZMQ to a default location,", + " try rebuilding the ld cache with `sudo ldconfig`", + " or specify zmq's location with `--zmq=/usr/local`", + "", + ])) + + # ultra-lazy pip detection: + if 'pip' in ' '.join(sys.argv) or True: + print ('\n'.join([ + "If you expected to get a binary install (egg), we have those for", + "current Pythons on OSX and Windows. These can be installed with", + "easy_install, but PIP DOES NOT SUPPORT EGGS.", + "", + ])) + + print ('\n'.join([ + "You can skip all this detection/waiting nonsense if you know", + "you want pyzmq to bundle libzmq as an extension by passing:", + "", + " `--zmq=bundled`", + "", + "I will now fetch the libzmq sources and build libzmq as a Python extension", + "unless you interrupt me (^C) in the next 10 seconds...", + "", + ])) + + for i in range(10,0,-1): + sys.stdout.write('\r%2i...' % i) + sys.stdout.flush() + time.sleep(1) + + print ("") + + return self.bundle_libzmq_extension() + + + def test_build(self, zmq, settings): self.create_tempdir() - settings = self.settings - if bundle_libzmq and not sys.platform.startswith('win'): + if bundle_libzmq_dylib and not sys.platform.startswith('win'): # rpath slightly differently here, because libzmq not in .. but ../zmq: settings['library_dirs'] = ['zmq'] if sys.platform == 'darwin': @@ -263,60 +431,102 @@ def run(self): # settings['extra_link_args'] = ['-Wl,-rpath','-Wl,$ORIGIN/../zmq'] else: settings['runtime_library_dirs'] = ['$ORIGIN/../zmq'] + + line() + print ("Configure: Autodetecting ZMQ settings...") + print (" Custom ZMQ dir: %s" % zmq) try: - print ("*"*42) - print ("Configure: Autodetecting ZMQ settings...") - print (" Custom ZMQ dir: %s" % (self.zmq,)) config = detect_zmq(self.tempdir, **settings) - except Exception: - # if zmq unspecified on *ix, try again with explicit /usr/local - if self.zmq is None and not sys.platform.startswith('win'): - self.erase_tempdir() - print ("Failed with default libzmq, trying again with /usr/local") - self.zmq = '/usr/local' - self.settings = settings_from_prefix(self.zmq) - - self.run() + finally: + self.erase_tempdir() + + print (" ZMQ version detected: %s" % v_str(config['vers'])) + + return config + + def run(self): + if self.zmq == "bundled": + self.config = self.bundle_libzmq_extension() + line() + return + + config = None + + # There is no available default on Windows, so start with fallback unless + # zmq was given explicitly. + if self.zmq is None and sys.platform.startswith("win"): + config = self.fallback_on_bundled() + self.zmq = "bundled" + + if config is None: + # first try with given config or defaults + try: + config = self.test_build(self.zmq, self.settings) + except Exception: + etype, evalue, tb = sys.exc_info() + # print the error as distutils would if we let it raise: + print ("\nerror: %s\n" % evalue) + + # try fallback on /usr/local on *ix + if config is None and self.zmq is None and not sys.platform.startswith('win'): + print ("Failed with default libzmq, trying again with /usr/local") + time.sleep(1) + zmq = '/usr/local' + settings = settings_from_prefix(zmq) + try: + config = self.test_build(zmq, settings) + except Exception: + etype, evalue, tb = sys.exc_info() + # print the error as distutils would if we let it raise: + print ("\nerror: %s\n" % evalue) + else: # if we get here the second run succeeded, so we need to update compiler # settings for the extensions with /usr/local prefix + self.zmq = zmq for ext in self.distribution.ext_modules: - for key,value in self.settings.iteritems(): - setattr(ext, key, value) - return - - etype, evalue, tb = sys.exc_info() - # print the error as distutils would if we let it raise: - print ("error: %s" % evalue) - if etype is CompileError: - action = 'compile' - elif etype is LinkError: - action = 'link' - else: - action = 'build or run' - - fatal(""" - Failed to %s ZMQ test program. Please check to make sure: - - * You have a C compiler installed - * A development version of Python is installed (including header files) - * A development version of ZMQ >= %s is installed (including header files) - * If ZMQ is not in a default location, supply the argument --zmq= - * If you did recently install ZMQ to a default location, - try rebuilding the ld cache with `sudo ldconfig` - or specify zmq's location with `--zmq=/usr/local` - """%(action, v_str(min_zmq))) - - else: - savepickle('configure.pickle', config) - print (" ZMQ version detected: %s" % v_str(config['vers'])) - finally: - print ("*"*42) - self.erase_tempdir() + for attr,value in settings.items(): + setattr(ext, attr, value) + + # finally, fallback on bundled + if config is None and self.zmq is None: + config = self.fallback_on_bundled() + self.zmq = "bundled" + + save_config('configure', config) self.config = config + line() + + +class FetchCommand(Command): + """Fetch libzmq and uuid sources, that's it.""" + + description = "Fetch libuuid and libzmq sources into bundled" + + user_options = [ ] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + # fetch sources for libzmq extension: + bundledir = "bundled" + if not os.path.exists(bundledir): + os.makedirs(bundledir) + fetch_uuid(bundledir) + fetch_libzmq(bundledir) + for tarball in glob(pjoin(bundledir, '*.tar.gz')): + os.remove(tarball) + + class TestCommand(Command): """Custom distutils command to run the test suite.""" + description = "Test PyZMQ (must have been built inplace: `setup.py build_ext --inplace`)" + user_options = [ ] def initialize_options(self): @@ -355,7 +565,7 @@ def run(self): sys.exit(1) if nose is None: - print ("nose unavailable, falling back on unittest. Skipped tests will appear as ERRORs.") + warn("nose unavailable, falling back on unittest. Skipped tests will appear as ERRORs.") return self.run_unittest() else: return self.run_nose() @@ -363,6 +573,8 @@ def run(self): class GitRevisionCommand(Command): """find the current git revision and add it to zmq.core.verion.__revision__""" + description = "Store current git revision in version.py" + user_options = [ ] def initialize_options(self): @@ -467,7 +679,7 @@ class CopyingBuild(build): """subclass of build that copies libzmq if doing bdist.""" def run(self): - if bundle_libzmq and not sys.platform.startswith('win'): + if bundle_libzmq_dylib and not sys.platform.startswith('win'): # always rebuild before bdist, because linking may be wrong: self.run_command('clean') copy_and_patch_libzmq(ZMQ, 'libzmq'+lib_ext) @@ -490,6 +702,7 @@ def build_extensions(self): self.check_extensions_list(self.extensions) for ext in self.extensions: + self.build_extension(ext) def run(self): @@ -497,14 +710,15 @@ def run(self): configure = self.distribution.get_command_obj('configure') configure.check_zmq_version() build_ext.run(self) - + #----------------------------------------------------------------------------- # Extensions #----------------------------------------------------------------------------- cmdclass = {'test':TestCommand, 'clean':CleanCommand, 'revision':GitRevisionCommand, - 'configure': Configure, 'build': CopyingBuild} + 'configure': Configure, 'build': CopyingBuild, 'fetchbundle': FetchCommand, + } def pxd(subdir, name): return os.path.abspath(pjoin('zmq', subdir, name+'.pxd')) @@ -546,7 +760,7 @@ def dotc(subdir, name): ) try: - from Cython.Distutils import build_ext + from Cython.Distutils import build_ext as build_ext_c cython=True except ImportError: cython=False @@ -556,14 +770,17 @@ def dotc(subdir, name): suffix = '.pyx' - class CythonCommand(build_ext): + class CythonCommand(build_ext_c): """Custom distutils command subclassed from Cython.Distutils.build_ext to compile pyx->c, and stop there. All this does is override the C-compile method build_extension() with a no-op.""" + + description = "Compile Cython sources to C" + def build_extension(self, ext): pass - class zbuild_ext(build_ext): + class zbuild_ext(build_ext_c): def run(self): configure = self.distribution.get_command_obj('configure') configure.check_zmq_version() @@ -586,14 +803,14 @@ def run(self): ) extensions.append(ext) -# + package_data = {'zmq':['*.pxd'], 'zmq.core':['*.pxd'], 'zmq.devices':['*.pxd'], 'zmq.utils':['*.pxd', '*.h'], } -if bundle_libzmq: +if bundle_libzmq_dylib: package_data['zmq'].append('libzmq'+lib_ext) def extract_version(): diff --git a/zmq/__init__.py b/zmq/__init__.py index c78df1be3..969e34d1e 100644 --- a/zmq/__init__.py +++ b/zmq/__init__.py @@ -13,15 +13,27 @@ #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- + +import os import sys +import glob + +here = os.path.dirname(__file__) + +bundled = [] +for ext in ('pyd', 'so', 'dll', 'dylib'): + bundled.extend(glob.glob(os.path.join(here, 'libzmq*.%s*' % ext))) + +if bundled: + import ctypes + if bundled[0].endswith('.pyd'): + # a Windows Extension + _libzmq = ctypes.cdll.LoadLibrary(bundled[0]) + else: + _libzmq = ctypes.CDLL(bundled[0], mode=ctypes.RTLD_GLOBAL) + del ctypes -if sys.platform.startswith('win'): - import os, ctypes - here = os.path.dirname(__file__) - libzmq = os.path.join(here, 'libzmq.dll') - if os.path.exists(libzmq): - ctypes.cdll.LoadLibrary(libzmq) - del here, libzmq, ctypes, os +del os, sys, glob, here, bundled, ext from zmq.utils import initthreads # initialize threads initthreads.init_threads()