Какова связь между Vala VAPI и GObject Introspection?

Во-первых, немного контекста: я разработчик Python, который написал приложение среднего размера, использующее PyGObject, использующее преимущества GObject Introspection для доступа к таким вещам, как GSettings и т. Д. Некоторые из моих объектов Python фактически являются подклассом GObject.GObject, поэтому я использование GObject довольно широко.

Недавно к моему вниманию обратилась некая библиотека, которая оборачивает библиотеку C в GObject (gexiv2, используется Shotwell/Vala), однако в настоящее время она не поддерживает самоанализ. Я заинтересован в добавлении поддержки самоанализа в gexiv2, чтобы я мог получить к нему доступ из Python, но я даже не знаю, с чего начать в этой теме.

Когда я исследую интроспекцию и VAPI, я вижу много документации, ссылающейся на тот факт, что 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).

Привязки VAPI не обязательно связаны с самоанализом GObject. Например, есть привязки VAPI для POSIX, Linux, libudev и других вещей, которые определенно не основаны на GObject. Нет прямого способа конвертировать 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

И это создаст привязку GIR (XML), которую вы можете использовать в Python.

Другие вопросы по тегам