Пример #1
0
 def dir1(self, ignore_global_vars=False):
     space = self.space
     total = rffi.getintfield(self.ctx, 'c_num_globals')
     g = self.ctx.c_globals
     names_w = []
     for i in range(total):
         if ignore_global_vars:
             op = getop(g[i].c_type_op)
             if (op == cffi_opcode.OP_GLOBAL_VAR or
                 op == cffi_opcode.OP_GLOBAL_VAR_F):
                 continue
         names_w.append(space.wrap(rffi.charp2str(g[i].c_name)))
     return space.newlist(names_w)
Пример #2
0
 def dir1(self, ignore_global_vars=False):
     space = self.space
     total = rffi.getintfield(self.ctx, 'c_num_globals')
     g = self.ctx.c_globals
     names_w = []
     for i in range(total):
         if ignore_global_vars:
             op = getop(g[i].c_type_op)
             if (op == cffi_opcode.OP_GLOBAL_VAR
                     or op == cffi_opcode.OP_GLOBAL_VAR_F):
                 continue
         names_w.append(space.newtext(rffi.charp2str(g[i].c_name)))
     return space.newlist(names_w)
Пример #3
0
    def fetch_int_constant(self, name):
        index = parse_c_type.search_in_globals(self.ctxobj.ctx, name)
        if index >= 0:
            g = self.ctxobj.ctx.c_globals[index]
            op = realize_c_type.getop(g.c_type_op)
            if (op == cffi_opcode.OP_CONSTANT_INT or
                  op == cffi_opcode.OP_ENUM):
                return realize_c_type.realize_global_int(self, g, index)
            raise oefmt(self.w_FFIError,
                        "function, global variable or non-integer constant "
                        "'%s' must be fetched from its original 'lib' "
                        "object", name)

        for ffi1, _ in self.included_ffis_libs:
            w_result = ffi1.fetch_int_constant(name)
            if w_result is not None:
                return w_result
        return None
Пример #4
0
    def fetch_int_constant(self, name):
        index = parse_c_type.search_in_globals(self.ctxobj.ctx, name)
        if index >= 0:
            g = self.ctxobj.ctx.c_globals[index]
            op = realize_c_type.getop(g.c_type_op)
            if (op == cffi_opcode.OP_CONSTANT_INT or
                  op == cffi_opcode.OP_ENUM):
                return realize_c_type.realize_global_int(self, g, index)
            raise oefmt(self.w_FFIError,
                        "function, global variable or non-integer constant "
                        "'%s' must be fetched from its original 'lib' "
                        "object", name)

        for ffi1, _ in self.included_ffis_libs:
            w_result = ffi1.fetch_int_constant(name)
            if w_result is not None:
                return w_result
        return None
Пример #5
0
def externpy_deco(space, w_ffi, w_python_callable, w_name, w_error, w_onerror):
    from pypy.module._cffi_backend.ffi_obj import W_FFIObject
    from pypy.module._cffi_backend.ccallback import W_ExternPython

    ffi = space.interp_w(W_FFIObject, w_ffi)

    if space.is_w(w_name, space.w_None):
        w_name = space.getattr(w_python_callable, space.wrap('__name__'))
    name = space.str_w(w_name)

    ctx = ffi.ctxobj.ctx
    index = parse_c_type.search_in_globals(ctx, name)
    if index < 0:
        raise externpy_not_found(ffi, name)

    g = ctx.c_globals[index]
    if getop(g.c_type_op) != cffi_opcode.OP_EXTERN_PYTHON:
        raise externpy_not_found(ffi, name)

    w_ct = realize_c_type.realize_c_type(ffi, ctx.c_types, getarg(g.c_type_op))

    # make a W_ExternPython instance, which is nonmovable; then cast it
    # to a raw pointer and assign it to the field 'reserved1' of the
    # externpy object from C.  We must make sure to keep it alive forever,
    # or at least until ffi.def_extern() is used again to change the
    # binding.  Note that the W_ExternPython is never exposed to the user.
    externpy = rffi.cast(parse_c_type.PEXTERNPY, g.c_address)
    externpython = instantiate(W_ExternPython, nonmovable=True)
    cdata = rffi.cast(rffi.CCHARP, externpy)
    W_ExternPython.__init__(externpython, space, cdata,
                          w_ct, w_python_callable, w_error, w_onerror)

    key = rffi.cast(lltype.Signed, externpy)
    space.fromcache(KeepaliveCache).cache_dict[key] = externpython
    externpy.c_reserved1 = externpython.hide_object()

    # return the function object unmodified
    return w_python_callable
Пример #6
0
def externpy_deco(space, w_ffi, w_python_callable, w_name, w_error, w_onerror):
    from pypy.module._cffi_backend.ffi_obj import W_FFIObject
    from pypy.module._cffi_backend.ccallback import W_ExternPython

    ffi = space.interp_w(W_FFIObject, w_ffi)

    if space.is_w(w_name, space.w_None):
        w_name = space.getattr(w_python_callable, space.wrap("__name__"))
    name = space.str_w(w_name)

    ctx = ffi.ctxobj.ctx
    index = parse_c_type.search_in_globals(ctx, name)
    if index < 0:
        raise externpy_not_found(ffi, name)

    g = ctx.c_globals[index]
    if getop(g.c_type_op) != cffi_opcode.OP_EXTERN_PYTHON:
        raise externpy_not_found(ffi, name)

    w_ct = realize_c_type.realize_c_type(ffi, ctx.c_types, getarg(g.c_type_op))

    # make a W_ExternPython instance, which is nonmovable; then cast it
    # to a raw pointer and assign it to the field 'reserved1' of the
    # externpy object from C.  We must make sure to keep it alive forever,
    # or at least until ffi.def_extern() is used again to change the
    # binding.  Note that the W_ExternPython is never exposed to the user.
    externpy = rffi.cast(parse_c_type.PEXTERNPY, g.c_address)
    externpython = instantiate(W_ExternPython, nonmovable=True)
    cdata = rffi.cast(rffi.CCHARP, externpy)
    W_ExternPython.__init__(externpython, space, cdata, w_ct, w_python_callable, w_error, w_onerror)

    key = rffi.cast(lltype.Signed, externpy)
    space.fromcache(KeepaliveCache).cache_dict[key] = externpython
    externpy.c_reserved1 = externpython.hide_object()

    # return the function object unmodified
    return w_python_callable
Пример #7
0
    def _build_attr(self, attr):
        index = parse_c_type.search_in_globals(self.ctx, attr)
        if index < 0:
            for ffi1, lib1 in self.ffi.included_ffis_libs:
                if lib1 is not None:
                    try:
                        w_result = lib1._get_attr_elidable(attr)
                        break  # found, break out of this loop
                    except KeyError:
                        w_result = lib1._build_attr(attr)
                        if w_result is not None:
                            break  # found, break out of this loop
                else:
                    w_result = ffi1.fetch_int_constant(attr)
                    if w_result is not None:
                        break  # found, break out of this loop
            else:
                return None  # not found at all
        else:
            space = self.space
            g = self.ctx.c_globals[index]
            op = getop(g.c_type_op)
            if (op == cffi_opcode.OP_CPYTHON_BLTN_V
                    or op == cffi_opcode.OP_CPYTHON_BLTN_N
                    or op == cffi_opcode.OP_CPYTHON_BLTN_O):
                # A function
                w_result = self._build_cpython_func(g, attr)
                #
            elif op == cffi_opcode.OP_GLOBAL_VAR:
                # A global variable of the exact type specified here
                w_ct = realize_c_type.realize_c_type(self.ffi,
                                                     self.ctx.c_types,
                                                     getarg(g.c_type_op))
                g_size = rffi.cast(lltype.Signed, g.c_size_or_direct_fn)
                if g_size != w_ct.size and g_size != 0 and w_ct.size > 0:
                    raise oefmt(
                        self.ffi.w_FFIError,
                        "global variable '%s' should be %d bytes "
                        "according to the cdef, but is actually %d", attr,
                        w_ct.size, g_size)
                ptr = rffi.cast(rffi.CCHARP, g.c_address)
                if not ptr:  # for dlopen() style
                    ptr = self.cdlopen_fetch(attr)
                w_result = cglob.W_GlobSupport(space, w_ct, ptr)
                #
            elif (op == cffi_opcode.OP_CONSTANT_INT
                  or op == cffi_opcode.OP_ENUM):
                # A constant integer whose value, in an "unsigned long long",
                # is obtained by calling the function at g->address
                w_result = realize_c_type.realize_global_int(
                    self.ffi, g, index)
                #
            elif (op == cffi_opcode.OP_CONSTANT
                  or op == cffi_opcode.OP_DLOPEN_CONST):
                # A constant which is not of integer type
                w_ct = realize_c_type.realize_c_type(self.ffi,
                                                     self.ctx.c_types,
                                                     getarg(g.c_type_op))
                fetch_funcptr = rffi.cast(realize_c_type.FUNCPTR_FETCH_CHARP,
                                          g.c_address)
                if w_ct.size <= 0:
                    raise oefmt(space.w_SystemError,
                                "constant has no known size")
                if not fetch_funcptr:  # for dlopen() style
                    assert op == cffi_opcode.OP_DLOPEN_CONST
                    ptr = self.cdlopen_fetch(attr)
                else:
                    assert op == cffi_opcode.OP_CONSTANT
                    ptr = lltype.malloc(rffi.CCHARP.TO,
                                        w_ct.size,
                                        flavor='raw')
                    self.ffi._finalizer.free_mems.append(ptr)
                    fetch_funcptr(ptr)
                w_result = w_ct.convert_to_object(ptr)
                #
            elif op == cffi_opcode.OP_DLOPEN_FUNC:
                # For dlopen(): the function of the given 'name'.  We use
                # dlsym() to get the address of something in the dynamic
                # library, which we interpret as being exactly a function of
                # the specified type.
                ptr = self.cdlopen_fetch(attr)
                w_ct = realize_c_type.realize_c_type_or_func(
                    self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                # must have returned a function type:
                assert isinstance(w_ct, realize_c_type.W_RawFuncType)
                w_ctfnptr = w_ct.unwrap_as_fnptr(self.ffi)
                w_result = W_CData(self.space, ptr, w_ctfnptr)
                #
            else:
                raise oefmt(space.w_NotImplementedError,
                            "in lib_build_attr: op=%d", op)

        assert w_result is not None
        self.dict_w[attr] = w_result
        return w_result
Пример #8
0
def ffiobj_init(ffi, module_name, version, types, w_globals,
                w_struct_unions, w_enums, w_typenames, w_includes):
    space = ffi.space

    # xxx force ll2ctypes conversion here.  This appears to be needed,
    # otherwise ll2ctypes explodes.  I don't want to know :-(
    rffi.cast(lltype.Signed, ffi.ctxobj)

    if version == -1 and not types:
        return
    if not (cffi1_module.VERSION_MIN <= version <= cffi1_module.VERSION_MAX):
        raise oefmt(space.w_ImportError,
            "cffi out-of-line Python module '%s' has unknown version %s",
            module_name, hex(version))

    if types:
        # unpack a string of 4-byte entries into an array of _cffi_opcode_t
        n = len(types) // 4
        ntypes = allocate_array(ffi, _CFFI_OPCODE_T, n)
        decoder = StringDecoder(ffi, types)
        for i in range(n):
            ntypes[i] = decoder.next_opcode()
        ffi.ctxobj.ctx.c_types = ntypes
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_types', n)
        ffi.cached_types = [None] * n

    if w_globals is not None:
        # unpack a tuple alternating strings and ints, each two together
        # describing one global_s entry with no specified address or size.
        # The int is only used with integer constants.
        globals_w = space.fixedview(w_globals)
        n = len(globals_w) // 2
        size = n * rffi.sizeof(GLOBAL_S) + n * rffi.sizeof(CDL_INTCONST_S)
        p = allocate(ffi, size)
        nglobs = rffi.cast(rffi.CArrayPtr(GLOBAL_S), p)
        p = rffi.ptradd(p, llmemory.raw_malloc_usage(n * rffi.sizeof(GLOBAL_S)))
        nintconsts = rffi.cast(rffi.CArrayPtr(CDL_INTCONST_S), p)
        for i in range(n):
            decoder = StringDecoder(ffi, space.str_w(globals_w[i * 2]))
            nglobs[i].c_type_op = decoder.next_opcode()
            nglobs[i].c_name = decoder.next_name()
            op = getop(nglobs[i].c_type_op)
            if op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM:
                w_integer = globals_w[i * 2 + 1]
                ll_set_cdl_realize_global_int(nglobs[i])
                bigint = space.bigint_w(w_integer)
                ullvalue = bigint.ulonglongmask()
                rffi.setintfield(nintconsts[i], 'neg', int(bigint.sign <= 0))
                rffi.setintfield(nintconsts[i], 'value', ullvalue)
        ffi.ctxobj.ctx.c_globals = nglobs
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_globals', n)

    if w_struct_unions is not None:
        # unpack a tuple of struct/unions, each described as a sub-tuple;
        # the item 0 of each sub-tuple describes the struct/union, and
        # the items 1..N-1 describe the fields, if any
        struct_unions_w = space.fixedview(w_struct_unions)
        n = len(struct_unions_w)
        nftot = 0     # total number of fields
        for i in range(n):
            nftot += space.len_w(struct_unions_w[i]) - 1
        nstructs = allocate_array(ffi, STRUCT_UNION_S, n)
        nfields = allocate_array(ffi, FIELD_S, nftot)
        nf = 0
        for i in range(n):
            # 'desc' is the tuple of strings (desc_struct, desc_field_1, ..)
            desc = space.fixedview(struct_unions_w[i])
            nf1 = len(desc) - 1
            decoder = StringDecoder(ffi, space.str_w(desc[0]))
            rffi.setintfield(nstructs[i], 'c_type_index', decoder.next_4bytes())
            flags = decoder.next_4bytes()
            rffi.setintfield(nstructs[i], 'c_flags', flags)
            nstructs[i].c_name = decoder.next_name()
            if flags & (cffi_opcode.F_OPAQUE | cffi_opcode.F_EXTERNAL):
                rffi.setintfield(nstructs[i], 'c_size', -1)
                rffi.setintfield(nstructs[i], 'c_alignment', -1)
                rffi.setintfield(nstructs[i], 'c_first_field_index', -1)
                rffi.setintfield(nstructs[i], 'c_num_fields', 0)
                assert nf1 == 0
            else:
                rffi.setintfield(nstructs[i], 'c_size', -2)
                rffi.setintfield(nstructs[i], 'c_alignment', -2)
                rffi.setintfield(nstructs[i], 'c_first_field_index', nf)
                rffi.setintfield(nstructs[i], 'c_num_fields', nf1)
            for j in range(nf1):
                decoder = StringDecoder(ffi, space.str_w(desc[j + 1]))
                # this 'decoder' is for one of the other strings beyond
                # the first one, describing one field each
                type_op = decoder.next_opcode()
                nfields[nf].c_field_type_op = type_op
                rffi.setintfield(nfields[nf], 'c_field_offset', -1)
                if getop(type_op) != cffi_opcode.OP_NOOP:
                    field_size = decoder.next_4bytes()
                else:
                    field_size = -1
                rffi.setintfield(nfields[nf], 'c_field_size', field_size)
                nfields[nf].c_name = decoder.next_name()
                nf += 1
        assert nf == nftot
        ffi.ctxobj.ctx.c_struct_unions = nstructs
        ffi.ctxobj.ctx.c_fields = nfields
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_struct_unions', n)

    if w_enums:
        # unpack a tuple of strings, each of which describes one enum_s entry
        enums_w = space.fixedview(w_enums)
        n = len(enums_w)
        nenums = allocate_array(ffi, ENUM_S, n)
        for i in range(n):
            decoder = StringDecoder(ffi, space.str_w(enums_w[i]))
            rffi.setintfield(nenums[i], 'c_type_index', decoder.next_4bytes())
            rffi.setintfield(nenums[i], 'c_type_prim', decoder.next_4bytes())
            nenums[i].c_name = decoder.next_name()
            nenums[i].c_enumerators = decoder.next_name()
        ffi.ctxobj.ctx.c_enums = nenums
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_enums', n)

    if w_typenames:
        # unpack a tuple of strings, each of which describes one typename_s
        # entry
        typenames_w = space.fixedview(w_typenames)
        n = len(typenames_w)
        ntypenames = allocate_array(ffi, TYPENAME_S, n)
        for i in range(n):
            decoder = StringDecoder(ffi, space.str_w(typenames_w[i]))
            rffi.setintfield(ntypenames[i],'c_type_index',decoder.next_4bytes())
            ntypenames[i].c_name = decoder.next_name()
        ffi.ctxobj.ctx.c_typenames = ntypenames
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_typenames', n)

    if w_includes:
        from pypy.module._cffi_backend.ffi_obj import W_FFIObject
        #
        for w_parent_ffi in space.fixedview(w_includes):
            parent_ffi = space.interp_w(W_FFIObject, w_parent_ffi)
            ffi.included_ffis_libs.append((parent_ffi, None))
Пример #9
0
def ffiobj_init(ffi, module_name, version, types, w_globals, w_struct_unions,
                w_enums, w_typenames, w_includes):
    space = ffi.space

    # xxx force ll2ctypes conversion here.  This appears to be needed,
    # otherwise ll2ctypes explodes.  I don't want to know :-(
    rffi.cast(lltype.Signed, ffi.ctxobj)

    if version == -1 and not types:
        return
    if not (cffi1_module.VERSION_MIN <= version <= cffi1_module.VERSION_MAX):
        raise oefmt(
            space.w_ImportError,
            "cffi out-of-line Python module '%s' has unknown version %s",
            module_name, hex(version))

    if types:
        # unpack a string of 4-byte entries into an array of _cffi_opcode_t
        n = len(types) // 4
        ntypes = allocate_array(ffi, _CFFI_OPCODE_T, n)
        decoder = StringDecoder(ffi, types)
        for i in range(n):
            ntypes[i] = decoder.next_opcode()
        ffi.ctxobj.ctx.c_types = ntypes
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_types', n)
        ffi.cached_types = [None] * n

    if w_globals is not None:
        # unpack a tuple alternating strings and ints, each two together
        # describing one global_s entry with no specified address or size.
        # The int is only used with integer constants.
        globals_w = space.fixedview(w_globals)
        n = len(globals_w) // 2
        size = n * rffi.sizeof(GLOBAL_S) + n * rffi.sizeof(CDL_INTCONST_S)
        p = allocate(ffi, size)
        nglobs = rffi.cast(rffi.CArrayPtr(GLOBAL_S), p)
        p = rffi.ptradd(p,
                        llmemory.raw_malloc_usage(n * rffi.sizeof(GLOBAL_S)))
        nintconsts = rffi.cast(rffi.CArrayPtr(CDL_INTCONST_S), p)
        for i in range(n):
            decoder = StringDecoder(ffi, space.bytes_w(globals_w[i * 2]))
            nglobs[i].c_type_op = decoder.next_opcode()
            nglobs[i].c_name = decoder.next_name()
            op = getop(nglobs[i].c_type_op)
            if op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM:
                w_integer = globals_w[i * 2 + 1]
                ll_set_cdl_realize_global_int(nglobs[i])
                bigint = space.bigint_w(w_integer)
                ullvalue = bigint.ulonglongmask()
                rffi.setintfield(nintconsts[i], 'neg', int(bigint.sign <= 0))
                rffi.setintfield(nintconsts[i], 'value', ullvalue)
        ffi.ctxobj.ctx.c_globals = nglobs
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_globals', n)

    if w_struct_unions is not None:
        # unpack a tuple of struct/unions, each described as a sub-tuple;
        # the item 0 of each sub-tuple describes the struct/union, and
        # the items 1..N-1 describe the fields, if any
        struct_unions_w = space.fixedview(w_struct_unions)
        n = len(struct_unions_w)
        nftot = 0  # total number of fields
        for i in range(n):
            nftot += space.len_w(struct_unions_w[i]) - 1
        nstructs = allocate_array(ffi, STRUCT_UNION_S, n)
        nfields = allocate_array(ffi, FIELD_S, nftot)
        nf = 0
        for i in range(n):
            # 'desc' is the tuple of strings (desc_struct, desc_field_1, ..)
            desc = space.fixedview(struct_unions_w[i])
            nf1 = len(desc) - 1
            decoder = StringDecoder(ffi, space.bytes_w(desc[0]))
            rffi.setintfield(nstructs[i], 'c_type_index',
                             decoder.next_4bytes())
            flags = decoder.next_4bytes()
            rffi.setintfield(nstructs[i], 'c_flags', flags)
            nstructs[i].c_name = decoder.next_name()
            if flags & (cffi_opcode.F_OPAQUE | cffi_opcode.F_EXTERNAL):
                rffi.setintfield(nstructs[i], 'c_size', -1)
                rffi.setintfield(nstructs[i], 'c_alignment', -1)
                rffi.setintfield(nstructs[i], 'c_first_field_index', -1)
                rffi.setintfield(nstructs[i], 'c_num_fields', 0)
                assert nf1 == 0
            else:
                rffi.setintfield(nstructs[i], 'c_size', -2)
                rffi.setintfield(nstructs[i], 'c_alignment', -2)
                rffi.setintfield(nstructs[i], 'c_first_field_index', nf)
                rffi.setintfield(nstructs[i], 'c_num_fields', nf1)
            for j in range(nf1):
                decoder = StringDecoder(ffi, space.bytes_w(desc[j + 1]))
                # this 'decoder' is for one of the other strings beyond
                # the first one, describing one field each
                type_op = decoder.next_opcode()
                nfields[nf].c_field_type_op = type_op
                rffi.setintfield(nfields[nf], 'c_field_offset', -1)
                if getop(type_op) != cffi_opcode.OP_NOOP:
                    field_size = decoder.next_4bytes()
                else:
                    field_size = -1
                rffi.setintfield(nfields[nf], 'c_field_size', field_size)
                nfields[nf].c_name = decoder.next_name()
                nf += 1
        assert nf == nftot
        ffi.ctxobj.ctx.c_struct_unions = nstructs
        ffi.ctxobj.ctx.c_fields = nfields
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_struct_unions', n)

    if w_enums:
        # unpack a tuple of strings, each of which describes one enum_s entry
        enums_w = space.fixedview(w_enums)
        n = len(enums_w)
        nenums = allocate_array(ffi, ENUM_S, n)
        for i in range(n):
            decoder = StringDecoder(ffi, space.bytes_w(enums_w[i]))
            rffi.setintfield(nenums[i], 'c_type_index', decoder.next_4bytes())
            rffi.setintfield(nenums[i], 'c_type_prim', decoder.next_4bytes())
            nenums[i].c_name = decoder.next_name()
            nenums[i].c_enumerators = decoder.next_name()
        ffi.ctxobj.ctx.c_enums = nenums
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_enums', n)

    if w_typenames:
        # unpack a tuple of strings, each of which describes one typename_s
        # entry
        typenames_w = space.fixedview(w_typenames)
        n = len(typenames_w)
        ntypenames = allocate_array(ffi, TYPENAME_S, n)
        for i in range(n):
            decoder = StringDecoder(ffi, space.bytes_w(typenames_w[i]))
            rffi.setintfield(ntypenames[i], 'c_type_index',
                             decoder.next_4bytes())
            ntypenames[i].c_name = decoder.next_name()
        ffi.ctxobj.ctx.c_typenames = ntypenames
        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_typenames', n)

    if w_includes:
        from pypy.module._cffi_backend.ffi_obj import W_FFIObject
        #
        for w_parent_ffi in space.fixedview(w_includes):
            parent_ffi = space.interp_w(W_FFIObject, w_parent_ffi)
            ffi.included_ffis_libs.append((parent_ffi, None))
Пример #10
0
    def _build_attr(self, attr):
        index = parse_c_type.search_in_globals(self.ctx, attr)
        if index < 0:
            for ffi1, lib1 in self.ffi.included_ffis_libs:
                if lib1 is not None:
                    try:
                        w_result = lib1._get_attr_elidable(attr)
                        break           # found, break out of this loop
                    except KeyError:
                        w_result = lib1._build_attr(attr)
                        if w_result is not None:
                            break       # found, break out of this loop
                else:
                    w_result = ffi1.fetch_int_constant(attr)
                    if w_result is not None:
                        break           # found, break out of this loop
            else:
                return None     # not found at all
        else:
            space = self.space
            g = self.ctx.c_globals[index]
            op = getop(g.c_type_op)
            if (op == cffi_opcode.OP_CPYTHON_BLTN_V or
                op == cffi_opcode.OP_CPYTHON_BLTN_N or
                op == cffi_opcode.OP_CPYTHON_BLTN_O):
                # A function
                w_result = self._build_cpython_func(g, attr)
                #
            elif op == cffi_opcode.OP_GLOBAL_VAR:
                # A global variable of the exact type specified here
                # (nowadays, only used by the ABI mode or backend
                # compatibility; see OP_GLOBAL_F for the API mode
                w_ct = realize_c_type.realize_c_type(
                    self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                g_size = rffi.cast(lltype.Signed, g.c_size_or_direct_fn)
                if g_size != w_ct.size and g_size != 0 and w_ct.size > 0:
                    raise oefmt(self.ffi.w_FFIError,
                            "global variable '%s' should be %d bytes "
                            "according to the cdef, but is actually %d",
                            attr, w_ct.size, g_size)
                ptr = rffi.cast(rffi.CCHARP, g.c_address)
                if not ptr:   # for dlopen() style
                    ptr = self.cdlopen_fetch(attr)
                w_result = cglob.W_GlobSupport(space, attr, w_ct, ptr=ptr)
                #
            elif op == cffi_opcode.OP_GLOBAL_VAR_F:
                w_ct = realize_c_type.realize_c_type(
                    self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                w_result = cglob.W_GlobSupport(space, attr, w_ct,
                                               fetch_addr=g.c_address)
                #
            elif (op == cffi_opcode.OP_CONSTANT_INT or
                  op == cffi_opcode.OP_ENUM):
                # A constant integer whose value, in an "unsigned long long",
                # is obtained by calling the function at g->address
                w_result = realize_c_type.realize_global_int(self.ffi, g,
                                                             index)
                #
            elif (op == cffi_opcode.OP_CONSTANT or
                  op == cffi_opcode.OP_DLOPEN_CONST):
                # A constant which is not of integer type
                w_ct = realize_c_type.realize_c_type(
                    self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                fetch_funcptr = rffi.cast(
                    realize_c_type.FUNCPTR_FETCH_CHARP,
                    g.c_address)
                if w_ct.size <= 0:
                    raise oefmt(self.ffi.w_FFIError,
                                "constant '%s' is of type '%s', "
                                "whose size is not known", attr, w_ct.name)
                    raise oefmt(space.w_SystemError,
                                "constant has no known size")
                if not fetch_funcptr:   # for dlopen() style
                    assert op == cffi_opcode.OP_DLOPEN_CONST
                    ptr = self.cdlopen_fetch(attr)
                else:
                    assert op == cffi_opcode.OP_CONSTANT
                    ptr = lltype.malloc(rffi.CCHARP.TO, w_ct.size, flavor='raw')
                    self.ffi._finalizer.free_mems.append(ptr)
                    fetch_funcptr(ptr)
                w_result = w_ct.convert_to_object(ptr)
                #
            elif op == cffi_opcode.OP_DLOPEN_FUNC:
                # For dlopen(): the function of the given 'name'.  We use
                # dlsym() to get the address of something in the dynamic
                # library, which we interpret as being exactly a function of
                # the specified type.
                ptr = self.cdlopen_fetch(attr)
                w_ct = realize_c_type.realize_c_type_or_func(
                    self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                # must have returned a function type:
                assert isinstance(w_ct, realize_c_type.W_RawFuncType)
                w_ctfnptr = w_ct.unwrap_as_fnptr(self.ffi)
                w_result = W_CData(self.space, ptr, w_ctfnptr)
                #
                #
            elif op == cffi_opcode.OP_EXTERN_PYTHON:
                # for reading 'lib.bar' where bar is declared
                # as an extern "Python"
                w_ct = realize_c_type.realize_c_type(
                    self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                ptr = lltype.direct_fieldptr(g, 'c_size_or_direct_fn')
                w_result = w_ct.convert_to_object(rffi.cast(rffi.CCHARP, ptr))
            else:
                raise oefmt(space.w_NotImplementedError,
                            "in lib_build_attr: op=%d", op)

        assert w_result is not None
        self.dict_w[attr] = w_result
        return w_result