Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Программирование с использованием gtkmm 3. Создание с помощью утилиты gmmproc оберток для разработанных с использованием языка программирования C библиотек

Оригинал: Programming with gtkmm 3
Авторы: Murray Cumming, Bernhard Rieder, Jonathon Jongsma, Ole Laursen, Marko Anastasov, Daniel Elstner, Chris Vine, David King, Pedro Ferreira, Kjell Ahlstedt
Дата публикации: 15 Октября 2013 г.
Перевод: А.Панин
Дата перевода: 25 Апреля 2014 г.

Приложение G. Создание с помощью утилиты gmmproc оберток для разработанных с использованием языка программирования C библиотек

G.4. Создаваемые вручную файлы исходного кода

Вы можете столкнуться с необходимостью включения в набор файлов исходного кода дополнительных файлов, которые не генерируются с помощью утилиты gmmproc на основе файлов с расширениями .hg и .ccg. Для этого вы можете просто поместить эти файлы в директорию libsomething/libsomethingmm и добавить их имена в файл Makefile.am в качестве значений переменных files_extra_h и files_extra_cc.

G.5. Инициализация

Ваша библиотека должна быть инициализирована перед использованием для регистрации новых типов, которые она делает доступными. Также созданная с использованием языка программирования C библиотека, для которой вы разрабатываете обертку, может иметь свою функцию инициализации, которую вы должны вызвать. Вы можете осуществлять инициализацию в рамках функции init(), которая может быть размещена в разработанных вручную файлах исходного кода init.h и init.cc. Данная функция должна осуществлять инициализацию необходимых программных компонентов (например, осуществляя вызов функции языка C и инициализацию gtkmm) и вызывать вашу сгенерированную функцию wrap_init(). Пример реализации функции:
void init()
{
  Gtk::Main::init_gtkmm_internals(); //Осуществляет настройку системы типов Glib и таблицы Glib::wrap().
  wrap_init(); //Помещает в таблицу Glib::wrap() информацию о классах библиотеки libsomethingmm.
}

Реализация метода wrap_init() в файле wrap_init.cc генерируется с помощью сценария generate_wrap_init.pl, но объявления в файле wrap_init.h должны быть созданы вручную, поэтому вы должны скорректировать файл wrap_init.h таким способом, чтобы функция wrap_init() находилась в корректном пространстве имен языка C++.

G.6. Проблемы в API языка C

Скорее всего, вы столкнетесь с некоторыми проблемами в библиотеке, для которой вы создаете обертку, особенно при работе над новым проектом. Ниже приведены описания наиболее часто встречающихся проблем вместе со способами их решения.

G.6.1. Отсутствие возможности предварительного объявления структур

В соответствии с соглашением, структуры объявляются в заголовочных файлах в стиле glib/GTK+ следующим образом:
typedef struct _ExampleWidget ExampleWidget;

struct _ExampleWidget
{
  ...
};

Дополнительный оператор typedef позволяет использовать структуру в заголовочном файле без включения ее полного объявления, просто предварительно объявив ее с помощью такой же строки с оператором typedef. Это значит, что вам не придется подключать заголовочный файл разработанной с использованием языка C библиотеки в рамках вашего заголовочного файла для языка C++ и, таким образом, объявления из него не будут включены в ваши публичные API. Утилита gmmproc предполагает, что была использована именно эта техника, поэтому вы увидите ошибки в том случае, если описанная техника не использовалась.

Ошибка компилятора может выглядеть следующим образом:
example-widget.h:56: error: using typedef-name 'ExampleWidget' after 'struct'
../../libexample/libexamplemm/example-widget.h:34: error: 'ExampleWidget' has a previous declaration here
make[4]: *** [example-widget.lo] Error 1
или следующим образом:
example-widget.h:60: error: '_ExampleWidget ExampleWidget' redeclared as different kind of symbol
../../libexample/libexamplemm/example-widget.h:34: error: previous declaration of 'typedef struct _ExampleWidget ExampleWidget'

Ее достаточно просто исправить на уровне разработанной с использованием языка C библиотеки, поэтому вам придется отправить патч разработчику, осуществляющему сопровождение рассматриваемой библиотеки.

G.6.2. Отсутствие свойств

В соответствии с соглашением, объекты в стиле glib/GTK+ имеют функции *_new(), такие, как example_widget_new(), которые всего лишь вызывают функцию g_object_new() и возвращают результат. Входные параметры передаются функции g_object_new() вместе с именами свойств, в качестве значений которых они выступают. Пример реализации описанной функции:
GtkWidget* example_widget_new(int something, const char* thing)
{
        return g_object_new (EXAMPLE_TYPE_WIDGET, "something", something, "thing", thing, NULL);
}

Данный подход позволяет при создании привязок для различных языков программирования реализовывать свои собственные эквиваленты этих функций (такие, как конструкторы языка C++) без использования функции *_new(). Это обычно необходимо для создания собственного происходящего от GType типа с целью добавления своих собственных функций предварительной обработки сигналов и виртуальных функций.

Функция _new(), по крайней мере, не должна использовать любые скрытые API (функции которых объявлены исключительно в файле с расширением .c). Даже в том случае, когда не осуществляется вызовов функций, мы иногда можем повторно реализовать 2 или 3 строки кода в рамках реализации функции _new(), в случае, если эти строки кода используют доступные для нас API.

Другим обходным путем является добавление функции *_construct(), которую конструктор языка C++ сможет вызвать после создания собственного типа. Пример реализации подобной функции:
GtkWidget* example_widget_new(int something, const char* thing)
{
        ExampleWidget* widget;
        widget = g_object_new (EXAMPLE_TYPE_WIDGET, NULL);
        example_widget_construct(widget, "something", something, "thing", thing);
}

void example_widget_construct(ExampleWidget* widget, int something, const char* thing)
{
        //Выполнение задач с использованием скрытого API:
        widget->priv->thing = thing;
        do_something(something);
}

Добавление свойств и проверка их корректного взаимодействия с уже существующими свойствами связаны с достаточно сложными манипуляциями с разработанной с использованием языка C библиотекой, но все же эта задача может быть решена, поэтому следует создать сообщение об ошибке и попытаться отправить патч ответственному за сопровождение библиотеки разработчику.

G.7. Документация

В большинстве своем проекты на основе gtkmm используют систему Doxygen, которая обрабатывает специальным образом отформатированные комментарии языка C++ и генерирует документацию в формате HTML. Вы можете размещать упомянутые комментарии для системы doxygen непосредственно в заголовочных файлах.

G.7.1. Повторное использование документация для языка C

Вы можете отдать предпочтение повторному использованию документации, которая уже создана для разработанной с использованием языка C библиотеки, для которой создается обертка. Разработанные с использованием языка C библиотеки обычно используют систему gtk-doc и, следовательно, содержат специально отформатированные для gtk-doc комментарии в исходном коде, а также некоторые дополнительные фрагменты документации в файлах с расширениями .sgml и .xml. Сценарий docextract_to_xml.py из директории tools/defs_gen исходного кода gtkmm может читать эти файлы и генерировать файл с расширением .xml, который, в свою очередь, может использоваться утилитой gmmproc для генерации комментариев в формате doxygen. Утилита gmmproc даже попытается преобразовать документацию для того, чтобы повысить ее совместимость с API языка C++.

Пример использования сценария:
./docextract_to_xml.py -s ~/checkout/gnome/gtk+/gtk/ > gtk_docs.xml

Из-за того, что это автоматическое преобразование не всегда дает требуемые результаты, вы можете отдать предпочтение созданию описания для определенного метода вручную. Для этого вам придется скопировать блок XML для рассматриваемой функции из вашего файла something_docs.xml в файл something_docs_override.xml и изменить его содержание.

G.7.2. Структура директорий для сборки документации

В том случае, если вы скопировали дерево исходного кода прототипа проекта из модуля mm-common и заменили стандартный текст, у вас в распоряжении уже будут корректные файлы сборки Makefile.am и Doxyfile.in. В рамках системы настройки сборки прототипа проекта из модуля mm-common список входных фалов для системы Doxygen не описывается в файле конфигурации Doxygen, а передается с помощью утилиты сборки make в стандартный поток ввода утилиты doxygen. Список входных файлов задается с помощью переменной doc_input в файле Makefile.am.


Вернуться : к началу книги.