1import os
2import platform
3import sys
4from distutils import sysconfig
5from distutils.command import build
6from distutils.spawn import spawn
7
8from setuptools import Extension, find_packages, setup
9
10import versioneer
11
12min_python_version = "3.6"
13min_numpy_build_version = "1.11"
14min_numpy_run_version = "1.15"
15min_llvmlite_version = "0.34.0.dev0"
16max_llvmlite_version = "0.35"
17
18if sys.platform.startswith('linux'):
19    # Patch for #2555 to make wheels without libpython
20    sysconfig.get_config_vars()['Py_ENABLE_SHARED'] = 0
21
22
23class build_doc(build.build):
24    description = "build documentation"
25
26    def run(self):
27        spawn(['make', '-C', 'docs', 'html'])
28
29
30versioneer.VCS = 'git'
31versioneer.versionfile_source = 'numba/_version.py'
32versioneer.versionfile_build = 'numba/_version.py'
33versioneer.tag_prefix = ''
34versioneer.parentdir_prefix = 'numba-'
35
36cmdclass = versioneer.get_cmdclass()
37cmdclass['build_doc'] = build_doc
38
39
40GCCFLAGS = ["-std=c89", "-Wdeclaration-after-statement", "-Werror"]
41
42if os.environ.get("NUMBA_GCC_FLAGS"):
43    CFLAGS = GCCFLAGS
44else:
45    CFLAGS = ['-g']
46
47install_name_tool_fixer = []
48if sys.platform == 'darwin':
49    install_name_tool_fixer += ['-headerpad_max_install_names']
50
51
52def is_building():
53    """
54    Parse the setup.py command and return whether a build is requested.
55    If False is returned, only an informational command is run.
56    If True is returned, information about C extensions will have to
57    be passed to the setup() function.
58    """
59    if len(sys.argv) < 2:
60        # User forgot to give an argument probably, let setuptools handle that.
61        return True
62
63    info_commands = ['--help-commands', '--name', '--version', '-V',
64                     '--fullname', '--author', '--author-email',
65                     '--maintainer', '--maintainer-email', '--contact',
66                     '--contact-email', '--url', '--license', '--description',
67                     '--long-description', '--platforms', '--classifiers',
68                     '--keywords', '--provides', '--requires', '--obsoletes']
69    # Add commands that do more than print info, but also don't need
70    # any build step.
71    info_commands.extend(['egg_info', 'install_egg_info', 'rotate'])
72
73    for command in info_commands:
74        if command in sys.argv[1:]:
75            return False
76
77    return True
78
79
80def get_ext_modules():
81    """
82    Return a list of Extension instances for the setup() call.
83    """
84    # Note we don't import Numpy at the toplevel, since setup.py
85    # should be able to run without Numpy for pip to discover the
86    # build dependencies
87    import numpy.distutils.misc_util as np_misc
88
89    # Inject required options for extensions compiled against the Numpy
90    # C API (include dirs, library dirs etc.)
91    np_compile_args = np_misc.get_info('npymath')
92
93    ext_dynfunc = Extension(name='numba._dynfunc',
94                            sources=['numba/_dynfuncmod.c'],
95                            extra_compile_args=CFLAGS,
96                            depends=['numba/_pymodule.h',
97                                     'numba/_dynfunc.c'])
98
99    ext_dispatcher = Extension(name="numba._dispatcher",
100                               sources=['numba/_dispatcher.c',
101                                        'numba/_typeof.c',
102                                        'numba/_hashtable.c',
103                                        'numba/_dispatcherimpl.cpp',
104                                        'numba/core/typeconv/typeconv.cpp'],
105                               depends=["numba/_pymodule.h",
106                                        "numba/_dispatcher.h",
107                                        "numba/_typeof.h",
108                                        "numba/_hashtable.h"],
109                               **np_compile_args)
110
111    ext_helperlib = Extension(name="numba._helperlib",
112                              sources=["numba/_helpermod.c",
113                                       "numba/cext/utils.c",
114                                       "numba/cext/dictobject.c",
115                                       "numba/cext/listobject.c",
116                                       ],
117                              extra_compile_args=CFLAGS,
118                              extra_link_args=install_name_tool_fixer,
119                              depends=["numba/_pymodule.h",
120                                       "numba/_helperlib.c",
121                                       "numba/_lapack.c",
122                                       "numba/_npymath_exports.c",
123                                       "numba/_random.c",
124                                       "numba/mathnames.inc",
125                                       ],
126                              **np_compile_args)
127
128    ext_typeconv = Extension(name="numba.core.typeconv._typeconv",
129                             sources=["numba/core/typeconv/typeconv.cpp",
130                                      "numba/core/typeconv/_typeconv.cpp"],
131                             depends=["numba/_pymodule.h"],
132                             )
133
134    ext_np_ufunc = Extension(name="numba.np.ufunc._internal",
135                             sources=["numba/np/ufunc/_internal.c"],
136                             depends=["numba/np/ufunc/_ufunc.c",
137                                      "numba/np/ufunc/_internal.h",
138                                      "numba/_pymodule.h"],
139                             **np_compile_args)
140
141    ext_npyufunc_num_threads = Extension(name="numba.np.ufunc._num_threads",
142                                         sources=[
143                                             "numba/np/ufunc/_num_threads.c"],
144                                         depends=["numba/_pymodule.h"],
145                                         )
146
147    ext_np_ufunc_backends = []
148
149    def check_file_at_path(path2file):
150        """
151        Takes a list as a path, a single glob (*) is permitted as an entry which
152        indicates that expansion at this location is required (i.e. version
153        might not be known).
154        """
155        found = None
156        path2check = [os.path.split(os.path.split(sys.executable)[0])[0]]
157        path2check += [os.getenv(n, '') for n in ['CONDA_PREFIX', 'PREFIX']]
158        if sys.platform.startswith('win'):
159            path2check += [os.path.join(p, 'Library') for p in path2check]
160        for p in path2check:
161            if p:
162                if '*' in path2file:
163                    globloc = path2file.index('*')
164                    searchroot = os.path.join(*path2file[:globloc])
165                    try:
166                        potential_locs = os.listdir(os.path.join(p, searchroot))
167                    except BaseException:
168                        continue
169                    searchfor = path2file[globloc + 1:]
170                    for x in potential_locs:
171                        potpath = os.path.join(p, searchroot, x, *searchfor)
172                        if os.path.isfile(potpath):
173                            found = p  # the latest is used
174                elif os.path.isfile(os.path.join(p, *path2file)):
175                    found = p  # the latest is used
176        return found
177
178    # Set various flags for use in TBB and openmp. On OSX, also find OpenMP!
179    have_openmp = True
180    if sys.platform.startswith('win'):
181        cpp11flags = []
182        ompcompileflags = ['-openmp']
183        omplinkflags = []
184    elif sys.platform.startswith('darwin'):
185        cpp11flags = ['-std=c++11']
186        # This is a bit unusual but necessary...
187        # llvm (clang) OpenMP is used for headers etc at compile time
188        # Intel OpenMP (libiomp5) provides the link library.
189        # They are binary compatible and may not safely coexist in a process, as
190        # libiomp5 is more prevalent and often linked in for NumPy it is used
191        # here!
192        ompcompileflags = ['-fopenmp']
193        omplinkflags = ['-fopenmp=libiomp5']
194        omppath = ['lib', 'clang', '*', 'include', 'omp.h']
195        have_openmp = check_file_at_path(omppath)
196    else:
197        cpp11flags = ['-std=c++11']
198        ompcompileflags = ['-fopenmp']
199        if platform.machine() == 'ppc64le':
200            omplinkflags = ['-fopenmp']
201        else:
202            omplinkflags = ['-fopenmp']
203
204    # Disable tbb if forced by user with NUMBA_DISABLE_TBB=1
205    if os.getenv("NUMBA_DISABLE_TBB"):
206        print("TBB disabled")
207    else:
208        # Search for Intel TBB, first check env var TBBROOT then conda locations
209        tbb_root = os.getenv('TBBROOT')
210        if not tbb_root:
211            tbb_root = check_file_at_path(['include', 'tbb', 'tbb.h'])
212
213        if tbb_root:
214            print("Using Intel TBB from:", tbb_root)
215            ext_np_ufunc_tbb_backend = Extension(
216                name='numba.np.ufunc.tbbpool',
217                sources=[
218                    'numba/np/ufunc/tbbpool.cpp',
219                    'numba/np/ufunc/gufunc_scheduler.cpp',
220                ],
221                depends=['numba/np/ufunc/workqueue.h'],
222                include_dirs=[os.path.join(tbb_root, 'include')],
223                extra_compile_args=cpp11flags,
224                libraries=['tbb'],  # TODO: if --debug or -g, use 'tbb_debug'
225                library_dirs=[
226                    # for Linux
227                    os.path.join(tbb_root, 'lib', 'intel64', 'gcc4.4'),
228                    # for MacOS
229                    os.path.join(tbb_root, 'lib'),
230                    # for Windows
231                    os.path.join(tbb_root, 'lib', 'intel64', 'vc_mt'),
232                ],
233            )
234            ext_np_ufunc_backends.append(ext_np_ufunc_tbb_backend)
235        else:
236            print("TBB not found")
237
238    # Disable OpenMP if forced by user with NUMBA_DISABLE_OPENMP=1
239    if os.getenv('NUMBA_DISABLE_OPENMP'):
240        print("OpenMP disabled")
241    elif have_openmp:
242        print("Using OpenMP from:", have_openmp)
243        # OpenMP backed work queue
244        ext_np_ufunc_omppool_backend = Extension(
245            name='numba.np.ufunc.omppool',
246            sources=[
247                'numba/np/ufunc/omppool.cpp',
248                'numba/np/ufunc/gufunc_scheduler.cpp',
249            ],
250            depends=['numba/np/ufunc/workqueue.h'],
251            extra_compile_args=ompcompileflags + cpp11flags,
252            extra_link_args=omplinkflags,
253        )
254
255        ext_np_ufunc_backends.append(ext_np_ufunc_omppool_backend)
256    else:
257        print("OpenMP not found")
258
259    # Build the Numba workqueue implementation irrespective of whether the TBB
260    # version is built. Users can select a backend via env vars.
261    ext_np_ufunc_workqueue_backend = Extension(
262        name='numba.np.ufunc.workqueue',
263        sources=['numba/np/ufunc/workqueue.c',
264                 'numba/np/ufunc/gufunc_scheduler.cpp'],
265        depends=['numba/np/ufunc/workqueue.h'])
266    ext_np_ufunc_backends.append(ext_np_ufunc_workqueue_backend)
267
268    ext_mviewbuf = Extension(name='numba.mviewbuf',
269                             extra_link_args=install_name_tool_fixer,
270                             sources=['numba/mviewbuf.c'])
271
272    ext_nrt_python = Extension(name='numba.core.runtime._nrt_python',
273                               sources=['numba/core/runtime/_nrt_pythonmod.c',
274                                        'numba/core/runtime/nrt.c'],
275                               depends=['numba/core/runtime/nrt.h',
276                                        'numba/_pymodule.h',
277                                        'numba/core/runtime/_nrt_python.c'],
278                               **np_compile_args)
279
280    ext_jitclass_box = Extension(name='numba.experimental.jitclass._box',
281                                 sources=['numba/experimental/jitclass/_box.c'],
282                                 depends=['numba/experimental/_pymodule.h'],
283                                 )
284
285    ext_cuda_extras = Extension(name='numba.cuda.cudadrv._extras',
286                                sources=['numba/cuda/cudadrv/_extras.c'],
287                                depends=['numba/_pymodule.h'],
288                                include_dirs=["numba"])
289
290    ext_modules = [ext_dynfunc, ext_dispatcher, ext_helperlib, ext_typeconv,
291                   ext_np_ufunc, ext_npyufunc_num_threads, ext_mviewbuf,
292                   ext_nrt_python, ext_jitclass_box, ext_cuda_extras]
293
294    ext_modules += ext_np_ufunc_backends
295
296    return ext_modules
297
298
299packages = find_packages(include=["numba", "numba.*"])
300
301build_requires = ['numpy >={}'.format(min_numpy_build_version)]
302install_requires = [
303    'llvmlite >={},<{}'.format(min_llvmlite_version, max_llvmlite_version),
304    'numpy >={}'.format(min_numpy_run_version),
305    'setuptools',
306]
307
308metadata = dict(
309    name='numba',
310    description="compiling Python code using LLVM",
311    version=versioneer.get_version(),
312    classifiers=[
313        "Development Status :: 4 - Beta",
314        "Intended Audience :: Developers",
315        "License :: OSI Approved :: BSD License",
316        "Operating System :: OS Independent",
317        "Programming Language :: Python",
318        "Programming Language :: Python :: 3",
319        "Programming Language :: Python :: 3.6",
320        "Programming Language :: Python :: 3.7",
321        "Programming Language :: Python :: 3.8",
322        "Topic :: Software Development :: Compilers",
323    ],
324    package_data={
325        # HTML templates for type annotations
326        "numba.core.annotations": ["*.html"],
327        # Various test data
328        "numba.cuda.tests.cudadrv.data": ["*.ptx"],
329        "numba.tests": ["pycc_distutils_usecase/*.py"],
330        # Some C files are needed by pycc
331        "numba": ["*.c", "*.h"],
332        "numba.pycc": ["*.c", "*.h"],
333        "numba.core.runtime": ["*.c", "*.h"],
334        "numba.cext": ["*.c", "*.h"],
335        # numba gdb hook init command language file
336        "numba.misc": ["cmdlang.gdb"],
337    },
338    scripts=["numba/pycc/pycc", "bin/numba"],
339    author="Anaconda, Inc.",
340    author_email="numba-users@continuum.io",
341    url="https://numba.github.com",
342    packages=packages,
343    setup_requires=build_requires,
344    install_requires=install_requires,
345    python_requires=">={}".format(min_python_version),
346    license="BSD",
347    cmdclass=cmdclass,
348)
349
350with open('README.rst') as f:
351    metadata['long_description'] = f.read()
352
353if is_building():
354    metadata['ext_modules'] = get_ext_modules()
355
356setup(**metadata)
357