Выбрать главу

Под капотом Crystal использует https://www.freedesktop.org/wiki/Software/pkg-config, если таковой имеется, чтобы определить, что следует передать компоновщику для правильного связывания библиотеки. Например, если бы мы проверили команду полной ссылки, которую Crystal выполняет при сборке нашего двоичного файла, мы бы смогли увидеть, какие флаги используются. Чтобы увидеть эту команду, добавьте флаг --verbose к команде сборки, которая будет выглядеть как Crystal build --verbose src/transform_cli.cr. Это выведет достаточное количество информации, но мы хотим посмотреть в самом конце, после опции -o, указывающей, каким будет имя выходного двоичного файла. Если бы мы запустили pkg-config --libs libnotify, мы бы получили -lnotify -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0, что мы также можем увидеть в команде необработанной ссылки.

Если pkg-config не установлен или недоступен, Crystal попытается передать флаг -llibnotify, который может работать или не работать в зависимости от связываемой библиотеки. В нашем случае это не так. Также можно явно указать, какие флаги следует передавать компоновщику, используя поле аннотации ldflags, которое будет иметь вид @[Link(ldflags: "...")].

Еще следует отметить, что мы используем некоторые псевдонимы в библиотеке lib. Псевдонимы в этом контексте действуют так же, как стандартные псевдонимы Crystal. Причина, по которой мы их определили, состоит в том, чтобы сделать код немного проще в сопровождении, оставаясь как можно ближе к фактическому определению методов. Если в будущем создатели библиотеки захотят изменить значение GInt, мы также легко сможем это поддержать.

Для представления типа уведомления мы используем ключевое слово type для создания непрозрачного типа, поддерживаемого указателем void, что нам может сойти с рук, поскольку нам не нужно фактически ссылаться или взаимодействовать с фактическим внутренним представлением уведомления в libnotify. Это также служит хорошим примером того, что не все нужно связывать, особенно если оно не будет использоваться.

Причина создания NotifyNotification непрозрачного типа заключается в том, что libnotify обрабатывает создание/обновление структуры внутри себя. Ключевое слово type позволяет нам создавать что-то, на что мы можем ссылаться в нашем коде Crystal, не заботясь о том, как это было создано.

В случае notify_notification_show мы сделали второй аргумент типа Void, поскольку предполагаем, что все работает так, как ожидалось. Мы также связали функцию notify_notification_update. Этот метод на самом деле не обязателен, но он поможет кое-что продемонстрировать позже в этом разделе, так что следите за обновлениями!

Тестирование привязок

Следующий вопрос, на который нам нужно ответить: куда нам следует поместить файл привязки? Идеальным решением было бы создать выделенный сегмент и потребовать его в качестве зависимости. Основное преимущество, которое это дает, заключается в том, что другие могут использовать их независимо от источника нашего приложения CLI. Однако для целей этой демонстрации мы просто добавим их в исходные файлы нашего приложения CLI.

Мы собираемся создать подкаталог lib_notify, чтобы хотя бы обеспечить некоторое разделение организации между типами, связанными с привязками, и нашей реальной логикой. Это также облегчит переключение на выделенный сегмент, если мы решим сделать это позже. Давайте создадим новый файл src/lib_notify/lib_notify.cr, который будет содержать код, связанный с привязкой. Обязательно добавьте require “./lib_notify” в файл src/transform.cr.

Поскольку сами привязки не зависят от нашего приложения CLI, мы можем протестировать их независимо. Мы можем сделать это, добавив следующие строки в наш файл привязки, запускающий его, и обязательно удалив этот тестовый код после его запуска:

LibNotify.notify_init "Transform"

notification = LibNotify.notify_notification_new "Hello",

"From Crystal!", nil

LibNotify.notify_notification_show notification, nil LibNotify.notify_uninit

Если все работает правильно, вы должны увидеть уведомление на рабочем столе с заголовком “Привет” и текстом “От Crystal!”. Мы передаем nil аргументам, для которых не имеем значения. Это работает нормально, поскольку эти аргументы являются необязательными, и Crystal автоматически преобразует их в нулевой указатель. Однако это не сработало бы, если бы переменная представляла собой объединение Pointer и Nil. Работа с необработанными привязками функциональна, но не удобна для пользователя. Обычной практикой является определение стандартных типов Crystal, которые обертывают типы привязки C. Это позволяет скрыть внутренние компоненты библиотеки C за API, который более удобен для пользователя и его легче документировать. Давайте начнем с этого сейчас.