dub: менеджер зависимостей для языка D

Трудность с поиском необходимых библиотек. Проблемы с универсальной кросс-платформенной сборкой проекта. Разделение и контроль зависимостей.

Всё вышеперечисленное нередко упоминалось новичками, пытающимися использовать D, как значимое препятствие к созданию новых проектов. Популярность таких проектов как NPM и Ruby Gems формируют определённые ожидания у современных программистов. В то же время, мир нативно компилируемых программ имеет свою специфику.

DUB это попытка создать подобный инструмент для программистов на D, проект, который пользуюется огромной популярностью в сообществе и, вероятно, скоро станет официальным.

Описание


DUB это:
  • Сборка проекта на различных операционных системах простым dub build
  • Автоматическая загрузка указанных зависимости из регистра проектов
  • Контроль версий зависимостей
  • Публикация своих проектов в регистре для использования сообществом
  • Возможность запускать локальные проекты через dub run, не засоряя систему
  • Полностью открытая инфраструктура — ничто не мешает запустить свой регистр проектов или же использовать локальные пути

При этом DUB не предоставляет инструментов по дистрибуции и установке программ среди конечных пользователей и не является менеджером пакетов в полном смысле этого слова. Этот инструмент предназначен для облегчения самого процесса разработки и фокусируется исключительно на этом.

Изначально DUB был создан Sönke Ludwig в рамках проекта vibe.d, однако через некоторое время был переписан в качестве самостоятельного проекта и на данный момент является стандартом de facto для проектов на D. Предполагается, что с какого-то момента утилита станет распространятся вместе с компилятором и получит статус стандартного инструмента de jure — эта идея уже предварительно одобрена авторами языка и вопрос исключительно в более стабилизации API / формата проектов.

Установка


Для установки DUB можно использовать один из следующих вариантов:

По умолчанию, все временные файлы и кэш регистра хранится в ~/.dub или аналогичной директории локального пользователя, прав администратора для работы не требуется.

Использование


Создание проекта


Самый простой способ создать каркас для нового проекта, это использовать подкоманду init:

dub init proj1
find proj1
# proj1/
# proj1/dub.json
# proj1/source
# proj1/source/app.d
cd proj1
dub run
# proj1: ["proj1"]
# Building proj1 configuration "application", build type debug.
# Compiling...
# Linking...
# Running ./proj1 
# Edit source/app.d to start your project.


Команда dub run компилирует и запускает текущий проект согласно настройкам из dub.json, файла описания проекта. Обычно компилируются все файлы из подкаталога ./source/, а так же импортируемые ими модули. Команда dub build делает то же самое, но не запускает исполняемый файл.

Добавление зависимостей


Ключевая возможность dub, ради которой он прежде всего и был написан — автоматическая загрузка зависимостей при компиляции. Для этого нужно указать необходимые библиотеки в dub.json:

{
    "name": "proj1",
    "description": "A minimal D application.",
    "dependencies": {
        "vibe-d" : ">=0.7.18",
        "cerealed" : ">=0.5.0"
    }
}

Все зависимости зависимостей будут загружены неявно. При первой сборке приложения в логе действий будет указано, какие пакеты dub загружает и куда они сохраняются. В дальнейшем будет использовать локальный кэш до тех пор, пока не будет изменена версия зависимости в dub.json или же явно вызвана команда dub upgrade.

В коде самого приложения можно импортировать любые модули из библиотек-зависимостей, не прилагая никаких дополнительных усилий. Генерация необходимых флагов компилятора выполняется самим dub.

module app;
import vibe.d; // just works

Зависимостями могут быть не только библиотеки, но и приложения. В таком случае они будут скомпилированы перед вашим проектом и доступны для использования через dub:

dub run <package name> <application arguments ...>


Дополнительные конфигурации. Тестирование.


Команда dub test скомпилирует и выполнит все юнит-тесты вашего приложения (имеется в виду нативная возможность D: inline unittests). Однако обычно хочется держать тесты более высокого уровня, например, интеграционные, отдельно от основного приложения. Это можно добиться, использовав такую возможность dub.json, как конфигурации:

{
    "name": "proj1",
    "description": "A minimal D application.",
    "sourcePaths" : [ ],

    "configurations" : [
        {
            "name"           : "app",
            "targetType"     : "executable",
            "sourcePaths"    : [ "./source" ],
        },
        {
            "name"           : "tests",
            "sourcePaths"    : [ "./tests" ],
            "targetType"     : "executable",
            "targetName"     : "app-tests",
        }
    ]
}


find ./
# ./dub.json
# ./source
# ./source/app.d
# ./tests
# ./tests/app.d
dub build --config=tests
dub build --config=app # default

По сути, конфигурация — это просто именованый блок опций. В только что приведённом примере используется такой параметр dub.json, как sourcePaths — список директорий с исходниками для используемой конфигурации. По умолчанию в этом списке всегда есть директория "./source", поэтому необходимо сбросить этот параметр в глобальной секции dub.json:

    "sourcePaths" : [ ]

Первая из конфигураций в списке всегда используется как конфигурация по умолчанию, поэтому практично использовать её для параметров обычной сборки приложения. В случае, если используется только одна конфигурация, само собой, все эти параметры можно просто указывать в глобальной секции.

Исходники проекта-примера можно и нужно потрогать: github.com/Dicebot/examples/tree/master/dub/proj1

Больше информации


Приведённой выше информации должно хватить для конвертации большинства простых проектов. Для удовлетворения реальных рабочих потребностей, конечно же, может понадобиться куда больше. Рекомендации для дальнейшего изучения:

Наиболее полное описание формата dub.json: code.dlang.org/package-format
Подборка примеров в репозитории проекта: github.com/rejectedsoftware/dub/tree/master/examples
Вопросы / предложения / пожелания: forum.rejectedsoftware.com/groups/rejectedsoftware.dub

… а так же задавайте вопросы здесь.

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

Happy coding.
Поделиться публикацией
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 17
    +1
    В dub наконец-то появилась инкрементальная сборка, ждать по 5 мин пока вместе с твоим hello-world компилится весь gtk-d — вот это было издевательством.

    Стоило бы упомянуть о крайне полезных platform suffixes, которые специализирует параметры для конкретной платформы, например:
    "libs-posix": ["ssl", "crypto"]
    

      +1
      С инкрементальной сборкой нужно быть осторожным в проектах с большим количеством шаблонов — ещё не так давно логика определения instantiation module давала частые сбои, что давало замечательно невразумительные ошибки линкера. С тех пор в этом направлении было сделано много исправлений / улучшений, но шансы наткнуться на шальной баг ещё есть.

      Не хотелось превращать вступительную заметку в дотошный мануал по всем возможностям dub, оттого многие полезные возможности не упомянуты.
      +2
      Блин, вот почему когда это делается для новых, скриптовых, JAVA, C# подобных языков, это принимается как «ура, да здравствует мир во всем мире, давайте это запихнем в стандартную поставку, что бы всем было легче жить», а когда подобную штуку предлагаешь для С++ тебя закидывают тапками, ставят в угол, и говорят мол юзай то то и то то и нехрен выеживаться.

      Вот почему бы такое не сделать для CMake, ведь единственное проблема тут, это собрать все библиотеки вместе и поддерживать их актуальность. Нет, бл* скачай, собери, пропиши куда надо. А если нужно две версии для экспериментов, то ваще пиши пропало.
        0
        Я даже как-то порывался написать аналог хаскелевского Cabal для C++. Мне кажется, модель cabal весьма уместна для плюсов: сборка из исходников, вашим компилятором, на вашей платформе. Дьявол, как всегда, в деталях…
          0
          Есть еще возможность Maven июзать с С++, я даже реп находил, правда он умер еще в зародыше. Хотя в CERN его (Maven) для С++ используют. Но я так думаю что он свой реп для своих проектов только построили.
            0
            Модели maven и в gradle в контексте C++ мне совсем не нравятся. Они хранят в репозиториях собранные бинарные версии. С кросс-платформенным java-байткодом это отлично работает, а с нативными исполняемыми файлами возникает слишком много проблем. В рамках отдельных компаний это может работать, как универсальное решение — врядли.
              0
              Ну это же не мешает хранить пакеты библиотек в репах ОС?

              Вообще я вижу два подхода (в том числе оба могут работать одновременно). Первый это забирать готовые собранные пакеты с репа. Второй это качать сурсы и собирать в локальном репе.

              Проблему я виже только в том, что сейчас полных хаос со сборкой С/C++ проектов. Каждый собирается по своими сферическим правила, со своими сферическими зависимостями. А нужно это как то все уметь свести к единому виду. Ну или просто написать кучу адаптеров для все возможных режимов сборки.
                0
                > забирать готовые собранные пакеты с репа
                Вот такой подход мне как раз не нравится. Так нужно хранить собранные версии для всех платформ, операционных систем, конфигураций сборки. А ещё типично огромное кол-во макросов, конфигурируемых при сборке через ./configure.
                В java/groovy таких проблем нет, поэтому там всё работает :)
                Кстати, в Google тоже всегда всё собирается из исходников (объектники, собиравшиеся из в точности тех же версий с теми же ключами, конечно, кэшируются).
                  0
                  Так ли уж все? Достаточно лишь каких то основных конфигураций (зачем в репе хранить debug? хотя если позволяет место то почему бы и нет), Зачем разные сборки под разные ОС? Нужно лишь под разные версии g++ и платформы.

                  А любую более изотерическую сборку делать локально.
        0
        Кстати, у CMake есть интересная фича — ExternalProjects. До нормального пакетного менеджера очень далеко, но уже весьма полезно.
          0
          Я бы не сказал, что dub легко был принят сообществом. В самом начале был еще Orbit и не все соглашались с идеей брать пакеты с github реп, компилировать из исходников, иметь немодерируемый регистр.

          Буквально несколько месяцев назад кол-во пакетов в dub начало ускоренно расти, разработчики, наконец-то, начали использовать dub и TravisCI.
            0
            Я согласен с тем, что сперва надо сделать, да так, что бы сразу решить большинстно очевидных проблем, и еще предоставить задел на будущее в виде легкого расширения и убодного (крайне удобного механизма) побликации новых пакетов и полной автоматизацией всей рутины. И только тогда появится шанс что народ на это подсядед.
              0
              Orbit заметно отличался от dub.

              Во-первых, его автор, Jacob Carlborg, во многом брал пример с Ruby, но копирование модели gems грозило большой головной болью в поддержке пакетов дистрибутивов.
              Во-вторых, реализация практически без использования стандартной библиотеки ставила крест на возможном включении в список официальных инструментов.
              И, что немаловажно, dub был изначально создан как часть проекта vibe.d и разрабатывался по мере вполне конкретных практических потребностей.

              Изначально, конечно, было много возражений и неприязни, но это осталось в прошлом. Сейчас полезность dub признается даже теми, кто его не использует (вроде меня :)).
                +1
                P.S. есть очень больше желание сделать аналог Travis привязанный к code.dlang.org, с учётом всей специфики D, проблема, как всегда, в том чтобы сесть и сделать :)
                  0
                  Идея мне нравится, но нужен мощный хост, решить проблему виртуализации и интеграции с third-party зависимостями. Сейчас уже есть отработанные конфиги под Travis, только не хватает интеграции с регистром. Было бы гораздо проще выдергивать с реп ссылки на травис и отображать в регистре эту travis-button.
                    0
                    У меня есть полудомашний сервер (core i5 / 8 Gb), от которого не жалко часть мощностей выделить на эту задачу. Нагрузка на сервер на слишком большая, т.к. для регистра достаточно актуальности статуса сборки в ~1 день, можно не дёргать на каждый коммит. Основная работа тут это модификация github.com/rejectedsoftware/dub-registry для поддержки информации по статусу тестов из внешних источников.

                    Если интересно эти заняться, можно всё обсудить после DConf.

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

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