Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
setuptools_ext.py230 linesDownload Raw Back to cffi
1import os2import sys3import sysconfig4 5try:6    basestring7except NameError:8    # Python 3.x9    basestring = str10 11def error(msg):12    from cffi._shimmed_dist_utils import DistutilsSetupError13    raise DistutilsSetupError(msg)14 15 16def execfile(filename, glob):17    # We use execfile() (here rewritten for Python 3) instead of18    # __import__() to load the build script.  The problem with19    # a normal import is that in some packages, the intermediate20    # __init__.py files may already try to import the file that21    # we are generating.22    with open(filename) as f:23        src = f.read()24    src += '\n'      # Python 2.6 compatibility25    code = compile(src, filename, 'exec')26    exec(code, glob, glob)27 28 29def add_cffi_module(dist, mod_spec):30    from cffi.api import FFI31 32    if not isinstance(mod_spec, basestring):33        error("argument to 'cffi_modules=...' must be a str or a list of str,"34              " not %r" % (type(mod_spec).__name__,))35    mod_spec = str(mod_spec)36    try:37        build_file_name, ffi_var_name = mod_spec.split(':')38    except ValueError:39        error("%r must be of the form 'path/build.py:ffi_variable'" %40              (mod_spec,))41    if not os.path.exists(build_file_name):42        ext = ''43        rewritten = build_file_name.replace('.', '/') + '.py'44        if os.path.exists(rewritten):45            ext = ' (rewrite cffi_modules to [%r])' % (46                rewritten + ':' + ffi_var_name,)47        error("%r does not name an existing file%s" % (build_file_name, ext))48 49    mod_vars = {'__name__': '__cffi__', '__file__': build_file_name}50    execfile(build_file_name, mod_vars)51 52    try:53        ffi = mod_vars[ffi_var_name]54    except KeyError:55        error("%r: object %r not found in module" % (mod_spec,56                                                     ffi_var_name))57    if not isinstance(ffi, FFI):58        ffi = ffi()      # maybe it's a function instead of directly an ffi59    if not isinstance(ffi, FFI):60        error("%r is not an FFI instance (got %r)" % (mod_spec,61                                                      type(ffi).__name__))62    if not hasattr(ffi, '_assigned_source'):63        error("%r: the set_source() method was not called" % (mod_spec,))64    module_name, source, source_extension, kwds = ffi._assigned_source65    if ffi._windows_unicode:66        kwds = kwds.copy()67        ffi._apply_windows_unicode(kwds)68 69    if source is None:70        _add_py_module(dist, ffi, module_name)71    else:72        _add_c_module(dist, ffi, module_name, source, source_extension, kwds)73 74def _set_py_limited_api(Extension, kwds):75    """76    Add py_limited_api to kwds if setuptools >= 26 is in use.77    Do not alter the setting if it already exists.78    Setuptools takes care of ignoring the flag on Python 2 and PyPy.79 80    CPython itself should ignore the flag in a debugging version81    (by not listing .abi3.so in the extensions it supports), but82    it doesn't so far, creating troubles.  That's why we check83    for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent84    of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401)85 86    On Windows, with CPython <= 3.4, it's better not to use py_limited_api87    because virtualenv *still* doesn't copy PYTHON3.DLL on these versions.88    Recently (2020) we started shipping only >= 3.5 wheels, though.  So89    we'll give it another try and set py_limited_api on Windows >= 3.5.90    """91    from cffi._shimmed_dist_utils import log92    from cffi import recompiler93 94    if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount')95            and recompiler.USE_LIMITED_API):96        import setuptools97        try:98            setuptools_major_version = int(setuptools.__version__.partition('.')[0])99            if setuptools_major_version >= 26:100                kwds['py_limited_api'] = True101        except ValueError:  # certain development versions of setuptools102            # If we don't know the version number of setuptools, we103            # try to set 'py_limited_api' anyway.  At worst, we get a104            # warning.105            kwds['py_limited_api'] = True106 107    if sysconfig.get_config_var("Py_GIL_DISABLED"):108        if kwds.get('py_limited_api'):109            log.info("Ignoring py_limited_api=True for free-threaded build.")110 111        kwds['py_limited_api'] = False112 113    if kwds.get('py_limited_api') is False:114        # avoid setting Py_LIMITED_API if py_limited_api=False115        # which _cffi_include.h does unless _CFFI_NO_LIMITED_API is defined116        kwds.setdefault("define_macros", []).append(("_CFFI_NO_LIMITED_API", None))117    return kwds118 119def _add_c_module(dist, ffi, module_name, source, source_extension, kwds):120    # We are a setuptools extension. Need this build_ext for py_limited_api.121    from setuptools.command.build_ext import build_ext122    from cffi._shimmed_dist_utils import Extension, log, mkpath123    from cffi import recompiler124 125    allsources = ['$PLACEHOLDER']126    allsources.extend(kwds.pop('sources', []))127    kwds = _set_py_limited_api(Extension, kwds)128    ext = Extension(name=module_name, sources=allsources, **kwds)129 130    def make_mod(tmpdir, pre_run=None):131        c_file = os.path.join(tmpdir, module_name + source_extension)132        log.info("generating cffi module %r" % c_file)133        mkpath(tmpdir)134        # a setuptools-only, API-only hook: called with the "ext" and "ffi"135        # arguments just before we turn the ffi into C code.  To use it,136        # subclass the 'distutils.command.build_ext.build_ext' class and137        # add a method 'def pre_run(self, ext, ffi)'.138        if pre_run is not None:139            pre_run(ext, ffi)140        updated = recompiler.make_c_source(ffi, module_name, source, c_file)141        if not updated:142            log.info("already up-to-date")143        return c_file144 145    if dist.ext_modules is None:146        dist.ext_modules = []147    dist.ext_modules.append(ext)148 149    base_class = dist.cmdclass.get('build_ext', build_ext)150    class build_ext_make_mod(base_class):151        def run(self):152            if ext.sources[0] == '$PLACEHOLDER':153                pre_run = getattr(self, 'pre_run', None)154                ext.sources[0] = make_mod(self.build_temp, pre_run)155            base_class.run(self)156    dist.cmdclass['build_ext'] = build_ext_make_mod157    # NB. multiple runs here will create multiple 'build_ext_make_mod'158    # classes.  Even in this case the 'build_ext' command should be159    # run once; but just in case, the logic above does nothing if160    # called again.161 162 163def _add_py_module(dist, ffi, module_name):164    from setuptools.command.build_py import build_py165    from setuptools.command.build_ext import build_ext166    from cffi._shimmed_dist_utils import log, mkpath167    from cffi import recompiler168 169    def generate_mod(py_file):170        log.info("generating cffi module %r" % py_file)171        mkpath(os.path.dirname(py_file))172        updated = recompiler.make_py_source(ffi, module_name, py_file)173        if not updated:174            log.info("already up-to-date")175 176    base_class = dist.cmdclass.get('build_py', build_py)177    class build_py_make_mod(base_class):178        def run(self):179            base_class.run(self)180            module_path = module_name.split('.')181            module_path[-1] += '.py'182            generate_mod(os.path.join(self.build_lib, *module_path))183        def get_source_files(self):184            # This is called from 'setup.py sdist' only.  Exclude185            # the generate .py module in this case.186            saved_py_modules = self.py_modules187            try:188                if saved_py_modules:189                    self.py_modules = [m for m in saved_py_modules190                                         if m != module_name]191                return base_class.get_source_files(self)192            finally:193                self.py_modules = saved_py_modules194    dist.cmdclass['build_py'] = build_py_make_mod195 196    # distutils and setuptools have no notion I could find of a197    # generated python module.  If we don't add module_name to198    # dist.py_modules, then things mostly work but there are some199    # combination of options (--root and --record) that will miss200    # the module.  So we add it here, which gives a few apparently201    # harmless warnings about not finding the file outside the202    # build directory.203    # Then we need to hack more in get_source_files(); see above.204    if dist.py_modules is None:205        dist.py_modules = []206    dist.py_modules.append(module_name)207 208    # the following is only for "build_ext -i"209    base_class_2 = dist.cmdclass.get('build_ext', build_ext)210    class build_ext_make_mod(base_class_2):211        def run(self):212            base_class_2.run(self)213            if self.inplace:214                # from get_ext_fullpath() in distutils/command/build_ext.py215                module_path = module_name.split('.')216                package = '.'.join(module_path[:-1])217                build_py = self.get_finalized_command('build_py')218                package_dir = build_py.get_package_dir(package)219                file_name = module_path[-1] + '.py'220                generate_mod(os.path.join(package_dir, file_name))221    dist.cmdclass['build_ext'] = build_ext_make_mod222 223def cffi_modules(dist, attr, value):224    assert attr == 'cffi_modules'225    if isinstance(value, basestring):226        value = [value]227 228    for cffi_module in value:229        add_cffi_module(dist, cffi_module)230 
codekingpro/portable-devtools · Team Ai