You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2016/11/25 21:01:19 UTC

[23/48] qpid-proton git commit: PROTON-1330: [python] bundle the C source in the python source distribution

PROTON-1330: [python] bundle the C source in the python source distribution

This closes #88


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/888862f9
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/888862f9
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/888862f9

Branch: refs/heads/go1
Commit: 888862f9d149f11516fdec35bdb1e0fa1998c3c1
Parents: eac0bb6
Author: Ken Giusti <kg...@apache.org>
Authored: Tue Nov 1 13:21:15 2016 -0400
Committer: Ken Giusti <kg...@apache.org>
Committed: Wed Nov 16 08:58:22 2016 -0500

----------------------------------------------------------------------
 proton-c/CMakeLists.txt                       |  67 +++-
 proton-c/bindings/python/CMakeLists.txt       |  55 +++
 proton-c/bindings/python/MANIFEST.in          |   3 +
 proton-c/bindings/python/PACKAGING.txt        |  26 ++
 proton-c/bindings/python/README.rst.in        |  11 +
 proton-c/bindings/python/setup.py             | 401 ---------------------
 proton-c/bindings/python/setup.py.in          | 323 +++++++++++++++++
 proton-c/bindings/python/setuputils/bundle.py |  92 -----
 proton-c/bindings/python/setuputils/misc.py   |  38 +-
 proton-c/tox.ini.in                           |   3 +-
 10 files changed, 506 insertions(+), 513 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 3cf01cd..7753f1f 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -91,6 +91,11 @@ add_custom_command (
   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py
   )
 
+add_custom_target(
+  generated_c_files
+  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
+  )
+
 # Select IO impl
 if(PN_WINAPI)
   set (pn_io_impl src/reactor/io/windows/io.c src/reactor/io/windows/iocp.c src/reactor/io/windows/write_pipeline.c)
@@ -300,16 +305,38 @@ pn_absolute_install_dir(EXEC_PREFIX "." ${CMAKE_INSTALL_PREFIX})
 pn_absolute_install_dir(LIBDIR ${LIB_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX})
 pn_absolute_install_dir(INCLUDEDIR ${INCLUDE_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX})
 
-add_subdirectory(bindings)
 add_subdirectory(docs/api)
 add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
 
+# for full source distribution:
+set (qpid-proton-platform-all
+  src/platform/platform.c
+  src/reactor/io/windows/io.c
+  src/reactor/io/windows/iocp.c
+  src/reactor/io/windows/write_pipeline.c
+  src/reactor/io/windows/selector.c
+  src/reactor/io/posix/io.c
+  src/reactor/io/posix/selector.c
+  )
+
+# platform specific library build:
 set (qpid-proton-platform-io
   src/platform/platform.c
   ${pn_io_impl}
   ${pn_selector_impl}
   )
 
+# for full source distribution:
+set (qpid-proton-layers-all
+  src/sasl/sasl.c
+  src/sasl/cyrus_sasl.c
+  src/sasl/none_sasl.c
+  src/ssl/openssl.c
+  src/ssl/schannel.c
+  src/ssl/ssl_stub.c
+  )
+
+# for current build system's environment:
 set (qpid-proton-layers
   ${pn_sasl_impl}
   ${pn_ssl_impl}
@@ -347,6 +374,37 @@ set (qpid-proton-core
 set (qpid-proton-include-generated
   ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
   ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
+  ${CMAKE_CURRENT_BINARY_DIR}/include/proton/version.h
+  )
+
+set (qpid-proton-private-includes
+  src/extra/scanner.h
+  src/messenger/store.h
+  src/messenger/subscription.h
+  src/messenger/messenger.h
+  src/messenger/transform.h
+  src/ssl/ssl-internal.h
+  src/sasl/sasl-internal.h
+  src/core/autodetect.h
+  src/core/log_private.h
+  src/core/config.h
+  src/core/encoder.h
+  src/core/dispatch_actions.h
+  src/core/engine-internal.h
+  src/core/transport.h
+  src/core/framing.h
+  src/core/buffer.h
+  src/core/util.h
+  src/core/dispatcher.h
+  src/core/data.h
+  src/core/decoder.h
+  src/reactor/io/windows/iocp.h
+  src/reactor/selector.h
+  src/reactor/io.h
+  src/reactor/reactor.h
+  src/reactor/selectable.h
+  src/platform/platform.h
+  src/platform/platform_fmt.h
   )
 
 set (qpid-proton-extra
@@ -376,6 +434,7 @@ set (qpid-proton-include
   include/proton/codec.h
   include/proton/condition.h
   include/proton/connection.h
+  include/proton/connection_engine.h
   include/proton/delivery.h
   include/proton/disposition.h
   include/proton/engine.h
@@ -404,6 +463,10 @@ set (qpid-proton-include-extra
   include/proton/url.h
 )
 
+# note: process bindings after the source lists have been defined so
+# the bindings can reference them
+add_subdirectory(bindings)
+
 source_group("API Header Files" FILES ${qpid-proton-include} ${qpid-proton-include-extra})
 
 set_source_files_properties (
@@ -441,6 +504,7 @@ add_library (
   ${qpid-proton-include}
   ${qpid-proton-include-generated}
   )
+add_dependencies(qpid-proton-core generated_c_files)
 
 target_link_libraries (qpid-proton-core ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
 
@@ -466,6 +530,7 @@ add_library(
   ${qpid-proton-platform-io}
   ${qpid-proton-include-extra}
   )
+add_dependencies(qpid-proton generated_c_files)
 
 target_link_libraries (qpid-proton ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index fc28417..fe732d9 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -64,6 +64,13 @@ set (pysrc
     proton/wrapper.py
     proton/_compat.py
     )
+# extra files included in the source distribution
+set(py_dist_files
+    cproton.i
+    MANIFEST.in
+    setuputils
+    docs
+    )
 
 macro (py_compile directory files artifacts)
   foreach (src_file ${files})
@@ -122,3 +129,51 @@ install(TARGETS ${SWIG_MODULE_cproton_REAL_NAME}
         COMPONENT Python)
 
 set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "html;tutorial")
+
+#
+# Set up the directory 'dist' for building the python native package
+# source distribution for Pypi/pip
+#
+
+set(py_dist_dir ${CMAKE_CURRENT_BINARY_DIR}/dist)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
+               ${py_dist_dir}/setup.py
+)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/README.rst.in
+               ${py_dist_dir}/README.rst
+)
+
+file(COPY ${py_dist_files} DESTINATION ${py_dist_dir})
+
+file(MAKE_DIRECTORY ${py_dist_dir}/proton)
+file(COPY ${pysrc} DESTINATION ${py_dist_dir}/proton)
+
+add_custom_target(py_src_dist ALL)
+add_dependencies(py_src_dist generated_c_files)
+file(MAKE_DIRECTORY ${py_dist_dir}/proton-c)
+
+# copy generated source files from the binary dir to the dist
+foreach(sfile ${qpid-proton-include-generated})
+  string(REPLACE ${CMAKE_BINARY_DIR} ${py_dist_dir} dfile ${sfile})
+  add_custom_command(TARGET py_src_dist
+                     COMMAND ${CMAKE_COMMAND} -E
+                         copy ${sfile} ${dfile})
+endforeach()
+
+# copy the proton C sources to the dist
+set (all_src
+  ${qpid-proton-core}
+  ${qpid-proton-extra}
+  ${qpid-proton-include}
+  ${qpid-proton-include-extra}
+  ${qpid-proton-layers-all}
+  ${qpid-proton-platform-all}
+  ${qpid-proton-private-includes}
+  include/proton/cproton.i
+)
+foreach(sfile ${all_src})
+  add_custom_command(TARGET py_src_dist
+                     COMMAND ${CMAKE_COMMAND} -E
+                         copy ${CMAKE_SOURCE_DIR}/proton-c/${sfile} ${py_dist_dir}/proton-c/${sfile})
+endforeach()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/MANIFEST.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/MANIFEST.in b/proton-c/bindings/python/MANIFEST.in
index a89a962..a37ad72 100644
--- a/proton-c/bindings/python/MANIFEST.in
+++ b/proton-c/bindings/python/MANIFEST.in
@@ -1,2 +1,5 @@
 graft docs
 graft setuputils
+graft proton-c
+global-exclude proton-c *.pyc *.pyo
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/PACKAGING.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/PACKAGING.txt b/proton-c/bindings/python/PACKAGING.txt
new file mode 100644
index 0000000..fa127f0
--- /dev/null
+++ b/proton-c/bindings/python/PACKAGING.txt
@@ -0,0 +1,26 @@
+This document describes how to build a native Python source package.
+This can be used to install the Python bindings via pip.
+
+First configure the project using 'cmake' then build it. You do not
+need to install the project. See the INSTALL.md file at the project's
+top directory for details on building.
+
+Once you have built the project, there should be a 'dist' directory in
+the Python bindings directory in the build directory.
+
+For example, assuming the build directory is named 'build':
+
+$ cd build/proton-c/bindings/python/dist
+
+You can now run the setup.py script from within the dist directory to
+build your source distribution package.
+
+To build a Python source distribution:
+
+$ python ./setup.py sdist
+
+To build and install:
+
+$ python ./setup.py build install
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/README.rst.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/README.rst.in b/proton-c/bindings/python/README.rst.in
new file mode 100644
index 0000000..8be1dd3
--- /dev/null
+++ b/proton-c/bindings/python/README.rst.in
@@ -0,0 +1,11 @@
+Python bindings for Qpid Proton
+===============================
+
+This module provides version @PN_VERSION_MAJOR@.@PN_VERSION_MINOR@.@PN_VERSION_POINT@ of the Proton AMQP messaging toolkit.
+
+Qpid Proton is a high-performance, lightweight messaging library. It
+can be used in the widest range of messaging applications, including
+brokers, client libraries, routers, bridges, proxies, and more. Proton
+makes it trivial to integrate with the AMQP 1.0 ecosystem from any
+platform, environment, or language.  More about `Proton <http://qpid.apache.org/proton/index.html>`_.
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/setup.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py b/proton-c/bindings/python/setup.py
deleted file mode 100755
index 3606bed..0000000
--- a/proton-c/bindings/python/setup.py
+++ /dev/null
@@ -1,401 +0,0 @@
-#!/usr/bin/env python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-"""
-python-qpid-proton setup script
-
-DISCLAIMER: This script took lots of inspirations from PyZMQ, which is licensed
-under the 'MODIFIED BSD LICENSE'.
-
-Although inspired by the work in PyZMQ, this script and the modules it depends
-on were largely simplified to meet the requirements of the library.
-
-The default behavior of this script is to build the registered `_cproton`
-extension using the system qpid-proton library. However, before doing that, the
-script will try to discover the available qpid-proton's version and whether it's
-suitable for the version of this library. This allows us to have a tight release
-between the versions of the bindings and qpid-proton's version.
-
-The versions used to verify this are in `setuputils.bundle` and they should be
-increased on every release. Note that `bundled_version` matches the current
-released version. The motivation behind this is that we don't know how many
-new releases will be made in the `0.9` series, therefore we need to target the
-latest possible.
-
-If qpid-proton is found in the system and the available versions are match the
-required ones, then the install process will continue normally.
-
-If the available versions are not good for the bindings or the library is
-missing, then the following will happen:
-
-The setup script will attempt to download the C source for qpid-proton - see
-`setuputils.bundle.fetch_libqpid_proton` - and it will include the proton C
-code into the extension itself.
-
-While the above removes the need of *always* having qpid-proton installed, it
-does not solve the need of having `swig` and the libraries qpid-proton requires
-installed to make this setup work.
-
-From the Python side, this scripts overrides 1 command - build_ext - and it adds a
-new one. The later - Configure - is called from the former to setup/discover what's
-in the system. The rest of the comands and steps are done normally without any kind
-of monkey patching.
-"""
-
-import glob
-import os
-import subprocess
-import sys
-
-import distutils.spawn as ds_spawn
-import distutils.sysconfig as ds_sys
-from distutils.ccompiler import new_compiler, get_default_compiler
-from distutils.core import setup, Extension
-from distutils.command.build import build
-from distutils.command.build_ext import build_ext
-from distutils.command.sdist import sdist
-from distutils import errors
-
-from setuputils import bundle
-from setuputils import log
-from setuputils import misc
-
-
-class CheckSDist(sdist):
-
-    def run(self):
-        self.distribution.run_command('configure')
-
-        # Append the source that was removed during
-        # the configuration step.
-        _cproton = self.distribution.ext_modules[-1]
-        _cproton.sources.append('cproton.i')
-
-        try:
-            sdist.run(self)
-        finally:
-            for src in ['cproton.py', 'cproton_wrap.c']:
-                if os.path.exists(src):
-                    os.remove(src)
-
-
-class Configure(build_ext):
-    description = "Discover Qpid Proton version"
-
-    @property
-    def compiler_type(self):
-        compiler = self.compiler
-        if compiler is None:
-            return get_default_compiler()
-        elif isinstance(compiler, str):
-            return compiler
-        else:
-            return compiler.compiler_type
-
-    def prepare_swig_wrap(self):
-        """Run swig against the sources.  This will cause swig to compile the
-        cproton.i file into a .c file called cproton_wrap.c, and create
-        cproton.py.
-        """
-        ext = self.distribution.ext_modules[-1]
-
-        if 'SWIG' in os.environ:
-            self.swig = os.environ['SWIG']
-
-        try:
-            # This will actually call swig to generate the files
-            # and list the sources.
-            self.swig_sources(ext.sources, ext)
-        except (errors.DistutilsExecError, errors.DistutilsPlatformError) as e:
-            if not (os.path.exists('cproton_wrap.c') or
-                    os.path.exists('cproton.py')):
-                raise e
-
-        # now remove the cproton.i file from the source list so we don't run
-        # swig again.
-        ext.sources = ext.sources[1:]
-        ext.swig_opts = []
-
-    def bundle_libqpid_proton_extension(self):
-        """The proper version of libqpid-proton is not present on the system,
-        so attempt to retrieve the proper libqpid-proton sources and
-        include them in the extension.
-        """
-        setup_path = os.path.dirname(os.path.realpath(__file__))
-        base = self.get_finalized_command('build').build_base
-        build_include = os.path.join(base, 'include')
-
-        log.info("Bundling qpid-proton into the extension")
-
-        # QPID_PROTON_SRC - (optional) pathname to the Proton C sources.  Can
-        # be used to override where this setup gets the Proton C sources from
-        # (see bundle.fetch_libqpid_proton())
-        if 'QPID_PROTON_SRC' not in os.environ:
-            if not os.path.exists(os.path.join(setup_path, 'CMakeLists.txt')):
-                bundledir = os.path.join(base, "bundled")
-                if not os.path.exists(bundledir):
-                    os.makedirs(bundledir)
-                bundle.fetch_libqpid_proton(bundledir)
-                libqpid_proton_dir = os.path.abspath(os.path.join(bundledir, 'qpid-proton'))
-            else:
-                # setup.py is being invoked from within the proton source tree
-                # (CMakeLists.txt is not present in the python source dist).
-                # In this case build using the local sources.  This use case is
-                # specifically for developers working on the proton source
-                # code.
-                proton_c = os.path.join(setup_path, '..', '..', '..')
-                libqpid_proton_dir = os.path.abspath(proton_c)
-        else:
-            libqpid_proton_dir = os.path.abspath(os.environ['QPID_PROTON_SRC'])
-
-        log.debug("Using libqpid-proton src: %s" % libqpid_proton_dir)
-
-        proton_base = os.path.join(libqpid_proton_dir, 'proton-c')
-        proton_src = os.path.join(proton_base, 'src')
-        proton_include = os.path.join(proton_base, 'include')
-
-        #
-        # Create any generated header files, and put them in build_include:
-        #
-        if not os.path.exists(build_include):
-            os.makedirs(build_include)
-            os.mkdir(os.path.join(build_include, 'proton'))
-
-        # Create copy of environment variables and modify PYTHONPATH to preserve
-        # all others environment variables defined by user. When `env` is specified
-        # Popen will not inherit environment variables of the current process.
-        proton_envs = os.environ.copy()
-        default_path = proton_envs.get('PYTHONPATH')
-        proton_envs['PYTHONPATH'] = proton_base if not default_path else '{0}{1}{2}'.format(
-            proton_base, os.pathsep, default_path)
-
-        # Generate `protocol.h` by calling the python
-        # script found in the source dir.
-        with open(os.path.join(build_include, 'protocol.h'), 'wb') as header:
-            subprocess.Popen([sys.executable, os.path.join(proton_src, 'protocol.h.py')],
-                              env=proton_envs, stdout=header)
-
-        # Generate `encodings.h` by calling the python
-        # script found in the source dir.
-        with open(os.path.join(build_include, 'encodings.h'), 'wb') as header:
-            subprocess.Popen([sys.executable, os.path.join(proton_src, 'encodings.h.py')],
-                              env=proton_envs, stdout=header)
-
-        # Create a custom, temporary, version.h file mapping the
-        # major and minor versions from the downloaded tarball. This version should
-        # match the ones in the bundle module
-        with open(os.path.join(build_include, 'proton', 'version.h'), "wb") as ver:
-            version_text = """
-#ifndef _PROTON_VERSION_H
-#define _PROTON_VERSION_H 1
-#define PN_VERSION_MAJOR %i
-#define PN_VERSION_MINOR %i
-#define PN_VERSION_POINT %i
-#endif /* version.h */
-""" % bundle.bundled_version
-            ver.write(version_text.encode('utf-8'))
-
-        # Collect all the Proton C files that need to be built.
-        # we could've used `glob(.., '*', '*.c')` but I preferred going
-        # with an explicit list of subdirs that we can control and expand
-        # depending on the version. Specifically, lets avoid adding things
-        # we don't need.
-
-        sources = []
-        for subdir in ['core', 'core/object', 'compiler',
-                       'extra', 'message', 'reactor', 'messenger', 'handlers',
-                       'platform', 'reactor/io/posix']:
-
-            sources.extend(glob.glob(os.path.join(proton_src, subdir, '*.c')))
-
-        sources.extend(filter(lambda x: not x.endswith('dump.c'),
-                       glob.iglob(os.path.join(proton_src, '*.c'))))
-
-        # Look for any optional libraries that proton needs, and adjust the
-        # source list and compile flags as necessary.
-        libraries = []
-
-        # -D flags (None means no value, just define)
-        macros=[('qpid_proton_EXPORTS', None),
-                ('USE_ATOLL', None),
-                ('USE_STRERROR_R', None)]
-
-        # Check whether openssl is installed by poking
-        # pkg-config for a minimum version 0. If it's installed, it should
-        # return True and we'll use it. Otherwise, we'll use the stub.
-        if misc.pkg_config_version(atleast='0', module='openssl'):
-            libraries += ['ssl', 'crypto']
-            sources.append(os.path.join(proton_src, 'ssl', 'openssl.c'))
-        else:
-            sources.append(os.path.join(proton_src, 'ssl', 'ssl_stub.c'))
-
-        # create a temp compiler to check for optional compile-time features
-        cc = new_compiler(compiler=self.compiler_type)
-        cc.output_dir = self.build_temp
-
-        # Some systems need to link to `rt`. Check whether `clock_gettime` is
-        # around and if librt is needed
-        if cc.has_function('clock_gettime'):
-            macros.append(('USE_CLOCK_GETTIME', None))
-        else:
-            if cc.has_function('clock_gettime', libraries=['rt']):
-                libraries.append('rt')
-                macros.append(('USE_CLOCK_GETTIME', None))
-
-        # 0.10 added an implementation for cyrus. Check
-        # if it is available before adding the implementation to the sources
-        # list. Eventually, `sasl.c` will be added and one of the existing
-        # implementations will be used.
-        if cc.has_function('sasl_client_done', includes=['sasl/sasl.h'],
-                           libraries=['sasl2']):
-            libraries.append('sasl2')
-            sources.append(os.path.join(proton_src, 'sasl', 'cyrus_sasl.c'))
-        else:
-            sources.append(os.path.join(proton_src, 'sasl', 'none_sasl.c'))
-
-        sources.append(os.path.join(proton_src, 'sasl', 'sasl.c'))
-
-        # compile all the proton sources.  We'll add the resulting list of
-        # objects to the _cproton extension as 'extra objects'.  We do this
-        # instead of just lumping all the sources into the extension to prevent
-        # any proton-specific compilation flags from affecting the compilation
-        # of the generated swig code
-
-        cc = new_compiler(compiler=self.compiler_type)
-        ds_sys.customize_compiler(cc)
-
-        objects = cc.compile(sources,
-                             macros=macros,
-                             include_dirs=[build_include,
-                                           proton_include,
-                                           proton_src],
-                             # compiler command line options:
-                             extra_postargs=['-std=gnu99'],
-                             output_dir=self.build_temp)
-
-        #
-        # Now update the _cproton extension instance to include the objects and
-        # libraries
-        #
-        _cproton = self.distribution.ext_modules[-1]
-        _cproton.extra_objects = objects
-        _cproton.include_dirs.append(build_include)
-        _cproton.include_dirs.append(proton_include)
-
-        # swig will need to access the proton headers:
-        _cproton.swig_opts.append('-I%s' % build_include)
-        _cproton.swig_opts.append('-I%s' % proton_include)
-
-        # lastly replace the libqpid-proton dependency with libraries required
-        # by the Proton objects:
-        _cproton.libraries=libraries
-
-    def check_qpid_proton_version(self):
-        """check the qpid_proton version"""
-
-        target_version = bundle.bundled_version_str
-        return (misc.pkg_config_version(max_version=target_version) and
-                misc.pkg_config_version(atleast=bundle.min_qpid_proton_str))
-
-    @property
-    def bundle_proton(self):
-        """Need to bundle proton if the conditions below are met."""
-        return ('QPID_PROTON_SRC' in os.environ) or \
-            (not self.check_qpid_proton_version())
-
-    def use_installed_proton(self):
-        """The Proton development headers and library are installed, update the
-        _cproton extension to tell it where to find the library and headers.
-        """
-        _cproton = self.distribution.ext_modules[-1]
-        incs = misc.pkg_config_get_var('includedir')
-        for i in incs.split():
-            _cproton.swig_opts.append('-I%s' % i)
-            _cproton.include_dirs.append(i)
-        ldirs = misc.pkg_config_get_var('libdir')
-        _cproton.library_dirs.extend(ldirs.split())
-
-    def run(self):
-        # check if the Proton library and headers are installed and are
-        # compatible with this version of the binding.
-        if self.bundle_proton:
-            # Proton not installed or compatible
-            self.bundle_libqpid_proton_extension()
-        else:
-            self.use_installed_proton()
-        self.prepare_swig_wrap()
-
-
-class CustomBuildOrder(build):
-    # The sole purpose of this class is to re-order
-    # the commands execution so that `build_ext` is executed *before*
-    # build_py. We need this to make sure `cproton.py` is generated
-    # before the python modules are collected. Otherwise, it won't
-    # be installed.
-    sub_commands = [
-        ('build_ext', build.has_ext_modules),
-        ('build_py', build.has_pure_modules),
-        ('build_clib', build.has_c_libraries),
-        ('build_scripts', build.has_scripts),
-    ]
-
-
-class CheckingBuildExt(build_ext):
-    """Subclass build_ext to build qpid-proton using `cmake`"""
-
-    def run(self):
-        # Discover qpid-proton in the system
-        self.distribution.run_command('configure')
-        build_ext.run(self)
-
-
-# Override `build_ext` and add `configure`
-cmdclass = {'configure': Configure,
-            'build': CustomBuildOrder,
-            'build_ext': CheckingBuildExt,
-            'sdist': CheckSDist}
-
-setup(name='python-qpid-proton',
-      version=bundle.bundled_version_str,
-      description='An AMQP based messaging library.',
-      author='Apache Qpid',
-      author_email='proton@qpid.apache.org',
-      url='http://qpid.apache.org/proton/',
-      packages=['proton'],
-      py_modules=['cproton'],
-      license="Apache Software License",
-      classifiers=["License :: OSI Approved :: Apache Software License",
-                   "Intended Audience :: Developers",
-                   "Programming Language :: Python",
-                   "Programming Language :: Python :: 2",
-                   "Programming Language :: Python :: 2.6",
-                   "Programming Language :: Python :: 2.7",
-                   "Programming Language :: Python :: 3",
-                   "Programming Language :: Python :: 3.3",
-                   "Programming Language :: Python :: 3.4",
-                   "Programming Language :: Python :: 3.5"],
-      cmdclass=cmdclass,
-      # Note well: the following extension instance is modified during the
-      # installation!  If you make changes below, you may need to update the
-      # Configure class above
-      ext_modules=[Extension('_cproton',
-                             sources=['cproton.i', 'cproton_wrap.c'],
-                             swig_opts=['-threads'],
-                             extra_compile_args=['-pthread'],
-                             libraries=['qpid-proton'])])

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/setup.py.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py.in b/proton-c/bindings/python/setup.py.in
new file mode 100755
index 0000000..57f4368
--- /dev/null
+++ b/proton-c/bindings/python/setup.py.in
@@ -0,0 +1,323 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+python-qpid-proton setup script
+
+DISCLAIMER: This script took lots of inspirations from PyZMQ, which is licensed
+under the 'MODIFIED BSD LICENSE'.
+
+Although inspired by the work in PyZMQ, this script and the modules it depends
+on were largely simplified to meet the requirements of the library.
+
+The behavior of this script is to build the registered `_cproton` extension
+using the installed Qpid Proton C library and header files. If the library and
+headers are not installed, or the installed version does not match the version
+of these python bindings, then the script will attempt to build the extension
+using the Proton C sources included in the python source distribution package.
+
+While the above removes the need of *always* having Qpid Proton C development
+files installed, it does not solve the need of having `swig` and the libraries
+qpid-proton requires installed to make this setup work.
+
+From the Python side, this scripts overrides 1 command - build_ext - and it adds a
+new one. The latter - Configure - is called from the former to setup/discover what's
+in the system. The rest of the comands and steps are done normally without any kind
+of monkey patching.
+"""
+
+import glob
+import os
+import subprocess
+import sys
+
+import distutils.spawn as ds_spawn
+import distutils.sysconfig as ds_sys
+from distutils.ccompiler import new_compiler, get_default_compiler
+from distutils.core import setup, Extension
+from distutils.command.build import build
+from distutils.command.build_ext import build_ext
+from distutils.command.sdist import sdist
+from distutils import errors
+
+from setuputils import log
+from setuputils import misc
+
+
+_PROTON_VERSION=(@PN_VERSION_MAJOR@,
+                 @PN_VERSION_MINOR@,
+                 @PN_VERSION_POINT@)
+_PROTON_VERSION_STR = "%d.%d.%d" % _PROTON_VERSION
+
+
+class CheckSDist(sdist):
+
+    def run(self):
+        self.distribution.run_command('configure')
+
+        # Append the source that was removed during
+        # the configuration step.
+        _cproton = self.distribution.ext_modules[-1]
+        _cproton.sources.append('cproton.i')
+
+        try:
+            sdist.run(self)
+        finally:
+            for src in ['cproton.py', 'cproton_wrap.c']:
+                if os.path.exists(src):
+                    os.remove(src)
+
+
+class Configure(build_ext):
+    description = "Discover Qpid Proton version"
+
+    @property
+    def compiler_type(self):
+        compiler = self.compiler
+        if compiler is None:
+            return get_default_compiler()
+        elif isinstance(compiler, str):
+            return compiler
+        else:
+            return compiler.compiler_type
+
+    def prepare_swig_wrap(self):
+        """Run swig against the sources.  This will cause swig to compile the
+        cproton.i file into a .c file called cproton_wrap.c, and create
+        cproton.py.
+        """
+        ext = self.distribution.ext_modules[-1]
+
+        if 'SWIG' in os.environ:
+            self.swig = os.environ['SWIG']
+
+        try:
+            # This will actually call swig to generate the files
+            # and list the sources.
+            self.swig_sources(ext.sources, ext)
+        except (errors.DistutilsExecError, errors.DistutilsPlatformError) as e:
+            if not (os.path.exists('cproton_wrap.c') or
+                    os.path.exists('cproton.py')):
+                raise e
+
+        # now remove the cproton.i file from the source list so we don't run
+        # swig again.
+        ext.sources = ext.sources[1:]
+        ext.swig_opts = []
+
+    def use_bundled_proton(self):
+        """The proper version of libqpid-proton is not installed on the system,
+        so use the included proton-c sources to build the extension
+        """
+        log.info("Building the bundled proton-c sources into the extension")
+
+        setup_path = os.path.dirname(os.path.realpath(__file__))
+        base = self.get_finalized_command('build').build_base
+        build_include = os.path.join(base, 'include')
+        proton_base = os.path.abspath(os.path.join(setup_path, 'proton-c'))
+        proton_src = os.path.join(proton_base, 'src')
+        proton_include = os.path.join(proton_base, 'include')
+
+        log.debug("Using Proton C sources: %s" % proton_base)
+
+        # Collect all the Proton C files that need to be built.
+        # we could've used `glob(.., '*', '*.c')` but I preferred going
+        # with an explicit list of subdirs that we can control and expand
+        # depending on the version. Specifically, lets avoid adding things
+        # we don't need.
+
+        sources = []
+        for subdir in ['core', 'core/object', 'compiler',
+                       'extra', 'message', 'reactor', 'messenger', 'handlers',
+                       'platform', 'reactor/io/posix']:
+
+            sources.extend(glob.glob(os.path.join(proton_src, subdir, '*.c')))
+
+        sources.extend(filter(lambda x: not x.endswith('dump.c'),
+                       glob.iglob(os.path.join(proton_src, '*.c'))))
+
+        # Look for any optional libraries that proton needs, and adjust the
+        # source list and compile flags as necessary.
+        libraries = []
+
+        # -D flags (None means no value, just define)
+        macros=[('qpid_proton_EXPORTS', None),
+                ('USE_ATOLL', None),
+                ('USE_STRERROR_R', None)]
+
+        # Check whether openssl is installed by poking
+        # pkg-config for a minimum version 0. If it's installed, it should
+        # return True and we'll use it. Otherwise, we'll use the stub.
+        if misc.pkg_config_version_installed('openssl', atleast='0'):
+            libraries += ['ssl', 'crypto']
+            sources.append(os.path.join(proton_src, 'ssl', 'openssl.c'))
+        else:
+            sources.append(os.path.join(proton_src, 'ssl', 'ssl_stub.c'))
+            log.warn("OpenSSL not installed - disabling SSL support!")
+
+        # create a temp compiler to check for optional compile-time features
+        cc = new_compiler(compiler=self.compiler_type)
+        cc.output_dir = self.build_temp
+
+        # Some systems need to link to `rt`. Check whether `clock_gettime` is
+        # around and if librt is needed
+        if cc.has_function('clock_gettime'):
+            macros.append(('USE_CLOCK_GETTIME', None))
+        else:
+            if cc.has_function('clock_gettime', libraries=['rt']):
+                libraries.append('rt')
+                macros.append(('USE_CLOCK_GETTIME', None))
+
+        # 0.10 added an implementation for cyrus. Check
+        # if it is available before adding the implementation to the sources
+        # list. Eventually, `sasl.c` will be added and one of the existing
+        # implementations will be used.
+        if cc.has_function('sasl_client_done', includes=['sasl/sasl.h'],
+                           libraries=['sasl2']):
+            libraries.append('sasl2')
+            sources.append(os.path.join(proton_src, 'sasl', 'cyrus_sasl.c'))
+        else:
+            sources.append(os.path.join(proton_src, 'sasl', 'none_sasl.c'))
+            log.warn("Cyrus SASL not installed - only the ANONYMOUS and"
+                     " PLAIN mechanisms will be supported!")
+        sources.append(os.path.join(proton_src, 'sasl', 'sasl.c'))
+
+        # compile all the proton sources.  We'll add the resulting list of
+        # objects to the _cproton extension as 'extra objects'.  We do this
+        # instead of just lumping all the sources into the extension to prevent
+        # any proton-specific compilation flags from affecting the compilation
+        # of the generated swig code
+
+        cc = new_compiler(compiler=self.compiler_type)
+        ds_sys.customize_compiler(cc)
+
+        objects = cc.compile(sources,
+                             macros=macros,
+                             include_dirs=[build_include,
+                                           proton_include,
+                                           proton_src],
+                             # compiler command line options:
+                             extra_postargs=['-std=gnu99'],
+                             output_dir=self.build_temp)
+
+        #
+        # Now update the _cproton extension instance passed to setup to include
+        # the objects and libraries
+        #
+        _cproton = self.distribution.ext_modules[-1]
+        _cproton.extra_objects = objects
+        _cproton.include_dirs.append(build_include)
+        _cproton.include_dirs.append(proton_include)
+
+        # swig will need to access the proton headers:
+        _cproton.swig_opts.append('-I%s' % build_include)
+        _cproton.swig_opts.append('-I%s' % proton_include)
+
+        # lastly replace the libqpid-proton dependency with libraries required
+        # by the Proton objects:
+        _cproton.libraries=libraries
+
+    def libqpid_proton_installed(self, version):
+        """Check to see if the proper version of the Proton development library
+        and headers are already installed
+        """
+        return misc.pkg_config_version_installed('libqpid-proton', version)
+
+    def use_installed_proton(self):
+        """The Proton development headers and library are installed, update the
+        _cproton extension to tell it where to find the library and headers.
+        """
+        # update the Extension instance passed to setup() to use the installed
+        # headers and link library
+        _cproton = self.distribution.ext_modules[-1]
+        incs = misc.pkg_config_get_var('libqpid-proton', 'includedir')
+        for i in incs.split():
+            _cproton.swig_opts.append('-I%s' % i)
+            _cproton.include_dirs.append(i)
+        ldirs = misc.pkg_config_get_var('libqpid-proton', 'libdir')
+        _cproton.library_dirs.extend(ldirs.split())
+
+    def run(self):
+        # check if the Proton library and headers are installed and are
+        # compatible with this version of the binding.
+        if self.libqpid_proton_installed(_PROTON_VERSION_STR):
+            self.use_installed_proton()
+        else:
+            # Proton not installed or compatible, use bundled proton-c sources
+            self.use_bundled_proton()
+        self.prepare_swig_wrap()
+
+
+class CustomBuildOrder(build):
+    # The sole purpose of this class is to re-order
+    # the commands execution so that `build_ext` is executed *before*
+    # build_py. We need this to make sure `cproton.py` is generated
+    # before the python modules are collected. Otherwise, it won't
+    # be installed.
+    sub_commands = [
+        ('build_ext', build.has_ext_modules),
+        ('build_py', build.has_pure_modules),
+        ('build_clib', build.has_c_libraries),
+        ('build_scripts', build.has_scripts),
+    ]
+
+
+class CheckingBuildExt(build_ext):
+    """Subclass build_ext to build qpid-proton using `cmake`"""
+
+    def run(self):
+        # Discover qpid-proton in the system
+        self.distribution.run_command('configure')
+        build_ext.run(self)
+
+
+# Override `build_ext` and add `configure`
+cmdclass = {'configure': Configure,
+            'build': CustomBuildOrder,
+            'build_ext': CheckingBuildExt,
+            'sdist': CheckSDist}
+
+setup(name='python-qpid-proton',
+      version=_PROTON_VERSION_STR + os.environ.get('PROTON_VERSION_SUFFIX', ''),
+      description='An AMQP based messaging library.',
+      author='Apache Qpid',
+      author_email='proton@qpid.apache.org',
+      url='http://qpid.apache.org/proton/',
+      packages=['proton'],
+      py_modules=['cproton'],
+      license="Apache Software License",
+      classifiers=["License :: OSI Approved :: Apache Software License",
+                   "Intended Audience :: Developers",
+                   "Programming Language :: Python",
+                   "Programming Language :: Python :: 2",
+                   "Programming Language :: Python :: 2.6",
+                   "Programming Language :: Python :: 2.7",
+                   "Programming Language :: Python :: 3",
+                   "Programming Language :: Python :: 3.3",
+                   "Programming Language :: Python :: 3.4",
+                   "Programming Language :: Python :: 3.5"],
+      cmdclass=cmdclass,
+      # Note well: the following extension instance is modified during the
+      # installation!  If you make changes below, you may need to update the
+      # Configure class above
+      ext_modules=[Extension('_cproton',
+                             sources=['cproton.i', 'cproton_wrap.c'],
+                             swig_opts=['-threads'],
+                             extra_compile_args=['-pthread'],
+                             libraries=['qpid-proton'])])

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/setuputils/bundle.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setuputils/bundle.py b/proton-c/bindings/python/setuputils/bundle.py
deleted file mode 100644
index 1bf3450..0000000
--- a/proton-c/bindings/python/setuputils/bundle.py
+++ /dev/null
@@ -1,92 +0,0 @@
-#-----------------------------------------------------------------------------
-#  Copyright (C) PyZMQ Developers
-#  Distributed under the terms of the Modified BSD License.
-#
-#  This bundling code is largely adapted from pyzmq-static's get.sh by
-#  Brandon Craig-Rhodes, which is itself BSD licensed.
-#-----------------------------------------------------------------------------
-
-#-----------------------------------------------------------------------------
-#  This bundling code is largely adapted from pyzmq's code
-#  PyZMQ Developers, which is itself Modified BSD licensed.
-#-----------------------------------------------------------------------------
-
-import os
-import shutil
-import stat
-import sys
-import tarfile
-from glob import glob
-from subprocess import Popen, PIPE
-
-try:
-    # py2
-    from urllib2 import urlopen
-except ImportError:
-    # py3
-    from urllib.request import urlopen
-
-from . import log
-
-
-#-----------------------------------------------------------------------------
-# Constants
-#-----------------------------------------------------------------------------
-min_qpid_proton = (0, 16, 0)
-min_qpid_proton_str = "%i.%i.%i" % min_qpid_proton
-
-bundled_version = (0, 16, 0)
-bundled_version_str = "%i.%i.%i" % bundled_version
-libqpid_proton = "qpid-proton-%s.tar.gz" % bundled_version_str
-libqpid_proton_url = ("http://www.apache.org/dist/qpid/proton/%s/%s" %
-                      (bundled_version_str, libqpid_proton))
-
-HERE = os.path.dirname(__file__)
-ROOT = os.path.dirname(HERE)
-
-
-def fetch_archive(savedir, url, fname):
-    """Download an archive to a specific location
-
-    :param savedir: Destination dir
-    :param url: URL where the archive should be downloaded from
-    :param fname: Archive's filename
-    """
-    dest = os.path.join(savedir, fname)
-
-    if os.path.exists(dest):
-        log.info("already have %s" % fname)
-        return dest
-
-    log.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_libqpid_proton(savedir):
-    """Download qpid-proton to `savedir`."""
-    def _c_only(members):
-        # just extract the files necessary to build the shared library
-        for tarinfo in members:
-            npath = os.path.normpath(tarinfo.name)
-            if ("proton-c/src" in npath or
-                "proton-c/include" in npath or
-                "proton-c/mllib" in npath):
-                yield tarinfo
-    dest = os.path.join(savedir, 'qpid-proton')
-    if os.path.exists(dest):
-        log.info("already have %s" % dest)
-        return
-    fname = fetch_archive(savedir, libqpid_proton_url, libqpid_proton)
-    tf = tarfile.open(fname)
-    member = tf.firstmember.path
-    if member == '.':
-        member = tf.getmembers()[1].path
-    with_version = os.path.join(savedir, member)
-    tf.extractall(savedir, members=_c_only(tf))
-    tf.close()
-    shutil.move(with_version, dest)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/setuputils/misc.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setuputils/misc.py b/proton-c/bindings/python/setuputils/misc.py
index b1864a0..54a8fde 100644
--- a/proton-c/bindings/python/setuputils/misc.py
+++ b/proton-c/bindings/python/setuputils/misc.py
@@ -40,39 +40,43 @@ def _call_pkg_config(args):
 
 
 
-def pkg_config_version(atleast=None, max_version=None, module='libqpid-proton'):
-    """Check the qpid_proton version using pkg-config
+def pkg_config_version_installed(package, version=None, atleast=None):
+    """Check if version of a package is is installed
 
     This function returns True/False depending on whether
-    the library is found and atleast/max_version are met.
+    the package is found and is the correct version.
 
-    :param atleast: The minimum required version
-    :param max_version: The maximum supported version. This
-        basically represents the target version.
+    :param version: The exact version of the package required
+    :param atleast: True if installed package is at least this version
     """
 
-    if atleast and max_version:
-        log.fatal('Specify either atleast or max_version')
+    if version is None and atleast is None:
+        log.fatal('package version string required')
+    elif version and atleast:
+        log.fatal('Specify either version or atleast, not both')
 
-    p = _call_pkg_config(['--%s-version=%s' % (atleast and 'atleast' or 'max',
-                                               atleast or max_version),
-                          module])
+    check = 'exact' if version else 'atleast'
+    p = _call_pkg_config(['--%s-version=%s' % (check,
+                                               version or atleast),
+                          package])
     if p:
         out,err = p.communicate()
         if p.returncode:
-            log.info("Did not find %s via pkg-config: %s" % (module, err))
+            log.info("Did not find %s via pkg-config: %s" % (package, err))
             return False
-        log.info("Using %s (found via pkg-config)." % module)
+        log.info("Using %s version %s (found via pkg-config)" %
+                 (package,
+                  _call_pkg_config(['--modversion', package]).communicate()[0]))
         return True
     return False
 
 
-def pkg_config_get_var(name, module='libqpid-proton'):
-    """Retrieve the value of the named module variable as a string
+def pkg_config_get_var(package, name):
+    """Retrieve the value of the named package variable as a string
     """
-    p = _call_pkg_config(['--variable=%s' % name, module])
+    p = _call_pkg_config(['--variable=%s' % name, package])
     if not p:
-        log.warn("pkg-config: var %s get failed, package %s", name, module)
+        log.warn("pkg-config: var %s get failed, package %s", name, package)
         return ""
     out,err = p.communicate()
     if p.returncode:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/tox.ini.in
----------------------------------------------------------------------
diff --git a/proton-c/tox.ini.in b/proton-c/tox.ini.in
index 7a9c8eb..2a6b09d 100644
--- a/proton-c/tox.ini.in
+++ b/proton-c/tox.ini.in
@@ -2,14 +2,13 @@
 envlist = py26,py27,py33,py34,py35
 minversion = 1.4
 skipdist = True
-setupdir = @py_src@
+setupdir = @py_bin@/dist
 
 [testenv]
 usedevelop = False
 setenv =
     VIRTUAL_ENV={envdir}
     DEBUG=True
-    QPID_PROTON_SRC=@CMAKE_SOURCE_DIR@
 passenv =
     PKG_CONFIG_PATH
     CFLAGS


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org