def bundle_libqpid_proton_extension(self): bundledir = "bundled" ext_modules = self.distribution.ext_modules log.info("Using bundled libqpid-proton") if not os.path.exists(bundledir): os.makedirs(bundledir) bundle.fetch_libqpid_proton(bundledir) libqpid_proton_dir = os.path.join(bundledir, 'qpid-proton') # NOTE(flaper87): Find prefix. We need to run make ourselves libqpid_proton = Extension( 'cmake_cproton', sources = [libqpid_proton_dir], # NOTE(flaper87): Disable all bindings, set the prefix to whatever # is in `distutils.sysconfig.PREFIX` and finally, disable testing # as well. The python binding will be built by this script later # on. Don't let cmake do it. extra_compile_args = ['-DCMAKE_INSTALL_PREFIX:PATH=%s' % ds_sys.PREFIX, '-DBUILD_PYTHON=False', '-DBUILD_JAVA=False', '-DBUILD_PERL=False', '-DBUILD_RUBY=False', '-DBUILD_PHP=False', '-DBUILD_JAVASCRIPT=False', '-DBUILD_TESTING=False', ] ) # NOTE(flaper87): Register this new extension and make # sure it's built and installed *before* `_cproton`. self.distribution.ext_modules.insert(0, libqpid_proton)
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, 'tox.ini')): 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: # This should happen just in **dev** environemnts since # tox.ini is not shipped with the driver. It should only # be triggered when calling `setup.py`. This can happen either # manually or when calling `tox` in the **sdist** step. Tox will # defined the `QPID_PROTON_SRC` itself. proton_c = os.path.join(setup_path, 'qpid-proton') 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')) # 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={'PYTHONPATH': proton_base}, 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, 'codec', 'encodings.h.py')], env={'PYTHONPATH': proton_base}, stdout=header) # Create a custom, temporary, version.h file mapping the # major and minor versions from the downloaded tarbal. 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 #endif /* version.h */ """ % bundle.min_qpid_proton 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 ['object', 'framing', 'codec', 'dispatcher', 'engine', 'events', 'transport', 'message', 'reactor', 'messenger', 'handlers', '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 as necessary. libraries = [] # 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_getttime` is around # and if not, link on rt. if not cc.has_function('clock_getttime'): libraries.append('rt') # 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, # -D flags (None means no value, just define) macros=[('qpid_proton_EXPORTS', None), ('USE_ATOLL', None), ('USE_CLOCK_GETTIME', None), ('USE_STRERROR_R', None)], 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 bundle_libqpid_proton_extension(self): base = self.get_finalized_command('build').build_base build_include = os.path.join(base, 'include') install = self.get_finalized_command('install').install_base install_lib = self.get_finalized_command('install').install_lib ext_modules = self.distribution.ext_modules log.info("Using bundled libqpid-proton") if 'QPID_PROTON_SRC' not in os.environ: 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: 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') if not os.path.exists(build_include): os.makedirs(build_include) os.mkdir(os.path.join(build_include, 'proton')) # 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={'PYTHONPATH': proton_base}, 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, 'codec', 'encodings.h.py')], env={'PYTHONPATH': proton_base}, stdout=header) # Create a custom, temporary, version.h file mapping the # major and minor versions from the downloaded tarbal. 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 #endif /* version.h */ """ % bundle.min_qpid_proton ver.write(version_text) # Collect all the 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 = [] libraries = [] extra_compile_args = [ '-std=gnu99', '-Dqpid_proton_EXPORTS', '-DUSE_ATOLL', '-DUSE_CLOCK_GETTIME', '-DUSE_STRERROR_R', ] for subdir in ['object', 'framing', 'codec', 'dispatcher', 'engine', 'events', 'transport', 'message', 'reactor', 'messenger', 'handlers', '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')))) # 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')) cc = new_compiler(compiler=self.compiler_type) cc.output_dir = self.build_temp # Some systems need to link to # `rt`. Check whether `clock_getttime` is around # and if not, link on rt. if not cc.has_function('clock_getttime'): libraries.append('rt') # 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')) # Create an extension for the bundled qpid-proton # library and let distutils do the build step for us. # This is not the `swig` library... What's going to be built by this # `Extension` is qpid-proton itself. For the swig library, pls, see the # dependencies in the `setup` function call and how it's extended further # down this method. libqpid_proton = Extension( 'libqpid-proton', # List of `.c` files that will be compiled. # `sources` is defined earlier on in this method and it's mostly # filled dynamically except for a few cases where files are added # depending on the presence of some libraries. sources=sources, # Libraries that need to be linked to should # be added to this list. `libraries` is defined earlier on # in this same method and it's filled depending on some # conditions. You'll find comments on each of those. libraries=libraries, # Changes to this list should be rare. # However, this is where new headers' dirs are added. # This list translates to `-I....` flags. include_dirs=[build_include, proton_src, proton_include], # If you need to add a default flag, this is # the place. All these compile arguments will be appended to # the GCC command. This list of flags is not used during the # linking phase. extra_compile_args = extra_compile_args, # If you need to add flags to the linking phase # this is the right place to do it. Just like the compile flags, # this is a list of flags that will be appended to the link # command. extra_link_args = [] ) # Extend the `swig` module `Extension` and add a few # extra options. For instance, we'll add new library dirs where `swig` # should look for headers and libraries. In addition to this, we'll # also append a `runtime path` where the qpid-proton library for this # swig extension should be looked up from whenever the proton bindings # are imported. We need this because the library will live in the # site-packages along with the proton bindings instead of being in the # common places like `/usr/lib` or `/usr/local/lib`. # # This is not the place where you'd add "default" flags. If you need to # add flags like `-thread` please read the `setup` function call at the # bottom of this file and see the examples there. _cproton = self.distribution.ext_modules[-1] _cproton.library_dirs.append(self.build_lib) _cproton.include_dirs.append(proton_include) _cproton.include_dirs.append(build_include) _cproton.include_dirs.append(os.path.join(proton_src, 'bindings', 'python')) _cproton.swig_opts.append('-I%s' % build_include) _cproton.swig_opts.append('-I%s' % proton_include) _cproton.runtime_library_dirs.extend([install_lib]) # Register this new extension and make # sure it's built and installed *before* `_cproton`. self.distribution.ext_modules.insert(0, libqpid_proton)