20
20
from setuptools .command .build_ext import build_ext
21
21
22
22
23
+ CFLAGS = ['-O2' ]
23
24
LIBUV_DIR = os .path .join (os .path .dirname (__file__ ), 'vendor' , 'libuv' )
24
25
25
26
@@ -30,17 +31,149 @@ def discover_tests():
30
31
31
32
32
33
class libuv_build_ext (build_ext ):
33
- build_ext .user_options .extend ([
34
- ("use-system-libuv" , None ,
35
- "Use the system provided libuv, instead of the bundled one" )
36
- ])
34
+ user_options = build_ext .user_options + [
35
+ ('cython-always' , None ,
36
+ 'run cythonize() even if .c files are present' ),
37
+ ('cython-annotate' , None ,
38
+ 'Produce a colorized HTML version of the Cython source.' ),
39
+ ('cython-directives=' , None ,
40
+ 'Cythion compiler directives' ),
41
+ ('use-system-libuv' , None ,
42
+ 'Use the system provided libuv, instead of the bundled one' ),
43
+ ]
37
44
38
- build_ext .boolean_options .extend (["use-system-libuv" ])
45
+ boolean_options = build_ext .boolean_options + [
46
+ 'cython-always' ,
47
+ 'cython-annotate' ,
48
+ 'use-system-libuv' ,
49
+ ]
39
50
40
51
def initialize_options (self ):
41
- build_ext .initialize_options (self )
42
- if getattr (self , 'use_system_libuv' , None ) is None :
43
- self .use_system_libuv = 0
52
+ super ().initialize_options ()
53
+ self .use_system_libuv = False
54
+ self .cython_always = False
55
+ self .cython_annotate = None
56
+ self .cython_directives = None
57
+
58
+ def finalize_options (self ):
59
+ need_cythonize = self .cython_always
60
+ cfiles = {}
61
+
62
+ for extension in self .distribution .ext_modules :
63
+ for i , sfile in enumerate (extension .sources ):
64
+ if sfile .endswith ('.pyx' ):
65
+ prefix , ext = os .path .splitext (sfile )
66
+ cfile = prefix + '.c'
67
+
68
+ if os .path .exists (cfile ) and not self .cython_always :
69
+ extension .sources [i ] = cfile
70
+ else :
71
+ if os .path .exists (cfile ):
72
+ cfiles [cfile ] = os .path .getmtime (cfile )
73
+ else :
74
+ cfiles [cfile ] = 0
75
+ need_cythonize = True
76
+
77
+ if need_cythonize :
78
+ try :
79
+ import Cython
80
+ except ImportError :
81
+ raise RuntimeError (
82
+ 'please install Cython to compile asyncpg from source' )
83
+
84
+ if Cython .__version__ < '0.24' :
85
+ raise RuntimeError (
86
+ 'uvloop requires Cython version 0.24 or greater' )
87
+
88
+ from Cython .Build import cythonize
89
+
90
+ directives = {}
91
+ if self .cython_directives :
92
+ for directive in self .cython_directives .split (',' ):
93
+ k , _ , v = directive .partition ('=' )
94
+ if v .lower () == 'false' :
95
+ v = False
96
+ if v .lower () == 'true' :
97
+ v = True
98
+
99
+ directives [k ] = v
100
+
101
+ self .distribution .ext_modules [:] = cythonize (
102
+ self .distribution .ext_modules ,
103
+ compiler_directives = directives ,
104
+ annotate = self .cython_annotate )
105
+
106
+ for cfile , timestamp in cfiles .items ():
107
+ if os .path .getmtime (cfile ) != timestamp :
108
+ # The file was recompiled, patch
109
+ self ._patch_cfile (cfile )
110
+
111
+ super ().finalize_options ()
112
+
113
+ def _patch_cfile (self , cfile ):
114
+ # Patch Cython 'async def' coroutines to have a 'tp_iter'
115
+ # slot, which makes them compatible with 'yield from' without
116
+ # the `asyncio.coroutine` decorator.
117
+
118
+ with open (cfile , 'rt' ) as f :
119
+ src = f .read ()
120
+
121
+ src = re .sub (
122
+ r'''
123
+ \s* offsetof\(__pyx_CoroutineObject,\s*gi_weakreflist\),
124
+ \s* 0,
125
+ \s* 0,
126
+ \s* __pyx_Coroutine_methods,
127
+ \s* __pyx_Coroutine_memberlist,
128
+ \s* __pyx_Coroutine_getsets,
129
+ ''' ,
130
+
131
+ r'''
132
+ offsetof(__pyx_CoroutineObject, gi_weakreflist),
133
+ __Pyx_Coroutine_await, /* tp_iter */
134
+ 0,
135
+ __pyx_Coroutine_methods,
136
+ __pyx_Coroutine_memberlist,
137
+ __pyx_Coroutine_getsets,
138
+ ''' ,
139
+
140
+ src , flags = re .X )
141
+
142
+ # Fix a segfault in Cython.
143
+ src = re .sub (
144
+ r'''
145
+ \s* __Pyx_Coroutine_get_qualname\(__pyx_CoroutineObject\s+\*self\)
146
+ \s* {
147
+ \s* Py_INCREF\(self->gi_qualname\);
148
+ ''' ,
149
+
150
+ r'''
151
+ __Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self)
152
+ {
153
+ if (self->gi_qualname == NULL) { return __pyx_empty_unicode; }
154
+ Py_INCREF(self->gi_qualname);
155
+ ''' ,
156
+
157
+ src , flags = re .X )
158
+
159
+ src = re .sub (
160
+ r'''
161
+ \s* __Pyx_Coroutine_get_name\(__pyx_CoroutineObject\s+\*self\)
162
+ \s* {
163
+ \s* Py_INCREF\(self->gi_name\);
164
+ ''' ,
165
+
166
+ r'''
167
+ __Pyx_Coroutine_get_name(__pyx_CoroutineObject *self)
168
+ {
169
+ if (self->gi_name == NULL) { return __pyx_empty_unicode; }
170
+ Py_INCREF(self->gi_name);
171
+ ''' ,
172
+
173
+ src , flags = re .X )
174
+
175
+ with open (cfile , 'wt' ) as f :
176
+ f .write (src )
44
177
45
178
def build_libuv (self ):
46
179
env = os .environ .copy ()
@@ -112,9 +245,9 @@ def build_extensions(self):
112
245
Extension (
113
246
"uvloop.loop" ,
114
247
sources = [
115
- "uvloop/loop.c " ,
248
+ "uvloop/loop.pyx " ,
116
249
],
117
- extra_compile_args = [ '-O2' ]
250
+ extra_compile_args = CFLAGS
118
251
),
119
252
],
120
253
classifiers = [
0 commit comments