Source

cffi / cffi / cross_backend.py

Full commit
import os
import os.path
from distutils.core import Extension
from distutils.core import Distribution
import distutils.ccompiler
import distutils.errors
from .verifier import _caller_dir_pycache

checksrc={
    'cross_backend/check_int16.c'     : ('int', 2),
    'cross_backend/check_int64.c'     : ('int', 8),
    'cross_backend/check_long64.c'    : ('long', 8),
    'cross_backend/check_intptr_t64.c': ('intptr_t', 8),
    'cross_backend/check_size_t64.c'  : ('size_t', 8),
}

type_sizes={
    'char'   : 1,
    'short'  : 2,
    'int'    : 4, #Assume 32bit int unless the cross compile says different
    'long'   : 4, #Assume 32bit long unless the cross compile says different
    'long long' : 8,
    'intptr_t' : 4, #Assume 32bit pointers unless cross compile says different
    'size_t' : 4, #Assume 32bit pointers unless cross compile says different
}


def initdata(tmpdir):
    ext = Extension(name='_dummytest', sources=[])
    dist = Distribution({'ext_modules': [ext]})
    dist.parse_command_line()
    try:
        dist.run_command('build_ext')
    except (distutils.errors.CompileError,
            distutils.errors.LinkError) as e:
        print 'Test builds failed'
    ddir=os.path.dirname(__file__)
    cmd_obj = dist.get_command_obj('build_ext')
    for i in checksrc.keys():
        try:
            cmd_obj.compiler.compile([os.path.join(ddir,i)],
                                     output_dir=cmd_obj.build_temp,
                                     macros=ext.define_macros[:],
                                     include_dirs=ext.include_dirs,
                                     debug=cmd_obj.debug,
                                     extra_postargs=ext.extra_compile_args or [],
                                     depends=ext.depends)
        except:
            continue
        type_sizes[checksrc[i][0]]=checksrc[i][1]
    type_sizes['unsigned char'] = type_sizes['char']
    type_sizes['unsigned int'] = type_sizes['int']
    type_sizes['unsigned long'] = type_sizes['long']
    type_sizes['unsigned long long'] = type_sizes['long long']
    type_sizes['uintptr_t'] = type_sizes['intptr_t']
    type_sizes['ssize_t'] = type_sizes['size_t']


def nonstandard_integer_types():
    UNSIGNED = 0x1000
    x={
        'int8_t'       : 1,
        'uint8_t'      : 1 | UNSIGNED,
        'int16_t'      : 2,
        'uint16_t'     : 2 | UNSIGNED,
        'int32_t'      : 4,
        'uint32_t'     : 4 | UNSIGNED,
        'int64_t'      : 8,
        'uint64_t'     : 8 | UNSIGNED,
        'intptr_t'     : type_sizes['intptr_t'],
        'uintptr_t'    : type_sizes['intptr_t'] | UNSIGNED,
        'ptrdiff_t'    : type_sizes['intptr_t'],
        'size_t'       : type_sizes['size_t'] | UNSIGNED,
        'ssize_t'      : type_sizes['size_t'],
    }
    return x

def sizeof(x):
    t='%s'%x
    t=t.split("'")[1]
    if t in type_sizes:
        print 'Primitive type size: %s : crossbackend %d cbackend %d'%(t, type_sizes[t], _sizeof(x))
        return type_sizes[t]
    return _sizeof(x)

def update_backend(backend, tmpdir):
    global _sizeof, _module_initialized
    if not os.environ.get('CFFI_CROSSTARGET', None):
        return
    if backend.sizeof == sizeof:
        return
    tmpdir = tmpdir or _caller_dir_pycache()
    print 'Initializing Cross Compiling backend'
    initdata(tmpdir)
    backend.nonstandard_integer_types = nonstandard_integer_types
    _sizeof = backend.sizeof
    backend.sizeof = sizeof