def get_ext_modules():
    """
    Return a list of Extension instances for the setup() call.
    """
    # Note we don't import NumPy at the toplevel, since setup.py
    # should be able to run without NumPy for pip to discover the
    # build dependencies. Need NumPy headers and libm linkage.
    import numpy as np
    np_compile_args = {'include_dirs': [np.get_include(),],}
    if sys.platform != 'win32':
        np_compile_args['libraries'] = ['m',]

    ext_devicearray = Extension(name='numba._devicearray',
                                sources=['numba/_devicearray.cpp'],
                                depends=['numba/_pymodule.h',
                                         'numba/_devicearray.h'],
                                include_dirs=['numba'],
                                extra_compile_args=['-std=c++11'],
                                )

    ext_dynfunc = Extension(name='numba._dynfunc',
                            sources=['numba/_dynfuncmod.c'],
                            depends=['numba/_pymodule.h',
                                     'numba/_dynfunc.c'])

    dispatcher_sources = [
        'numba/_dispatcher.cpp',
        'numba/_typeof.cpp',
        'numba/_hashtable.cpp',
        'numba/core/typeconv/typeconv.cpp',
    ]
    ext_dispatcher = Extension(name="numba._dispatcher",
                               sources=dispatcher_sources,
                               depends=["numba/_pymodule.h",
                                        "numba/_typeof.h",
                                        "numba/_hashtable.h"],
                               extra_compile_args=['-std=c++11'],
                               **np_compile_args)

    ext_helperlib = Extension(name="numba._helperlib",
                              sources=["numba/_helpermod.c",
                                       "numba/cext/utils.c",
                                       "numba/cext/dictobject.c",
                                       "numba/cext/listobject.c",
                                       ],
                              # numba/_random.c needs pthreads
                              extra_link_args=install_name_tool_fixer +
                              extra_link_args,
                              depends=["numba/_pymodule.h",
                                       "numba/_helperlib.c",
                                       "numba/_lapack.c",
                                       "numba/_random.c",
                                       "numba/mathnames.inc",
                                       ],
                              **np_compile_args)

    ext_typeconv = Extension(name="numba.core.typeconv._typeconv",
                             sources=["numba/core/typeconv/typeconv.cpp",
                                      "numba/core/typeconv/_typeconv.cpp"],
                             depends=["numba/_pymodule.h"],
                             extra_compile_args=['-std=c++11'],
                             )

    ext_np_ufunc = Extension(name="numba.np.ufunc._internal",
                             sources=["numba/np/ufunc/_internal.c"],
                             depends=["numba/np/ufunc/_ufunc.c",
                                      "numba/np/ufunc/_internal.h",
                                      "numba/_pymodule.h"],
                             **np_compile_args)

    ext_npyufunc_num_threads = Extension(name="numba.np.ufunc._num_threads",
                                         sources=[
                                             "numba/np/ufunc/_num_threads.c"],
                                         depends=["numba/_pymodule.h"],
                                         )

    ext_np_ufunc_backends = []

    def check_file_at_path(path2file):
        """
        Takes a list as a path, a single glob (*) is permitted as an entry which
        indicates that expansion at this location is required (i.e. version
        might not be known).
        """
        found = None
        path2check = [os.path.split(os.path.split(sys.executable)[0])[0]]
        path2check += [os.getenv(n, '') for n in ['CONDA_PREFIX', 'PREFIX']]
        if sys.platform.startswith('win'):
            path2check += [os.path.join(p, 'Library') for p in path2check]
        for p in path2check:
            if p:
                if '*' in path2file:
                    globloc = path2file.index('*')
                    searchroot = os.path.join(*path2file[:globloc])
                    try:
                        potential_locs = os.listdir(os.path.join(p, searchroot))
                    except BaseException:
                        continue
                    searchfor = path2file[globloc + 1:]
                    for x in potential_locs:
                        potpath = os.path.join(p, searchroot, x, *searchfor)
                        if os.path.isfile(potpath):
                            found = p  # the latest is used
                elif os.path.isfile(os.path.join(p, *path2file)):
                    found = p  # the latest is used
        return found

    # Set various flags for use in TBB and openmp. On OSX, also find OpenMP!
    have_openmp = True
    if sys.platform.startswith('win'):
        if 'MSC' in sys.version:
            cpp11flags = []
            ompcompileflags = ['-openmp']
            omplinkflags = []
        else:
            # For non-MSVC toolchain e.g. gcc and clang with mingw
            cpp11flags = ['-std=c++11']
            ompcompileflags = ['-fopenmp']
            omplinkflags = ['-fopenmp']
    elif sys.platform.startswith('darwin'):
        cpp11flags = ['-std=c++11']
        # This is a bit unusual but necessary...
        # llvm (clang) OpenMP is used for headers etc at compile time
        # Intel OpenMP (libiomp5) provides the link library.
        # They are binary compatible and may not safely coexist in a process, as
        # libiomp5 is more prevalent and often linked in for NumPy it is used
        # here!
        ompcompileflags = ['-fopenmp']
        omplinkflags = ['-fopenmp=libiomp5']
        omppath = ['lib', 'clang', '*', 'include', 'omp.h']
        have_openmp = check_file_at_path(omppath)
    else:
        cpp11flags = ['-std=c++11']
        ompcompileflags = ['-fopenmp']
        if platform.machine() == 'ppc64le':
            omplinkflags = ['-fopenmp']
        else:
            omplinkflags = ['-fopenmp']

    # Disable tbb if forced by user with NUMBA_DISABLE_TBB=1
    if os.getenv("NUMBA_DISABLE_TBB"):
        print("TBB disabled")
    else:
        # Search for Intel TBB, first check env var TBBROOT then conda locations
        tbb_root = os.getenv('TBBROOT')
        if not tbb_root:
            tbb_root = check_file_at_path(['include', 'tbb', 'tbb.h'])

        if tbb_root:
            print("Using Intel TBB from:", tbb_root)
            ext_np_ufunc_tbb_backend = Extension(
                name='numba.np.ufunc.tbbpool',
                sources=[
                    'numba/np/ufunc/tbbpool.cpp',
                    'numba/np/ufunc/gufunc_scheduler.cpp',
                ],
                depends=['numba/np/ufunc/workqueue.h'],
                include_dirs=[os.path.join(tbb_root, 'include')],
                extra_compile_args=cpp11flags,
                extra_link_args=extra_link_args,
                libraries=['tbb'],  # TODO: if --debug or -g, use 'tbb_debug'
                library_dirs=[
                    # for Linux
                    os.path.join(tbb_root, 'lib', 'intel64', 'gcc4.4'),
                    # for MacOS
                    os.path.join(tbb_root, 'lib'),
                    # for Windows
                    os.path.join(tbb_root, 'lib', 'intel64', 'vc_mt'),
                ],
            )
            ext_np_ufunc_backends.append(ext_np_ufunc_tbb_backend)
        else:
            print("TBB not found")

    # Disable OpenMP if forced by user with NUMBA_DISABLE_OPENMP=1
    if os.getenv('NUMBA_DISABLE_OPENMP'):
        print("OpenMP disabled")
    elif have_openmp:
        print("Using OpenMP from:", have_openmp)
        # OpenMP backed work queue
        ext_np_ufunc_omppool_backend = Extension(
            name='numba.np.ufunc.omppool',
            sources=[
                'numba/np/ufunc/omppool.cpp',
                'numba/np/ufunc/gufunc_scheduler.cpp',
            ],
            depends=['numba/np/ufunc/workqueue.h'],
            extra_compile_args=ompcompileflags + cpp11flags,
            extra_link_args=omplinkflags,
        )

        ext_np_ufunc_backends.append(ext_np_ufunc_omppool_backend)
    else:
        print("OpenMP not found")

    # Build the Numba workqueue implementation irrespective of whether the TBB
    # version is built. Users can select a backend via env vars.
    ext_np_ufunc_workqueue_backend = Extension(
        name='numba.np.ufunc.workqueue',
        sources=['numba/np/ufunc/workqueue.c',
                 'numba/np/ufunc/gufunc_scheduler.cpp'],
        depends=['numba/np/ufunc/workqueue.h'],
        extra_link_args=extra_link_args)
    ext_np_ufunc_backends.append(ext_np_ufunc_workqueue_backend)

    ext_mviewbuf = Extension(name='numba.mviewbuf',
                             extra_link_args=install_name_tool_fixer,
                             sources=['numba/mviewbuf.c'])

    ext_nrt_python = Extension(name='numba.core.runtime._nrt_python',
                               sources=['numba/core/runtime/_nrt_pythonmod.c',
                                        'numba/core/runtime/nrt.cpp'],
                               depends=['numba/core/runtime/nrt.h',
                                        'numba/_pymodule.h',
                                        'numba/core/runtime/_nrt_python.c'],
                               **np_compile_args)

    ext_jitclass_box = Extension(name='numba.experimental.jitclass._box',
                                 sources=['numba/experimental/jitclass/_box.c'],
                                 depends=['numba/experimental/_pymodule.h'],
                                 )

    ext_cuda_extras = Extension(name='numba.cuda.cudadrv._extras',
                                sources=['numba/cuda/cudadrv/_extras.c'],
                                depends=['numba/_pymodule.h'],
                                include_dirs=["numba"])

    ext_modules = [ext_dynfunc, ext_dispatcher, ext_helperlib,
                   ext_typeconv, ext_np_ufunc, ext_npyufunc_num_threads,
                   ext_mviewbuf, ext_nrt_python, ext_jitclass_box,
                   ext_cuda_extras, ext_devicearray]

    ext_modules += ext_np_ufunc_backends

    return ext_modules

    Return a list of Extension instances for the setup() call.
    
setup.py