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

в 19:32, , рубрики: dlang, dub, libev, Программирование, Проектирование и рефакторинг, метки: , ,

На волне интереса к языку 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 dev-libev

Для использования её в проекте на 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 hilevel.libev;

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

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

PS: Неплохо бы было уже сделать подсветку синтаксиса D в редакторе хабратопиков.

Автор: Alesh

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js