7 from distutils
.core
import setup
8 from Cython
.Build
.Dependencies
import cythonize
, extended_iglob
9 from Cython
.Utils
import is_package_dir
10 from Cython
.Compiler
import Options
13 import multiprocessing
14 parallel_compiles
= int(multiprocessing
.cpu_count() * 1.5)
16 multiprocessing
= None
20 class _FakePool(object):
21 def map_async(self
, func
, args
):
22 from itertools
import imap
23 for _
in imap(func
, args
):
27 def terminate(self
): pass
31 def parse_directives(option
, name
, value
, parser
):
33 old_directives
= dict(getattr(parser
.values
, dest
,
34 Options
.directive_defaults
))
35 directives
= Options
.parse_directive_list(
36 value
, relaxed_bool
=True, current_settings
=old_directives
)
37 setattr(parser
.values
, dest
, directives
)
40 def parse_options(option
, name
, value
, parser
):
42 options
= dict(getattr(parser
.values
, dest
, {}))
43 for opt
in value
.split(','):
45 n
, v
= opt
.split('=', 1)
46 v
= v
.lower() not in ('false', 'f', '0', 'no')
50 setattr(parser
.values
, dest
, options
)
53 def find_package_base(path
):
54 base_dir
, package_path
= os
.path
.split(path
)
55 while os
.path
.isfile(os
.path
.join(base_dir
, '__init__.py')):
56 base_dir
, parent
= os
.path
.split(base_dir
)
57 package_path
= '%s/%s' % (parent
, package_path
)
58 return base_dir
, package_path
61 def cython_compile(path_pattern
, options
):
63 paths
= map(os
.path
.abspath
, extended_iglob(path_pattern
))
66 if options
.build_inplace
:
68 while not os
.path
.isdir(base_dir
) or is_package_dir(base_dir
):
69 base_dir
= os
.path
.dirname(base_dir
)
73 if os
.path
.isdir(path
):
74 # recursively compiling a package
75 paths
= [os
.path
.join(path
, '**', '*.%s' % ext
)
76 for ext
in ('py', 'pyx')]
78 # assume it's a file(-like thing)
81 ext_modules
= cythonize(
83 nthreads
=options
.parallel
,
84 exclude_failures
=options
.keep_going
,
85 exclude
=options
.excludes
,
86 compiler_directives
=options
.directives
,
91 if ext_modules
and options
.build
:
92 if len(ext_modules
) > 1 and options
.parallel
> 1:
95 pool
= multiprocessing
.Pool(options
.parallel
)
98 pool
.map_async(run_distutils
, [
99 (base_dir
, [ext
]) for ext
in ext_modules
])
101 run_distutils((base_dir
, ext_modules
))
112 def run_distutils(args
):
113 base_dir
, ext_modules
= args
114 script_args
= ['build_ext', '-i']
120 temp_dir
= tempfile
.mkdtemp(dir=base_dir
)
121 script_args
.extend(['--build-temp', temp_dir
])
123 script_name
='setup.py',
124 script_args
=script_args
,
125 ext_modules
=ext_modules
,
130 if temp_dir
and os
.path
.isdir(temp_dir
):
131 shutil
.rmtree(temp_dir
)
134 def parse_args(args
):
135 from optparse
import OptionParser
136 parser
= OptionParser(usage
='%prog [options] [sources and packages]+')
138 parser
.add_option('-X', '--directive', metavar
='NAME=VALUE,...', dest
='directives',
139 type=str, action
='callback', callback
=parse_directives
, default
={},
140 help='set a compiler directive')
141 parser
.add_option('-s', '--option', metavar
='NAME=VALUE', dest
='options',
142 type=str, action
='callback', callback
=parse_options
, default
={},
143 help='set a cythonize option')
144 parser
.add_option('-3', dest
='python3_mode', action
='store_true',
145 help='use Python 3 syntax mode by default')
147 parser
.add_option('-x', '--exclude', metavar
='PATTERN', dest
='excludes',
148 action
='append', default
=[],
149 help='exclude certain file patterns from the compilation')
151 parser
.add_option('-b', '--build', dest
='build', action
='store_true',
152 help='build extension modules using distutils')
153 parser
.add_option('-i', '--inplace', dest
='build_inplace', action
='store_true',
154 help='build extension modules in place using distutils (implies -b)')
155 parser
.add_option('-j', '--parallel', dest
='parallel', metavar
='N',
156 type=int, default
=parallel_compiles
,
157 help=('run builds in N parallel jobs (default: %d)' %
158 parallel_compiles
or 1))
159 parser
.add_option('-f', '--force', dest
='force', action
='store_true',
160 help='force recompilation')
161 parser
.add_option('-q', '--quiet', dest
='quiet', action
='store_true',
162 help='be less verbose during compilation')
164 parser
.add_option('--lenient', dest
='lenient', action
='store_true',
165 help='increase Python compatibility by ignoring some compile time errors')
166 parser
.add_option('-k', '--keep-going', dest
='keep_going', action
='store_true',
167 help='compile as much as possible, ignore compilation failures')
169 options
, args
= parser
.parse_args(args
)
171 parser
.error("no source files provided")
172 if options
.build_inplace
:
174 if multiprocessing
is None:
176 if options
.python3_mode
:
177 options
.options
['language_level'] = 3
182 options
, paths
= parse_args(args
)
185 # increase Python compatibility by ignoring compile time errors
186 Options
.error_on_unknown_names
= False
187 Options
.error_on_uninitialized
= False
190 cython_compile(path
, options
)
193 if __name__
== '__main__':