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