четверг, 11 октября 2018 г.

[prog] Почему мне нравится наш подход к управлению зависимостями в C++ проектах

Управление зависимостями для C++ сейчас, к счастью, горячая тема. На слуху vcpkg, conan, build2, buckaroo и др. Но мы вот уже 2.5 года используем собственный велосипед, MxxRu::externals. И сегодня я попробую на простом примере показать, почему этот подход нам нравится больше всего.

Сейчас ведется работа и над следующей версией SObjectizer-а, и над следующей версией so_5_extra (so_5_extra построен над SObjectizer-ом). Внешние зависимости для so_5_extra подтягиваются с помощью MxxRu::externals. И для стабильной версии so_5_extra описание зависимостей выглядит следующим образом:

MxxRu::arch_externals :so5 do |e|
  e.url 'https://sourceforge.net/projects/sobjectizer/files/sobjectizer/SObjectizer%20Core%20v.5.5/so-5.5.22.zip'

  e.map_dir 'dev/so_5' => 'dev'
  e.map_dir 'dev/timertt' => 'dev'
  e.map_dir 'dev/various_helpers_1' => 'dev'
end

MxxRu::arch_externals :asio do |e|
  e.url 'https://github.com/chriskohlhoff/asio/archive/asio-1-12-0.tar.gz'
  e.sha1 '630580c8393edafa63e7edfad953a03fba9afb80'

  e.map_dir 'asio/include' => 'dev/asio'
end

MxxRu::arch_externals :asio_mxxru do |e|
  e.url 'https://bitbucket.org/sobjectizerteam/asio_mxxru-1.1/get/1.1.1.tar.bz2'

  e.map_dir 'dev/asio_mxxru' => 'dev'
end

MxxRu::arch_externals :doctest do |e|
  e.url 'https://github.com/onqtam/doctest/archive/1.2.8.tar.gz'

  e.map_file 'doctest/doctest.h' => 'dev/doctest/*'
end

Т.е. это простое перечисление архивов, которые нужно взять из Интернета, а потом из этих архивов нужно взять какие-то куски и разместить их внутри дерева каталогов so_5_extra.

Тут все просто и привычно.

Но вот мы начинаем работать с нестабильной версией so_5_extra, которой нужны промежуточные, нестабильные версии SObjectizer-а. Эти самые нестабильные версии SObjectizer-а, понятное дело, никуда в виде архивов не выкладывались. Поэтому мы берем SObjectizer прямо из системы контроля версий. И описание зависимостей для so_5_extra принимает вот такой вид:

=begin
MxxRu::arch_externals :so5 do |e|
  e.url 'https://sourceforge.net/projects/sobjectizer/files/sobjectizer/SObjectizer%20Core%20v.5.5/so-5.5.22.zip'

  e.map_dir 'dev/so_5' => 'dev'
  e.map_dir 'dev/timertt' => 'dev'
  e.map_dir 'dev/various_helpers_1' => 'dev'
end
=end

MxxRu::svn_externals :so5_dev do |e|
  e.url 'https://svn.code.sf.net/p/sobjectizer/repo/branches/so_5/5.5.23--dev-trunk--enveloped-msg-v4'
  e.rev 3514

  e.map_dir 'dev/so_5' => 'dev'
end

MxxRu::svn_externals :timertt_dev do |e|
  e.url 'https://svn.code.sf.net/p/sobjectizer/repo/tags/timertt/1.2.2'

  e.map_dir 'dev/timertt' => 'dev'
end

MxxRu::svn_externals :various_helpers_dev do |e|
  e.url 'https://svn.code.sf.net/p/sobjectizer/repo/tags/various_helpers_1/1.0.4'

  e.map_dir 'dev/various_helpers_1' => 'dev'
end

MxxRu::arch_externals :asio do |e|
  e.url 'https://github.com/chriskohlhoff/asio/archive/asio-1-12-0.tar.gz'
  e.sha1 '630580c8393edafa63e7edfad953a03fba9afb80'

  e.map_dir 'asio/include' => 'dev/asio'
end

MxxRu::arch_externals :asio_mxxru do |e|
  e.url 'https://bitbucket.org/sobjectizerteam/asio_mxxru-1.1/get/1.1.1.tar.bz2'

  e.map_dir 'dev/asio_mxxru' => 'dev'
end

MxxRu::arch_externals :doctest do |e|
  e.url 'https://github.com/onqtam/doctest/archive/2.0.0.tar.gz'

  e.map_file 'doctest/doctest.h' => 'dev/doctest/*'
end

Т.е. комментируется фрагмент, в котором SObjectizer берется из тарбола, добавляются временные зависимости, которые подтягивают SObjectizer, timertt и various_helpers прямо из репозитория. Потом, когда версии SObjectizer-а и so_5_extra стабилизируются, все временные зависимости будут изъяты, а SObjectizer будет браться из опубликованного (когда-то) тарболла. Но пока стабилизация не прошла, мы имеем возможность запросто забирать то, что нам нужно из конкретных ревизий конкретных временных веток репозитория.

Ну и, напоследок, явно выделю два качества MxxRu::externals, которые в таком сценарии оказываются весьма ценными:

Во-первых, для работы MxxRu::externals не нужно иметь какого-то централизованного репозитория с зависимостями. И, соответственно, не нужно выкладывать в этот репозиторий промежуточные версии зависимостей (коих может быть множество).

Во-вторых, не образуется глобальной свалки всех зависимостей, которые мне когда-либо были нужны. Я работаю в конкретном рабочем каталоге, и именно внутри этого каталога оказываются промежуточные версии зависимостей, с которыми проводятся эксперименты. Я там могу хоть сотню версий попробовать. Дальше рабочего каталога это никуда не уйдет.

К сожалению, руки никак не доходят сделать какое-то единое описание MxxRu::externals :( Для тех, кто про MxxRu::externals ничего не слышал могу только дать ссылки на коротенький рассказ с прошлогоднего CoreHard Autumn 2017:

ну и среди записей блога можно поискать по MxxRu::externals, в свое время я делал отчеты о ходе разработки этого инструмента.

Комментариев нет: