Использование в языке D сторонних библиотек

  • Tutorial
На волне интереса к языку D решил и я внести свой вклад в его популяризацию. Статья не для новичков, а больше для тех кто рассматривает D как второй язык. Известно, что на заре своего развития, языки программирования имеют небогатый набор библиотек и это часто не позволяет начинать писать на них что-то серьёзное. Надеюсь статья поможет кому-нибудь переступить этот барьер.
Ниже будут рассмотрены возможности утилиты dub, а так же подключение сторонних пакетов и библиотек написанных на C/C++ на примере замечательной библиотеки libev.

Утилита dub


Честно говоря, я до сих пор “плаваю” в опциях dmd, необходимых для компиляции и сборки приложения. Виной тому утилита dub, которая берет на себя все эти заботы и позволяет отложить изучение нюансов компиляции и сборки приложения на потом, когда это действительно станет необходимо. Кроме этого, эта полезная программка выполняет функции пакетного менеджера, обладая функционалом, аналогичным утилитам pip для python, npm для javascript и т.п.

Инициализация проекта


Для инициализации приложения с помощью утилиты dub надо создать каталог проекта, перейти в него и выполнить команду:
$ dub init

В результате будет создан файл dub.json, с помощью которого задается конфигурация и параметры сборки приложения. А также, подкаталог source, содержащий файл app.d с незамысловатым хелоуворлдом.
Сборка и/или запуск приложения производится этой же утилитой, запускаемой из корневого каталога проекта, то есть из каталога, содержащего файл dub.json. Чтобы скомпилировать, собрать и запустить хелоуворлд из файла app.d, достаточно выполнить команду dub.

Подключение сторонних пакетов (библиотек)


В терминах языка, библиотеки сторонних разработчиков на D, распространяемые в виде исходных кодов, называются пакеты. Утилита dub использует реестр пакетов, находящийся по следующему адресу. Использование библиотек, написанных с помощью C/C++ также возможно, но для этого необходимо подключение в проект специальных пакетов, называемых binding. Сама же библиотека должна быть установлена в системе. Например, libev, которая дальше будет задействована, устанавливается в debian подобных дистрибутивах linux следующим образом:
$ sudo apt-get install libev-dev

Для использования её в проекте на D нужен биндинг, который добрый человек уже сделал и разместил в выше названном реестре. Там же есть инструкция, какие изменения нужно внести в файл dub.json для использования libev в проекте. Все сводится к добавлению в раздел dependencies файла dub.json имени пакета, версии и, по необходимости, некоторых других параметров.
При следующем выполнении команды dub, все перечисленные в dependencies пакеты будут проверены и подгружены в случае их отсутствия.

Хелоуворлд с использованием libev


После выше описанных манипуляций проект готов к использованию фичей из libev. Ниже приведен код, который следует поместить в файл app.d, и если все прошло гладко, получим исполняемый файл, который будет радовать раз в секунду сообщением “Hello, World!” в консоле.

import std.stdio;
import deimos.ev;

void main()
{
	ev_timer watcher;
	extern(C) void cb_timer(ev_loop_t* loop, ev_timer* watcher, int revents) {
		writeln("Hello, World!");
	}

	auto p_loop = ev_loop_new(EVFLAG_AUTO);
	ev_timer_init(&watcher, &cb_timer, 1.0, 1.0);
	
	ev_timer_start(p_loop, &watcher);
	ev_run(p_loop, 0);
}

Что тут стоит отметить в плане использования сторонних библиотек в программах на D?
Во-первых, во второй строке подключается пакет-биндинг к libev. Во-вторых, функция обратного вызова cb_timer определена как extern(C). Фактически её вызов будет происходить из недр подключенной библиотеки, а она у нас написана на С. Следовательно, соглашение о вызове cb_timer должно соответствовать вызову функций написанных на С.

Что можно сказать в целом, глядя на код? Не считая фичи языка D, позволившей определить cb_timer в теле функции main, код мало отличается от аналогичной программы на C. Это связано с тем, что пакеты-биндинги обычно содержат минимальную обвязку над вызовами функций из сишных библиотек. Часто для удобства делается еще один уровень обвязки, который предоставляет более читаемый код с использованием “синтаксического сахара” языка D. Например, аналогичный код мог бы выглядеть как-то так.

import std.stdio;
import mercury.core;

void main()
{
    new TimerWatcher(1.0, 1.0, (revents) {
        writeln("Hello, World!");
    }).start();
    defaultEventLoop.start();
}

Кстати, код приведенный выше — реально существующий. Я попробовал сделать высокоуровневую обертку над libev, используя параметризованный класс для вотчеров. Получилось вроде неплохо. Если это будет кому-то интересно — в следующей статье расскажу об этом.

Upd: По использованию dub здесь есть неплохая статья, автор достаточно подробно описал основные возможности утилиты.

PS: Неплохо бы было уже сделать подсветку синтаксиса D в редакторе хабратопиков.
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 17

    +5
    Ожидал увидеть еще рекомендации по написанию bindings, местами бывают нетривиальные или неочевидные проблемы. Как например, глобальные переменные должны экспортированы вот так:
    extern(C) extern __gshared int my_global_int;
    
      0
      Честно говоря, я вряд ли что смог бы прояснить по вопросом написания bindings. Сам не так давно увлекся этим языком. Разбираюсь в основном с возможностями написания асинхронного сетевого кода, реализацией coroutine на Fiber и интерфейсом с CPython.

      Биндинги сам не пробовал писать, все что меня пока интересует уже есть в проектах Deimos и pyd. А при разборе кода заинтересовавших меня bindings, черпал информацию отсюда.
        0
        Ух ты, наконец-то оформили в отдельную страничку то, что приходилось собирать по новостной группе.

        Итого вы работаете с vibe.d? Сопрограммы, правда, я там не видел в чистом виде. Я его использую для синхронизации рукописных кешей для бд, очень уж удобно устроен rest-api. Также все приглядываюсь к SCTP, если реализовать его сокеты для vibe.d, то можно будет не велосипедить на UDP стриминг голоса/видео и игровых данных.
          +1
          Итого вы работаете с vibe.d?

          Нет, с vibe.d кое-что пробовал делать, но в целях самообразования решил запилить собственный велосипед :). Перебросил кое-что более-менее не стыдное показать по теме асинхронной сети из приватной репы в проект на гитхабе. Там же есть и попытки реализации короутин.
            0
            Примеры для mercury выглядят элегантно, но, конечно, это простые демки. У вайба, как у большого проекта, появился один недостаток — там черт ногу сломит разбираться во многокилометровых модулях. Вот mercury хорошо демонструет ядро асинхронного IO.
              +2
              У вайба, как у большого проекта, появился один недостаток — там черт ногу сломит разбираться во многокилометровых модулях.
              Абсолютно верно. Использовать — да, очень удобно. Понять как это работает — практически нереально. Это и послужило толчком к велосипедо-строению. Так же хотелось попробовать реализовать концепцию разделения обработки клиентских подключений на логические уровни Transport, Protocol, как это сделано в twisted.
                +1
                > Понять как это работает — практически нереально.

                Готовлю длинный цикл статей о vibe.d, в том числе с объяснением деталей реализации (я автор некоторых модулей). Но жизнь всё отвлекает и отвлекает :)
        +1
        Хочется знать больше о подходах и идиомах языка. К примеру:
        1) В c++ проектах принято писать два исходника один *.hpp и другой *.cpp. Как в этом плане у D?
        2) Какие возможности модульного тестирования? К примеру есть ли бэнчамаркинг аналогичный тому что в объекте testing языка go?
          0
          1) Исходник один, но при необходимость можно разделить описание интерфейсов от реализации в разные файлы.
          2) Стандартными возможностями языка предусмотрено включение в код юниттестов. Кроме этого есть уже пакеты, которые облегчают написание тестов, например.
            0
            1) Значит как в Java. Разбить на interface и реализацию интерфейса. Все так?
            2) Как с BDD? Ваше мнение какое о том как с этим у D?
              0
              1) Как и почти во всех остальных языках :) Да именно так, сам не пробовал. Не было пока нужды писать закрытый код, а фича эта не знаю для чего еще может быть полезна, кроме этого. В книге это определенно было описано, не могу сейчас вспомнить в какой главе, к сожалению.

              2) Насчет BDD, Вы знаете какие-то языки программирования, которые эту фичу поддерживают «из коробки»? Я не знаю, был бы рад узнать. А то касается TDD, то в D ничего не мешает постановщику задачи отправит прогеру файл типа:
              class Sqr {
              }
              
              unittest {
                  auto sqr = new Sqr();
                  assert (sqr.do(2) == 4);
                  assert (sqr.do(3) == 9);
                  assert (sqr.do(10) == 100);
              }
              

              И прогеру ничего не помешает добавить метод do:
              class Sqr {
                  int do(int value x) {
                      return x * 2;
                  }
              }
              

              И закрыть тикет).
                0
                srq (x) => x*2 — и закрыть тикет — это сильно, конечно :)
                0
                Как с BDD?

                BDD тут при чем? Это по сути методология разработки, а заимплементить Gherkin на D для функциональных/интеграционных тестов я думаю вопрос времени и желания.
            +1
            Автоматическая генерация биндингов (plain C) возможна с помощью магической утилиты github.com/jacob-carlborg/dstep
            Минусы: не будет идиоматической конвертации макросов
            Плюсы: быстро, не нужно тратить время на поддержку

            Мы используем dstep в «боевом» коде при сборке: .proto -> protobuf-compiler -> dstep, экономит много времени при изменении файлов .proto
              +1
              Ещё есть раздел в официальной вики: wiki.dlang.org/Converting_C_.h_Files_to_D_Modules с информацией немного свежее, чем на dlang.org
                0
                Добавил в пост ссылку на вашу статью о dub, почему-то она прошла мимо меня при публикации.
              0
              Есть так же серия статей от Майка Паркера (Derelict). Там неплохо разъясняются основные подводные камни.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое