77import platform
88import re
99import unittest
10+ import sys
1011
1112try :
1213 from setuptools import Extension
1516 from distutils .core import Extension
1617 from distutils .core import setup
1718from distutils .command .build_ext import build_ext
18- from distutils import errors
1919from distutils import dep_util
2020from distutils import log
2121
2222
23+ IS_PYTHON3 = sys .version_info [0 ] == 3
24+ BROTLI_PYTHON3_LIMITED_API = os .environ .get ('BROTLI_PYTHON3_LIMITED_API' , '0' ) == '1'
25+
2326CURR_DIR = os .path .abspath (os .path .dirname (os .path .realpath (__file__ )))
2427
2528
2629def read_define (path , macro ):
2730 """ Return macro value from the given file. """
2831 with open (path , 'r' ) as f :
2932 for line in f :
30- m = re .match (rf '#define\s{ macro } \s+(.+)' , line )
33+ m = re .match ('#define\\ s{macro}\\ s+(.+)' . format ( macro = macro ) , line )
3134 if m :
3235 return m .group (1 )
3336 return ''
@@ -41,7 +44,7 @@ def get_version():
4144 patch = read_define (version_file_path , 'BROTLI_VERSION_PATCH' )
4245 if not major or not minor or not patch :
4346 return ''
44- return f '{ major } .{ minor } .{ patch } '
47+ return '{major}.{minor}.{patch}' . format ( major = major , minor = minor , patch = patch )
4548
4649
4750def get_test_suite ():
@@ -51,20 +54,7 @@ def get_test_suite():
5154
5255
5356class BuildExt (build_ext ):
54-
55- def get_source_files (self ):
56- filenames = build_ext .get_source_files (self )
57- for ext in self .extensions :
58- filenames .extend (ext .depends )
59- return filenames
60-
6157 def build_extension (self , ext ):
62- if ext .sources is None or not isinstance (ext .sources , (list , tuple )):
63- raise errors .DistutilsSetupError (
64- "in 'ext_modules' option (extension '%s'), "
65- "'sources' must be present and must be "
66- "a list of source filenames" % ext .name )
67-
6858 ext_path = self .get_ext_fullpath (ext .name )
6959 depends = ext .sources + ext .depends
7060 if not (self .force or dep_util .newer_group (depends , ext_path , 'newer' )):
@@ -73,59 +63,13 @@ def build_extension(self, ext):
7363 else :
7464 log .info ("building '%s' extension" , ext .name )
7565
76- c_sources = []
77- for source in ext .sources :
78- if source .endswith ('.c' ):
79- c_sources .append (source )
80- extra_args = ext .extra_compile_args or []
81-
82- objects = []
83-
84- macros = ext .define_macros [:]
85- if platform .system () == 'Darwin' :
86- macros .append (('OS_MACOSX' , '1' ))
87- elif self .compiler .compiler_type == 'mingw32' :
66+ if self .compiler .compiler_type == 'mingw32' :
8867 # On Windows Python 2.7, pyconfig.h defines "hypot" as "_hypot",
8968 # This clashes with GCC's cmath, and causes compilation errors when
9069 # building under MinGW: http://bugs.python.org/issue11566
91- macros .append (('_hypot' , 'hypot' ))
92- for undef in ext .undef_macros :
93- macros .append ((undef ,))
94-
95- objs = self .compiler .compile (
96- c_sources ,
97- output_dir = self .build_temp ,
98- macros = macros ,
99- include_dirs = ext .include_dirs ,
100- debug = self .debug ,
101- extra_postargs = extra_args ,
102- depends = ext .depends )
103- objects .extend (objs )
104-
105- self ._built_objects = objects [:]
106- if ext .extra_objects :
107- objects .extend (ext .extra_objects )
108- extra_args = ext .extra_link_args or []
109- # when using GCC on Windows, we statically link libgcc and libstdc++,
110- # so that we don't need to package extra DLLs
111- if self .compiler .compiler_type == 'mingw32' :
112- extra_args .extend (['-static-libgcc' , '-static-libstdc++' ])
70+ ext .define_macros .append (('_hypot' , 'hypot' ))
11371
114- ext_path = self .get_ext_fullpath (ext .name )
115- # Detect target language, if not provided
116- language = ext .language or self .compiler .detect_language (c_sources )
117-
118- self .compiler .link_shared_object (
119- objects ,
120- ext_path ,
121- libraries = self .get_libraries (ext ),
122- library_dirs = ext .library_dirs ,
123- runtime_library_dirs = ext .runtime_library_dirs ,
124- extra_postargs = extra_args ,
125- export_symbols = self .get_export_symbols (ext ),
126- debug = self .debug ,
127- build_temp = self .build_temp ,
128- target_lang = language )
72+ build_ext .build_extension (self , ext )
12973
13074
13175NAME = 'Brotli'
@@ -170,11 +114,25 @@ def build_extension(self, ext):
170114
171115PACKAGE_DIR = {'' : 'python' }
172116
173- PY_MODULES = ['brotli' ]
117+ class VersionedExtension (Extension ):
118+ def __init__ (self , * args , ** kwargs ):
119+ define_macros = []
120+
121+ if IS_PYTHON3 and BROTLI_PYTHON3_LIMITED_API :
122+ kwargs ['py_limited_api' ] = True
123+ define_macros .append (('Py_LIMITED_API' , '0x03060000' ))
124+
125+ if platform .system () == 'Darwin' :
126+ define_macros .append (('OS_MACOSX' , '1' ))
127+
128+ kwargs ['define_macros' ] = kwargs .get ('define_macros' , []) + define_macros
129+
130+ Extension .__init__ (self , * args , ** kwargs )
131+
174132
175133EXT_MODULES = [
176- Extension (
177- ' _brotli' ,
134+ VersionedExtension (
135+ name = 'brotli. _brotli' ,
178136 sources = [
179137 'python/_brotli.c' ,
180138 'c/common/constants.c' ,
@@ -276,6 +234,23 @@ def build_extension(self, ext):
276234 'build_ext' : BuildExt ,
277235}
278236
237+ if IS_PYTHON3 and BROTLI_PYTHON3_LIMITED_API :
238+ from wheel .bdist_wheel import bdist_wheel
239+ # adopted from:
240+ # https://github.com/joerick/python-abi3-package-sample/blob/7f05b22b9e0cfb4e60293bc85252e95278a80720/setup.py
241+ class bdist_wheel_abi3 (bdist_wheel ):
242+ def get_tag (self ):
243+ python , abi , plat = super ().get_tag ()
244+
245+ if python .startswith ("cp" ):
246+ # on CPython, our wheels are abi3 and compatible back to 3.6
247+ return "cp36" , "abi3" , plat
248+
249+ return python , abi , plat
250+
251+ CMD_CLASS ["bdist_wheel" ] = bdist_wheel_abi3
252+
253+
279254with open ("README.md" , "r" ) as f :
280255 README = f .read ()
281256
@@ -291,7 +266,7 @@ def build_extension(self, ext):
291266 platforms = PLATFORMS ,
292267 classifiers = CLASSIFIERS ,
293268 package_dir = PACKAGE_DIR ,
294- py_modules = PY_MODULES ,
269+ packages = [ "brotli" ] ,
295270 ext_modules = EXT_MODULES ,
296271 test_suite = TEST_SUITE ,
297272 cmdclass = CMD_CLASS )
0 commit comments