【问题标题】:What is the relationship between Vala VAPI and GObject Introspection?Vala VAPI 和 GObject Introspection 有什么关系?
【发布时间】:2012-06-27 03:52:34
【问题描述】:

首先,一些上下文:我是一名 Python 开发人员,他使用 PyGObject 编写了一个中型应用程序,利用 GObject Introspection 来访问 GSettings 等内容。我的一些 Python 对象实际上是 GObject.GObject 的子类,所以我非常广泛地使用 GObject。

最近,我注意到某个库在 GObject(gexiv2,Shotwell/Vala 使用)中包装了一个 C 库,但它目前不支持自省。我有兴趣为 gexiv2 添加自省支持,以便我可以从 Python 访问它,但我什至不知道从哪里开始讨论这个话题。

当我研究自省和 VAPI 时,我看到很多文档都提到了 VAPI 可以从自省注释自动生成的事实......但是如果项目已经有 VAPI 但没有自省呢?是否可以在给定 VAPI 的情况下自动生成自省注解?

谢谢。

【问题讨论】:

    标签: introspection vala pygobject gobject vapi


    【解决方案1】:

    VAPI 绑定不一定与 GObject 内省相关。例如,有针对 POSIX、Linux、libudev 和其他绝对不是基于 GObject 的东西的 VAPI 绑定。没有直接的方法可以将 VAPI 转换为 GObject 绑定。​​

    但是,如果您有 C 头文件和一个工作库,那么您通常可以从该库构建一个 GObject 内省文件。对于 gexiv2,下载并构建源代码,然后执行:

    g-ir-scanner -I gexiv2 gexiv2/gexiv2-{metadata,managed-stream,preview-properties,preview-image,log,startup}.h -n GExiv2 --library libgexiv2.la --pkg gobject-2.0
    

    这将生成一个您可以在 Python 中使用的 GIR 绑定 (XML)。

    【讨论】:

    • 我同意这是正确的前进方向,但是 AFAICT 在该项目中没有 GTK-Doc/GObject Introspection cmets,因此在您添加它们之前,您可能会得到一个非常糟糕的 GIR。见live.gnome.org/GObjectIntrospection/Annotations。此外,您需要编译到 typelib(使用 g-ir-compiler),然后将两者都安装到正确的位置(pkg-config --variable=typelibdir gobject-introspection-1.0 用于 typelib,pkg-config --variable=girdir gobject-introspection-1.0 用于 GIR)
    • 我忘记了 GTK 文档。不过,VAPI 可能有助于推断它们。我想简短的回答是:在 Python 中没有完全机械的方式来使用这个库。
    • 是的,我今天花了大部分时间查看我已经从 Python 访问的一些项目的源代码,以了解真实世界的注释是什么样的。我刚刚编译了 gexiv2,我将在上面运行 g-ir-scanner 看看会发生什么。如果我理解正确,没有从 VAPI 生成注释的自动方法,但参考 VAPI 可能会对编写注释有很大帮助。
    • 大家好,我发布了一个带有脚本的答案,该脚本解析 VAPI 并输出粗略的注释,如果您想查看的话。
    【解决方案2】:

    好吧,在厌倦了将 VAPI 定义手动复制到自省注释中的乏味之后,我编写了这个(粗略的)脚本来为我做这件事:

    #!/bin/env python
    
    import sys
    
    from collections import defaultdict
    
    ANNOTATION = """/**
     * %s:
    %s *
     * Returns:%s
     */
    """
    
    PARAMETER = """ * @%s:%s
    """
    
    methods = defaultdict(set)
    
    attrs = defaultdict(dict)
    
    with open(sys.argv[1]) as vapi:
        for line in vapi:
            tokens = line.split()
            try:
                names = tuple(tokens[0].split('.'))
            except IndexError:
                continue
    
            attrs[names] = {}
            for attribute in tokens[1:]:
                key, val = attribute.split('=')
                if val == '"1"': val = True
                if val == '"0"': val = False
                attrs[names][key] = val
    
            methods[names[0]]
            if len(names) > 1:
                methods[names[0]].add(names[-1])
    
    for method in methods:
        params = ''
        for param in methods[method]:
            param_attributes = ''
            param_attrs = attrs[(method, param)]
            if param_attrs.get('hidden'):
                param_attributes += ' (skip)'
            if param_attrs.get('is_out'):
                param_attributes += ' (out)'
            if param_attrs.get('transfer_ownership'):
                param_attributes += ' (transfer full)'
            elif 'transfer_ownership' in param_attrs:
                param_attributes += ' (transfer none)'
            if param_attrs.get('array_null_terminated'):
                param_attributes += ' (array zero-terminated=1)'
            if param_attrs.get('array_length_pos'):
                param_attributes += ' (array length=FIXME)'
            if param_attributes:
                param_attributes += ':'
            params += PARAMETER % (param, param_attributes)
    
        attributes = ''
        method_attrs = attrs[(method,)]
        if method_attrs.get('transfer_ownership'):
            attributes += ' (transfer full)'
        elif 'transfer_ownership' in method_attrs:
            attributes += ' (transfer none)'
        if method_attrs.get('nullable'):
            attributes += ' (allow-none)'
        if method_attrs.get('array_null_terminated'):
            attributes += ' (array zero-terminated=1)'
        if attributes:
            attributes += ':'
    
        print ANNOTATION % (method, params, attributes)
    

    这显然有一些缺点:它不会将注释插入代码中,它只是将它们打印出来,因此您必须进行大量复制和粘贴才能将所有内容放到正确的位置。它也不能很好地处理数组,但它至少可以让您知道何时需要手动修复数组。总而言之,与手动解析相比,运行此脚本然后处理结果的工作量要少得多。我在这里发布它是希望它被 google 采纳,并且有一天其他人可能会受益(尽管我非常希望从现在开始所有基于 GObject 的项目都只是从注释开始,然后使用 vapigen)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-30
      • 2016-12-12
      • 2011-10-15
      • 1970-01-01
      • 2012-04-02
      • 2016-03-30
      • 2013-02-05
      • 1970-01-01
      相关资源
      最近更新 更多