Dlang, или просто D — молодой язык программирования с многолетней историей. Не смотря на то, что язык с таким названием появился очень давно, то, что сейчас называется D2 или просто D, появилось недавно и слабо напоминает предшественника. Писать на D очень удобно, а произодительность не уступает C++, поэтому не удивительно, что он добрался до ARM и его мобильных представителей Android и iOS. Кроме того растёт интерес к интернету вещей и просто портативным устройствам.
В статье рассмотрена задача кросскомпиляции кода на dlang для Raspberry Pi. В этом нет ничего сложного, да и подводных камней не замечено. Данная публикация — простой мануал для начала использования D на разных устройствах в целом и Raspberry Pi в частности.
Hello, World
Нам понадобится:
- Компьютер с линуксом (в моём случае Ubuntu 14.04 на виртуалке)
- Raspberry Pi с ssh доступом (использована Raspberry Pi B+)
Не смотря на то, что можно собирать исходники прямо на Raspberry Pi, лучше это делать на отдельном более мощном компьютере. На самой малине слишком мало памяти, а кросскомпиляция под Raspberry Pi – дело несложное. Для начала нам нужен компилятор dlang для Raspberry Pi. Тут два варианта: LDC (LLVM based D Compiler) и GDC (GNU D Compiler). Проще оказалось найти подходящую версию GDC. LDC под ARM есть и его тоже можно использовать, просто так сложилось, что я использую GDC.
Идём на сайт GDC в раздел downloads.
Скачиваем x86_64 сборку для целевой платформы arm-linux-gnueabihf (тут по-внимательнее, сам GDC будет запускаться на x86, а таргет armhf; не путать с GDC для arm, который запускается на устройстве).
wget http://gdcproject.org/downloads/binaries/5.2.0/x86_64-linux-gnu/gdc-5.2.0-arm-linux-gnueabihf+2.066.1.tar.xz
Распаковываем
tar -xf gdc-5.2.0-arm-linux-gnueabihf+2.066.1.tar.xz
для удобства я ещё переименовал папку
mv arm-unknown-linux-gnueabihf gdc-arm
Для постоянного использования я скопировал папку с gdc в /usr/bin и сделал алиас gdc-arm, но для примера к статье будем всё делать локально в папке. И так создаём ссылку-шорткат:
ln -s gdc-arm/bin/arm-linux-gnueabihf-gdc gdc
Вообще говоря, этого уже достаточно чтобы собирать D код под Raspberry PI. Проверим на примере Hello, world. Итак пишем исходник:
import std.stdio;
void main() {
writeln("Hello, World!");
}
И сохраняем в hello.d. Компилируем:
./gdc hello.d -o hello
Теперь копируем на девайс идём на него и проверяем. У меня это выглядело так:
scp hello pi@192.168.1.85/~/dlang/hello
А на девайсе:
pi@raspberrypi:~/dlang $ ./hello
Hello, World!
Усложняем задачу – линковка библиотек
Всё, описанное выше, тривиально и работает из коробки. Теперь соберём что-то посложнее. Например, «Hello, vibe.d», то есть примитивное приложение на web фреймвёрке vibe.d. Отличие от обычного HelloWorld одно – нужно линковать библиотеки. Кросскомпиляция dlang в этом вопросе ничем не отличается от C, C++ и других компилируемых языков. Поэтому можно использовать любой удобный подход к кросскомпиляции на Raspberry Pi.
Библиотеки нужны для конкретной архитектуры и их лучший источник – репозиторий, установленного на Raspberry дистрибутива. Обычно это https://www.raspbian.org/RaspbianRepository. Проще всего использовать библиотеки прямо с самого устройства. Только не собирать на нём (очень плохая идея, очень медленно и вечно в свопе), а просто использовать файлы. Хорошей идеей будет использовать sshfs (подсмотрено здесь: wiki.dlang.org/GDC/Cross_Compiler/Existing_Sysroot). Основное преимущество данного подхода – абсолютная универсальность и стабильность. Не важно какой дистрибутив установлен, будут взяты идеально подходящие библиотеки. Нет никаких конфликтов и несоответствия версий дистрибутива или библиотек.
Создаём папку, в которую смонтируем всю файловую систему Raspberry Pi и записываем её в переменную окружения:
mkdir rpi
echo $RPIROOT
export RPIROOT=~/test_pi/rpi/
echo $RPIROOT
/home/user/test_pi/rpi/
Монтируем через sshfs:
sshfs -o idmap=user,follow_symlinks pi@192.168.1.85:/ $RPIROOT
Так как нам нужно указывать архитектуру и пути поиска либ, для сокращения записи создадим ещё один шорткат. Создадим файлик gdc-rpi и запишем туда скрипт для запуска GDC с нужными флагами.
#!/bin/bash
~/test_pi/gdc -march=armv6j -mfpu=vfp -mfloat-abi=hard --sysroot=$RPIROOT -B$RPIROOT/usr/lib/arm-linux-gnueabihf "$@"
Тут немного подробнее: -march=armv6j -mfpu=vfp -mfloat-abi=hard – это флаги архитектуры процессора Raspberry Pi. sysroot — рут девайса, -B – место поиска либ, у нас оно на самом же девайсе в usr/lib
Добавляем прав на запуск и проверяем:
user@ubuntu:~/test_pi$ chmod 777 gdc-rpi
user@ubuntu:~/test_pi$ ./gdc-rpi
gdc: fatal error: no input files
compilation terminated.
Всё работает, теперь нам на билд-машине нужен DUB (это билд-система и за одно менеджер зависимостей). Качаем и ставим его любым удобным способом, описанным здесь.
Создаём простой проект vibe.d:
dub init -tvibe.d test_vibe_pi
DUB создаст папку с минимальным проектом внутри. Теперь собираем:
cd test_vibe_pi/
dub build --compiler=../gdc-rpi
На выходе имеем файлик test_vibe_pi. Если нет чего-то вроде libcurl, то идём на девайс и apt-get'ом ставим всё необходимое. У меня уже всё было после прошлых экспериментов.
Копируем его на девайс и проверяем:
cp test_vibe_pi $RPIROOT/home/pi/dlang
На Raspberry Pi:
pi@raspberrypi:~/dlang $ ./test_vibe_pi
Listening for requests on http://[::1]:8080/
Listening for requests on http://127.0.0.1:8080/
Please open http://127.0.0.1:8080/ in your browser.
Всё, минимальный сайтик, отдающий «Hello, World!» на любой запрос на 127.0.0.1:8080/, готов.
Для тех, кто хочет собирать свои проекты прямо на устройстве
Собирать код на столь слабом устройстве — плохая идея, но иногда удобнее выкатывать проект на девайс в виде исходников. GDC для Raspberry есть готовый, можно идти в раздел ARM gdcproject.org/downloads и качать armhf версию. Для сборки скорее всего понадобится DUB и вот его придётся собирать, потому что готовый бинарь с сайта не запускается на Raspberry Pi B+.
Качаем исходники с сайта https://code.dlang.org/download (можно с гитхаба, это уж как хочется). Распаковываем, складываем в папку с удобным называнием
user@ubuntu:~/test_pi$ wget https://github.com/rejectedsoftware/dub/archive/v0.9.24.tar.gz
user@ubuntu:~/test_pi$ tar -xf v0.9.24.tar.gz
user@ubuntu:~/test_pi$ mv dub-0.9.24/ dub
user@ubuntu:~/test_pi$ cd dub
Для сборки под линуксом с использованием GDC есть отдельный скрипт: build-gdc.sh. Он ожидает, что gdc есть в системе, либо задана переменная окружения GDC. Используем переменную. Просто указываем путь до нашего скрипта-шортката и запускаем:
GDC=../gdc-rpi ./build-gdc.sh
Generating version file...
./build-gdc.sh: 15: ./build-gdc.sh: git: not found
Running ../gdc-rpi...
DUB has been built as bin/dub.
You may want to run
sudo ln -s /home/user/test_pi/dub/bin/dub /usr/local/bin
now.
Если получен этот вывод и никаких ошибок линковки, то теперь есть рабочий DUB для Raspberry Pi. Копируем на девайс и проверяем.
user@ubuntu:~/test_pi/dub$ cd ..
user@ubuntu:~/test_pi$ cp dub/bin/dub rpi/home/pi/dlang/dub-test/dub
На устройстве:
pi@raspberrypi:~/dlang/dub-test $ ./dub
Neither a package description file, nor source/app.d was found in
/home/pi/dlang/dub-test
Please run DUB from the root directory of an existing package, or run
"dub init --help" to get information on creating a new package.
Failed to find a package named ''.
DUB запустился и справедливо заметил отсутствие проекта в папке. Проекта у нас действительно нет, а главная цель достигнута – DUB работает на Raspberry Pi.
Вот и всё, мы можем собирать любые проекты на D под Rapberry Pi. Например, можно запустить сервер для умного дома. Есть поддержка MQTT в виде плагина к vibe.d, а так же возможность использовать любую существующую C библиотеку.
Комментарии (12)
scifix
11.03.2016 20:57а зачем D если есть C?)
bfDeveloper
11.03.2016 21:52Холиварный вброс, но всё же отвечу. Затем, что быстрее. Бытрее писать и внезапно быстрее работает.
Писать быстрее благодаря обилию алгоритмов, шаблонов, нормальной типизации, безопасности (в виде RAII, контрактов, тестов и сборке мусора) и кучи плюшек (http://dlang.org/ctod.html).
Быстрее работает — немного спорное утверждение. Эквивалентный код чуть медленнее, но на D не пишут как на C. Банальный пример: там, где в C будет массив или копия массива, в D будет ленивый диапазон. По моему опыту замена конкатенации строк на ленивый диапазон даёт прирост скорости 6 раз. Опыт портирования проектов с С или С++ говорит об ускорении результата. Например, в фейсбуке портировали небольшую библиотеку https://code.facebook.com/posts/729709347050548/under-the-hood-building-and-open-sourcing-flint/ D версия работает быстрее.
Чтобы повторить то, что даёт стандартная библиотека диапазонов в D, понадобится куча кода на C, который никто просто не будет писать. Писать быстрый код на D быстрее. Писать обычный код ещё быстрее.
Писать супероптимизированный код на D тоже проще, так как ничто не мешает опуститься до уровня C, пользоваться указателями и всеми низкоуровневыми оптимизациями вплоть до встроенного ассемблера. Вот только мощность шаблонов и прочих фич времени выполнения будет помогать даже на низком уровне и всем этим можно пользоваться.
Ситуаций, в которых D уступает C или C++, очень мало и с каждым днём становится всё меньше.BelBES
11.03.2016 23:41На D уже есть поддержка CUDA/OpenCL, или только через какие-нибудь биндинги(ну или как это в D называется) C/C++?
bfDeveloper
12.03.2016 17:12Есть динамический биндинг OpenCL. http://code.dlang.org/packages/derelict-cl
Это просто описанный интрефейс к обычному OpenCL. Как хэдеры в сях. Аналогичная штука есть для CUDA
http://code.dlang.org/packages/derelict-cuda
scifix
12.03.2016 07:13из статьи просто непонятно чем же лучше D и что в нем такого.helloworld везде можно написать
guai
15.03.2016 18:28«Пишем на D для Raspberry Pi» — разве статья не соответствует заявленному в заголовке? Где там про «лучше»?
scifix
15.03.2016 18:45соответствует, но надо раскрывать тему подробнее, а иначе в чем смысл.Самое главное — не раскрыт смысл слова "Пишем")
bfDeveloper
15.03.2016 19:35Согласен, язык не так популярен на хабре, стоило подробнее описать, зачем вообще писать на D. Восполню пробел парой ссылок на статьи на хабре:
https://habrahabr.ru/post/246623/
https://habrahabr.ru/post/224419/
https://habrahabr.ru/post/197480/
https://habrahabr.ru/post/154345/
guai
15.03.2016 20:08не уверен, что именно под пирожок именно на D писать лучше. Сишные либы подрубаются точно так же, как и в плюсы. Но вообще D приятнее во многих аспектах. На хабре есть хорошие вводные статьи, в тэге легко найдёте, там пока не много…
BelBES
А как там дела с перформансами обстоят на этой железяке "C++ vs. D" ?
bfDeveloper
Бенчмарков не ставил, но не вижу причин, почему он должен отличаться от x86. Бэкенд у компиляторов одинаковый, сами языки примерно на одном уровне производительности, так что +- то же самое.