brotli/setup.py

290 lines
9.2 KiB
Python
Raw Normal View History

2016-09-28 19:19:49 +00:00
# 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:
2016-09-28 19:19:49 +00:00
from setuptools import Extension
from setuptools import setup
except:
2016-09-28 19:19:49 +00:00
from distutils.core import Extension
from distutils.core import setup
2014-11-20 12:16:26 +00:00
from distutils.command.build_ext import build_ext
disable buidling/deployment of python wheels (#583) * [appveyor] remove 'deploy' stage; only test python 2.7 and 3.6 all the other python versions are being built and tested on https://github.com/google/brotli-wheels/blob/d571d63/appveyor.yml * remove terrify submodule as not needed any more * [travis] just test py2.7 and 3.6 on linux; remove extra osx python builds All the other python versions for OSX are being built/tested on: https://github.com/google/brotli-wheels/blob/d571d63/.travis.yml Also, there's no need to build and deploy wheels here, as that's done in the separate repository. * [setup.py] only rebuild if dependency are newer; fix typo in list of 'depends' https://github.com/python/cpython/blob/v3.6.2/Lib/distutils/command/build_ext.py#L485-L500 * [ci] only run 'python setup.py test' if we run 'python setup.py built test', the setuptools 'test' command will forcibly re-run the build_ext subcommand because it wants to pass the --inplace option (it ignores whether it's up to date, just re-runs it all the time). with this we go from running built_ext twice, to running it only once per build * [Makefile] run 'build_ext --inplace' instead of 'develop' as default target The 'develop' command is like 'install' in the sense that it modifies the user's python environment. The default make target should be less intrusive, i.e. just building the extension module in-place without modify anything in the user's environment. We don't need to tell make about the dependency between 'test' and 'build' target as that is baked in the `python setup.py test` command. * [Makefile] add 'develop' target; remove unnecessary 'tests' target `make test` is good enough * [Makefile] `setup.py test` requires setuptools; run `python -m unittest` This will work even if setuptools is not installed, which is unlikely nowadays but still our `setup.py` works with plain distutils, so we may well have our tests work without setuptools. * [python/README.md] add ref to 'develop' target; remove 'tests', just 'make test' * [setup.py] import modules as per nicksay's comment https://github.com/google/brotli/pull/583#discussion_r131981049 * [Makefile] add 'develop' to .PHONY targets remove 'tests' from .PHONY * [appveyor] remove unused setup scripts We don't need to install custom python versions, we are using the pre-installed ones on Appveyor. * [appveyor] remove unneeded setup code
2017-08-23 18:45:13 +00:00
from distutils import errors
from distutils import dep_util
from distutils import log
2014-11-20 12:16:26 +00:00
2015-03-30 09:20:50 +00:00
CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
def get_version():
2016-08-22 13:44:12 +00:00
""" Return BROTLI_VERSION string as defined in 'common/version.h' file. """
version_file_path = os.path.join(CURR_DIR, 'c', 'common', 'version.h')
2016-08-22 13:44:12 +00:00
version = 0
2016-09-28 19:19:49 +00:00
with open(version_file_path, 'r') as f:
for line in f:
2016-08-22 13:59:08 +00:00
m = re.match(r'#define\sBROTLI_VERSION\s+0x([0-9a-fA-F]+)', line)
if m:
2016-08-22 13:44:12 +00:00
version = int(m.group(1), 16)
if version == 0:
2016-09-28 19:19:49 +00:00
return ''
# Semantic version is calculated as (MAJOR << 24) | (MINOR << 12) | PATCH.
major = version >> 24
minor = (version >> 12) & 0xFFF
patch = version & 0xFFF
return '{0}.{1}.{2}'.format(major, minor, patch)
def get_test_suite():
test_loader = unittest.TestLoader()
test_suite = test_loader.discover('python', pattern='*_test.py')
return test_suite
2015-03-30 09:20:50 +00:00
2014-11-20 12:16:26 +00:00
class BuildExt(build_ext):
2016-09-28 19:19:49 +00:00
2014-11-20 12:16:26 +00:00
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):
disable buidling/deployment of python wheels (#583) * [appveyor] remove 'deploy' stage; only test python 2.7 and 3.6 all the other python versions are being built and tested on https://github.com/google/brotli-wheels/blob/d571d63/appveyor.yml * remove terrify submodule as not needed any more * [travis] just test py2.7 and 3.6 on linux; remove extra osx python builds All the other python versions for OSX are being built/tested on: https://github.com/google/brotli-wheels/blob/d571d63/.travis.yml Also, there's no need to build and deploy wheels here, as that's done in the separate repository. * [setup.py] only rebuild if dependency are newer; fix typo in list of 'depends' https://github.com/python/cpython/blob/v3.6.2/Lib/distutils/command/build_ext.py#L485-L500 * [ci] only run 'python setup.py test' if we run 'python setup.py built test', the setuptools 'test' command will forcibly re-run the build_ext subcommand because it wants to pass the --inplace option (it ignores whether it's up to date, just re-runs it all the time). with this we go from running built_ext twice, to running it only once per build * [Makefile] run 'build_ext --inplace' instead of 'develop' as default target The 'develop' command is like 'install' in the sense that it modifies the user's python environment. The default make target should be less intrusive, i.e. just building the extension module in-place without modify anything in the user's environment. We don't need to tell make about the dependency between 'test' and 'build' target as that is baked in the `python setup.py test` command. * [Makefile] add 'develop' target; remove unnecessary 'tests' target `make test` is good enough * [Makefile] `setup.py test` requires setuptools; run `python -m unittest` This will work even if setuptools is not installed, which is unlikely nowadays but still our `setup.py` works with plain distutils, so we may well have our tests work without setuptools. * [python/README.md] add ref to 'develop' target; remove 'tests', just 'make test' * [setup.py] import modules as per nicksay's comment https://github.com/google/brotli/pull/583#discussion_r131981049 * [Makefile] add 'develop' to .PHONY targets remove 'tests' from .PHONY * [appveyor] remove unused setup scripts We don't need to install custom python versions, we are using the pre-installed ones on Appveyor. * [appveyor] remove unneeded setup code
2017-08-23 18:45:13 +00:00
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)
2014-11-20 12:16:26 +00:00
c_sources = []
for source in ext.sources:
2016-09-28 19:19:49 +00:00
if source.endswith('.c'):
2014-11-20 12:16:26 +00:00
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)
2014-11-20 12:16:26 +00:00
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
2016-09-28 19:19:49 +00:00
if self.compiler.compiler_type == 'mingw32':
extra_args.extend(['-static-libgcc', '-static-libstdc++'])
2014-11-20 12:16:26 +00:00
ext_path = self.get_ext_fullpath(ext.name)
# Detect target language, if not provided
language = ext.language or self.compiler.detect_language(c_sources)
2014-11-20 12:16:26 +00:00
self.compiler.link_shared_object(
2016-09-28 19:19:49 +00:00
objects,
ext_path,
2014-11-20 12:16:26 +00:00
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)
2016-09-28 19:19:49 +00:00
NAME = 'Brotli'
VERSION = get_version()
URL = 'https://github.com/google/brotli'
DESCRIPTION = 'Python bindings for the Brotli compression library'
AUTHOR = 'The Brotli Authors'
2019-08-16 14:32:14 +00:00
LICENSE = 'MIT'
2016-09-28 19:19:49 +00:00
PLATFORMS = ['Posix', 'MacOS X', 'Windows']
CLASSIFIERS = [
'Development Status :: 4 - Beta',
'Environment :: Console',
'Intended Audience :: Developers',
2019-08-16 14:32:14 +00:00
'License :: OSI Approved :: MIT License',
2016-09-28 19:19:49 +00:00
'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']
2016-09-28 19:19:49 +00:00
EXT_MODULES = [
Extension(
'_brotli',
2016-09-28 19:19:49 +00:00
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',
2015-10-06 11:23:57 +00:00
],
2016-09-28 19:19:49 +00:00
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',
disable buidling/deployment of python wheels (#583) * [appveyor] remove 'deploy' stage; only test python 2.7 and 3.6 all the other python versions are being built and tested on https://github.com/google/brotli-wheels/blob/d571d63/appveyor.yml * remove terrify submodule as not needed any more * [travis] just test py2.7 and 3.6 on linux; remove extra osx python builds All the other python versions for OSX are being built/tested on: https://github.com/google/brotli-wheels/blob/d571d63/.travis.yml Also, there's no need to build and deploy wheels here, as that's done in the separate repository. * [setup.py] only rebuild if dependency are newer; fix typo in list of 'depends' https://github.com/python/cpython/blob/v3.6.2/Lib/distutils/command/build_ext.py#L485-L500 * [ci] only run 'python setup.py test' if we run 'python setup.py built test', the setuptools 'test' command will forcibly re-run the build_ext subcommand because it wants to pass the --inplace option (it ignores whether it's up to date, just re-runs it all the time). with this we go from running built_ext twice, to running it only once per build * [Makefile] run 'build_ext --inplace' instead of 'develop' as default target The 'develop' command is like 'install' in the sense that it modifies the user's python environment. The default make target should be less intrusive, i.e. just building the extension module in-place without modify anything in the user's environment. We don't need to tell make about the dependency between 'test' and 'build' target as that is baked in the `python setup.py test` command. * [Makefile] add 'develop' target; remove unnecessary 'tests' target `make test` is good enough * [Makefile] `setup.py test` requires setuptools; run `python -m unittest` This will work even if setuptools is not installed, which is unlikely nowadays but still our `setup.py` works with plain distutils, so we may well have our tests work without setuptools. * [python/README.md] add ref to 'develop' target; remove 'tests', just 'make test' * [setup.py] import modules as per nicksay's comment https://github.com/google/brotli/pull/583#discussion_r131981049 * [Makefile] add 'develop' to .PHONY targets remove 'tests' from .PHONY * [appveyor] remove unused setup scripts We don't need to install custom python versions, we are using the pre-installed ones on Appveyor. * [appveyor] remove unneeded setup code
2017-08-23 18:45:13 +00:00
'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',
2016-09-28 19:19:49 +00:00
],
include_dirs=[
'c/include',
]),
2016-09-28 19:19:49 +00:00
]
TEST_SUITE = 'setup.get_test_suite'
2016-09-28 19:19:49 +00:00
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,
2016-09-28 19:19:49 +00:00
ext_modules=EXT_MODULES,
test_suite=TEST_SUITE,
2016-09-28 19:19:49 +00:00
cmdclass=CMD_CLASS)