| # Copyright 2015 The Brotli Authors. All rights reserved. |
| # |
| # Distributed under MIT license. |
| # See file LICENSE for detail or copy at https://opensource.org/licenses/MIT |
| |
| import os |
| import platform |
| import re |
| import unittest |
| |
| try: |
| from setuptools import Extension |
| from setuptools import setup |
| except: |
| from distutils.core import Extension |
| from distutils.core import setup |
| from distutils.command.build_ext import build_ext |
| from distutils import errors |
| from distutils import dep_util |
| from distutils import log |
| |
| |
| CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) |
| |
| |
| def read_define(path, macro): |
| """ Return macro value from the given file. """ |
| with open(path, 'r') as f: |
| for line in f: |
| m = re.match(rf'#define\s{macro}\s+(.+)', line) |
| if m: |
| return m.group(1) |
| return '' |
| |
| |
| def get_version(): |
| """ Return library version string from 'common/version.h' file. """ |
| version_file_path = os.path.join(CURR_DIR, 'c', 'common', 'version.h') |
| major = read_define(version_file_path, 'BROTLI_VERSION_MAJOR') |
| minor = read_define(version_file_path, 'BROTLI_VERSION_MINOR') |
| patch = read_define(version_file_path, 'BROTLI_VERSION_PATCH') |
| if not major or not minor or not patch: |
| return '' |
| return f'{major}.{minor}.{patch}' |
| |
| |
| def get_test_suite(): |
| test_loader = unittest.TestLoader() |
| test_suite = test_loader.discover('python', pattern='*_test.py') |
| return test_suite |
| |
| |
| class BuildExt(build_ext): |
| |
| def get_source_files(self): |
| filenames = build_ext.get_source_files(self) |
| for ext in self.extensions: |
| filenames.extend(ext.depends) |
| return filenames |
| |
| def build_extension(self, ext): |
| if ext.sources is None or not isinstance(ext.sources, (list, tuple)): |
| raise errors.DistutilsSetupError( |
| "in 'ext_modules' option (extension '%s'), " |
| "'sources' must be present and must be " |
| "a list of source filenames" % ext.name) |
| |
| ext_path = self.get_ext_fullpath(ext.name) |
| depends = ext.sources + ext.depends |
| if not (self.force or dep_util.newer_group(depends, ext_path, 'newer')): |
| log.debug("skipping '%s' extension (up-to-date)", ext.name) |
| return |
| else: |
| log.info("building '%s' extension", ext.name) |
| |
| c_sources = [] |
| for source in ext.sources: |
| if source.endswith('.c'): |
| c_sources.append(source) |
| extra_args = ext.extra_compile_args or [] |
| |
| objects = [] |
| |
| macros = ext.define_macros[:] |
| if platform.system() == 'Darwin': |
| macros.append(('OS_MACOSX', '1')) |
| elif self.compiler.compiler_type == 'mingw32': |
| # On Windows Python 2.7, pyconfig.h defines "hypot" as "_hypot", |
| # This clashes with GCC's cmath, and causes compilation errors when |
| # building under MinGW: http://bugs.python.org/issue11566 |
| macros.append(('_hypot', 'hypot')) |
| for undef in ext.undef_macros: |
| macros.append((undef,)) |
| |
| objs = self.compiler.compile( |
| c_sources, |
| output_dir=self.build_temp, |
| macros=macros, |
| include_dirs=ext.include_dirs, |
| debug=self.debug, |
| extra_postargs=extra_args, |
| depends=ext.depends) |
| objects.extend(objs) |
| |
| self._built_objects = objects[:] |
| if ext.extra_objects: |
| objects.extend(ext.extra_objects) |
| extra_args = ext.extra_link_args or [] |
| # when using GCC on Windows, we statically link libgcc and libstdc++, |
| # so that we don't need to package extra DLLs |
| if self.compiler.compiler_type == 'mingw32': |
| extra_args.extend(['-static-libgcc', '-static-libstdc++']) |
| |
| ext_path = self.get_ext_fullpath(ext.name) |
| # Detect target language, if not provided |
| language = ext.language or self.compiler.detect_language(c_sources) |
| |
| self.compiler.link_shared_object( |
| objects, |
| ext_path, |
| libraries=self.get_libraries(ext), |
| library_dirs=ext.library_dirs, |
| runtime_library_dirs=ext.runtime_library_dirs, |
| extra_postargs=extra_args, |
| export_symbols=self.get_export_symbols(ext), |
| debug=self.debug, |
| build_temp=self.build_temp, |
| target_lang=language) |
| |
| |
| NAME = 'Brotli' |
| |
| VERSION = get_version() |
| |
| URL = 'https://github.com/google/brotli' |
| |
| DESCRIPTION = 'Python bindings for the Brotli compression library' |
| |
| AUTHOR = 'The Brotli Authors' |
| |
| LICENSE = 'MIT' |
| |
| PLATFORMS = ['Posix', 'MacOS X', 'Windows'] |
| |
| CLASSIFIERS = [ |
| 'Development Status :: 4 - Beta', |
| 'Environment :: Console', |
| 'Intended Audience :: Developers', |
| 'License :: OSI Approved :: MIT License', |
| 'Operating System :: MacOS :: MacOS X', |
| 'Operating System :: Microsoft :: Windows', |
| 'Operating System :: POSIX :: Linux', |
| 'Programming Language :: C', |
| 'Programming Language :: C++', |
| 'Programming Language :: Python', |
| 'Programming Language :: Python :: 2', |
| 'Programming Language :: Python :: 2.7', |
| 'Programming Language :: Python :: 3', |
| 'Programming Language :: Python :: 3.3', |
| 'Programming Language :: Python :: 3.4', |
| 'Programming Language :: Python :: 3.5', |
| 'Programming Language :: Unix Shell', |
| 'Topic :: Software Development :: Libraries', |
| 'Topic :: Software Development :: Libraries :: Python Modules', |
| 'Topic :: System :: Archiving', |
| 'Topic :: System :: Archiving :: Compression', |
| 'Topic :: Text Processing :: Fonts', |
| 'Topic :: Utilities', |
| ] |
| |
| PACKAGE_DIR = {'': 'python'} |
| |
| PY_MODULES = ['brotli'] |
| |
| EXT_MODULES = [ |
| Extension( |
| '_brotli', |
| sources=[ |
| 'python/_brotli.c', |
| 'c/common/constants.c', |
| 'c/common/context.c', |
| 'c/common/dictionary.c', |
| 'c/common/platform.c', |
| 'c/common/shared_dictionary.c', |
| 'c/common/transform.c', |
| 'c/dec/bit_reader.c', |
| 'c/dec/decode.c', |
| 'c/dec/huffman.c', |
| 'c/dec/state.c', |
| 'c/enc/backward_references.c', |
| 'c/enc/backward_references_hq.c', |
| 'c/enc/bit_cost.c', |
| 'c/enc/block_splitter.c', |
| 'c/enc/brotli_bit_stream.c', |
| 'c/enc/cluster.c', |
| 'c/enc/command.c', |
| 'c/enc/compound_dictionary.c', |
| 'c/enc/compress_fragment.c', |
| 'c/enc/compress_fragment_two_pass.c', |
| 'c/enc/dictionary_hash.c', |
| 'c/enc/encode.c', |
| 'c/enc/encoder_dict.c', |
| 'c/enc/entropy_encode.c', |
| 'c/enc/fast_log.c', |
| 'c/enc/histogram.c', |
| 'c/enc/literal_cost.c', |
| 'c/enc/memory.c', |
| 'c/enc/metablock.c', |
| 'c/enc/static_dict.c', |
| 'c/enc/utf8_util.c', |
| ], |
| depends=[ |
| 'c/common/constants.h', |
| 'c/common/context.h', |
| 'c/common/dictionary.h', |
| 'c/common/platform.h', |
| 'c/common/shared_dictionary_internal.h', |
| 'c/common/transform.h', |
| 'c/common/version.h', |
| 'c/dec/bit_reader.h', |
| 'c/dec/huffman.h', |
| 'c/dec/prefix.h', |
| 'c/dec/state.h', |
| 'c/enc/backward_references.h', |
| 'c/enc/backward_references_hq.h', |
| 'c/enc/backward_references_inc.h', |
| 'c/enc/bit_cost.h', |
| 'c/enc/bit_cost_inc.h', |
| 'c/enc/block_encoder_inc.h', |
| 'c/enc/block_splitter.h', |
| 'c/enc/block_splitter_inc.h', |
| 'c/enc/brotli_bit_stream.h', |
| 'c/enc/cluster.h', |
| 'c/enc/cluster_inc.h', |
| 'c/enc/command.h', |
| 'c/enc/compound_dictionary.h', |
| 'c/enc/compress_fragment.h', |
| 'c/enc/compress_fragment_two_pass.h', |
| 'c/enc/dictionary_hash.h', |
| 'c/enc/encoder_dict.h', |
| 'c/enc/entropy_encode.h', |
| 'c/enc/entropy_encode_static.h', |
| 'c/enc/fast_log.h', |
| 'c/enc/find_match_length.h', |
| 'c/enc/hash.h', |
| 'c/enc/hash_composite_inc.h', |
| 'c/enc/hash_forgetful_chain_inc.h', |
| 'c/enc/hash_longest_match64_inc.h', |
| 'c/enc/hash_longest_match_inc.h', |
| 'c/enc/hash_longest_match_quickly_inc.h', |
| 'c/enc/hash_rolling_inc.h', |
| 'c/enc/hash_to_binary_tree_inc.h', |
| 'c/enc/histogram.h', |
| 'c/enc/histogram_inc.h', |
| 'c/enc/literal_cost.h', |
| 'c/enc/memory.h', |
| 'c/enc/metablock.h', |
| 'c/enc/metablock_inc.h', |
| 'c/enc/params.h', |
| 'c/enc/prefix.h', |
| 'c/enc/quality.h', |
| 'c/enc/ringbuffer.h', |
| 'c/enc/static_dict.h', |
| 'c/enc/static_dict_lut.h', |
| 'c/enc/utf8_util.h', |
| 'c/enc/write_bits.h', |
| ], |
| include_dirs=[ |
| 'c/include', |
| ]), |
| ] |
| |
| TEST_SUITE = 'setup.get_test_suite' |
| |
| CMD_CLASS = { |
| 'build_ext': BuildExt, |
| } |
| |
| setup( |
| name=NAME, |
| description=DESCRIPTION, |
| version=VERSION, |
| url=URL, |
| author=AUTHOR, |
| license=LICENSE, |
| platforms=PLATFORMS, |
| classifiers=CLASSIFIERS, |
| package_dir=PACKAGE_DIR, |
| py_modules=PY_MODULES, |
| ext_modules=EXT_MODULES, |
| test_suite=TEST_SUITE, |
| cmdclass=CMD_CLASS) |