C++ CoreHard Autumn 2017
MxxRu::externals
Repositoryless Dependency Manager
Евгений Охотников
Откуда ноги растут?
Начало 2016-го года.
Нужно было уйти с Svn на Git или Hg.
Но Svn использовался и для управления зависимостями (svn:externals).
Аналоги svn:externals в Git и в Hg не понравились.
biicode умер, conan и hunter только-только появились, vcpkg еще не было...
Наиболее подходящим был CMake-овский ExternalProject_Add. Но сам CMake...
2
Чего хотелось достичь?
Взять любой чужой проект в исходниках и подключить к себе то, что из этого
проекта нужно.
Чужой проект должен жить и распространяться так, как удобно авторам
чужого проекта. Нельзя рассчитывать на то, что они сделают нужный тебе
пакет и зальют в нужный репозиторий.
Должны поддерживаться Git, Hg, Svn и архивы (zip, .tar.gz, .tar.bz2, .tar.xz)...
Работа под Windows, Linux, FreeBSD + MacOS (если повезет).
3
Ну и мы этого достигли
require 'mxx_ru/externals'
MxxRu::git_externals :asio do |e|
e.url 'https://github.com/chriskohlhoff/asio.git'
e.commit 'f5c570826d2ebf50eb38c44039181946a473148b'
e.map_dir 'asio/include' => 'dev/asio'
end
MxxRu::arch_externals :nodejs_http_parser do |e|
e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz'
e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*'
e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*'
end
MxxRu::hg_externals :eigen do |ext|
ext.url = 'https://bitbucket.org/eigen/eigen'
ext.tag = '3.2.5'
ext.map_dir 'Eigen' => 'dev'
ext.map_file 'INSTALL' => 'INSTALL.eigen'
end
4
Забрать зависимость из Git
require 'mxx_ru/externals'
MxxRu::git_externals :asio do |e|
e.url 'https://github.com/chriskohlhoff/asio.git'
e.commit 'f5c570826d2ebf50eb38c44039181946a473148b'
e.map_dir 'asio/include' => 'dev/asio'
end
MxxRu::arch_externals :nodejs_http_parser do |e|
e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz'
e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*'
e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*'
end
MxxRu::hg_externals :eigen do |ext|
ext.url = 'https://bitbucket.org/eigen/eigen'
ext.tag = '3.2.5'
ext.map_dir 'Eigen' => 'dev'
ext.map_file 'INSTALL' => 'INSTALL.eigen'
end
5
MxxRu::git_externals :asio do |e|
e.url 'https://github.com/chriskohlhoff/asio.git'
e.commit 'f5c570826d2ebf50eb38c44039181946a473148b'
e.map_dir 'asio/include' => 'dev/asio'
end
Забрать зависимость из Hg
require 'mxx_ru/externals'
MxxRu::git_externals :asio do |e|
e.url 'https://github.com/chriskohlhoff/asio.git'
e.commit 'f5c570826d2ebf50eb38c44039181946a473148b'
e.map_dir 'asio/include' => 'dev/asio'
end
MxxRu::arch_externals :nodejs_http_parser do |e|
e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz'
e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*'
e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*'
end
MxxRu::hg_externals :eigen do |ext|
ext.url = 'https://bitbucket.org/eigen/eigen'
ext.tag = '3.2.5'
ext.map_dir 'Eigen' => 'dev/Eigen'
ext.map_file 'INSTALL' => 'INSTALL.eigen'
end
6
MxxRu::hg_externals :eigen do |ext|
ext.url = 'https://bitbucket.org/eigen/eigen'
ext.tag = '3.2.5'
ext.map_dir 'Eigen' => 'dev'
ext.map_file 'INSTALL' => 'INSTALL.eigen'
end
Забрать зависимость из архива
require 'mxx_ru/externals'
MxxRu::git_externals :asio do |e|
e.url 'https://github.com/chriskohlhoff/asio.git'
e.commit 'f5c570826d2ebf50eb38c44039181946a473148b'
e.map_dir 'asio/include' => 'dev/asio'
end
MxxRu::arch_externals :nodejs_http_parser do |e|
e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz'
e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*'
e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*'
end
MxxRu::hg_externals :eigen do |ext|
ext.url = 'https://bitbucket.org/eigen/eigen'
ext.tag = '3.2.5'
ext.map_dir 'Eigen' => 'dev'
ext.map_file 'INSTALL' => 'INSTALL.eigen'
end
7
MxxRu::arch_externals :nodejs_http_parser do |e|
e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz'
e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*'
e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*'
end
Как это работает?
1. Подготавливается нужная структура каталогов.
8
~/my_project
├── dev/
├── LICENSE
└── README.md
Как это работает?
2. В корень помещается externals.rb
9
~/my_project
├── dev/
├── externals.rb
├── LICENSE
└── README.md
require 'mxx_ru/externals'
MxxRu::git_externals :asio do |e|
e.url 'https://github.com/chriskohlhoff/asio.git'
e.commit 'f5c570826d2ebf50eb38c44039181946a473148b'
e.map_dir 'asio/include' => 'dev/asio'
end
MxxRu::arch_externals :nodejs_http_parser do |e|
e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz'
e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*'
e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*'
end
MxxRu::hg_externals :eigen do |ext|
ext.url = 'https://bitbucket.org/eigen/eigen'
...
Как это работает?
3. В корне запускается mxxruexternals
10
~/my_project
├── dev/
├── externals.rb
├── LICENSE
└── README.md
$ cd ~/my_project
$ mxxruexternals
[Info] Generation of auxilary rakefile: ./mxxruexternals-temp20171011-19367-10hgydw
[Info] Launching rake with: rake -f ./mxxruexternals-temp20171011-19367-10hgydw install
mkdir -p .externals
git clone https://github.com/chriskohlhoff/asio.git .externals/asio.19369.10694860
Cloning into '.externals/asio.19369.10694860'...
Как это работает?
11
~/my_project
├── dev
...
└── .externals
├── asio
│ ├── asio
│ └── .git
├── eigen
│ ├── bench
...
│ └── .hg
└── nodejs_http_parser
└── contrib
mxxruexternals загружает все
зависимости в отдельный подкаталог
└── .externals
├── asio
│ ├── asio
│ └── .git
├── eigen
│ ├── bench
...
│ └── .hg
└── nodejs_http_parser
└── contrib
Как это работает?
12
~/my_project
├── dev
│ ├── asio
│ │ └── include
│ ├── Eigen
│ │ └── src
│ └── nodejs
│ └── http_parser
└── .externals
├── asio
│ ├── asio
│ └── .git
├── eigen
│ ├── bench
...
│ └── .hg
└── nodejs_http_parser
└── contrib
Затем mxxruexternals копирует только
то, что нам нужно и туда, куда нужно:
└── dev
├── asio
│ └── include
├── Eigen
│ └── src
└── nodejs
└── http_parser
Как это работает?
4. Получаем результат
13
~/my_project
├── dev
│ ├── asio
│ │ └── include
│ ├── Eigen
│ │ └── src
│ └── nodejs
│ └── http_parser
└── .externals
├── asio
│ ├── asio
│ └── .git
├── eigen
│ ├── bench
...
│ └── .hg
└── nodejs_http_parser
└── contrib
Ну и как оно?
Очень удобно!
Полтора года в активном использовании.
Пока не довелось попробовать с большими зависимостями вроде Boost, ICU,
Qt и т.п.
Что доводилось подключать чужого: ACE, Asio (standalone), Beast, C++REST
SDK, Catch, Pistache, RapidJSON, RestBed, SOCI, fmt, libmosquitto, spdlog
14
Как взять и попробовать?
Установить Ruby (и RubyGems)
Установить Mxx_ru:
gem install Mxx_ru
Поискать примеры и описания здесь: eao197.blogspot.com
До нормальной документации пока руки не дошли.
15
Будущее?
Не факт, что оно есть у самого MxxRu::externals...
Но может быть это кого-то подтолкнет к созданию чего-то более удачного.
Поскольку conan, hunter, cppan, vcpkg и пр. менеджеры с репозиториями
пакетов ‒ это хорошо, но вряд ли подходит для очень сегментированного
мира C++.
16

MxxRu::externals: Repositoryless Dependency Manager

  • 1.
    C++ CoreHard Autumn2017 MxxRu::externals Repositoryless Dependency Manager Евгений Охотников
  • 2.
    Откуда ноги растут? Начало2016-го года. Нужно было уйти с Svn на Git или Hg. Но Svn использовался и для управления зависимостями (svn:externals). Аналоги svn:externals в Git и в Hg не понравились. biicode умер, conan и hunter только-только появились, vcpkg еще не было... Наиболее подходящим был CMake-овский ExternalProject_Add. Но сам CMake... 2
  • 3.
    Чего хотелось достичь? Взятьлюбой чужой проект в исходниках и подключить к себе то, что из этого проекта нужно. Чужой проект должен жить и распространяться так, как удобно авторам чужого проекта. Нельзя рассчитывать на то, что они сделают нужный тебе пакет и зальют в нужный репозиторий. Должны поддерживаться Git, Hg, Svn и архивы (zip, .tar.gz, .tar.bz2, .tar.xz)... Работа под Windows, Linux, FreeBSD + MacOS (если повезет). 3
  • 4.
    Ну и мыэтого достигли require 'mxx_ru/externals' MxxRu::git_externals :asio do |e| e.url 'https://github.com/chriskohlhoff/asio.git' e.commit 'f5c570826d2ebf50eb38c44039181946a473148b' e.map_dir 'asio/include' => 'dev/asio' end MxxRu::arch_externals :nodejs_http_parser do |e| e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz' e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*' e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*' end MxxRu::hg_externals :eigen do |ext| ext.url = 'https://bitbucket.org/eigen/eigen' ext.tag = '3.2.5' ext.map_dir 'Eigen' => 'dev' ext.map_file 'INSTALL' => 'INSTALL.eigen' end 4
  • 5.
    Забрать зависимость изGit require 'mxx_ru/externals' MxxRu::git_externals :asio do |e| e.url 'https://github.com/chriskohlhoff/asio.git' e.commit 'f5c570826d2ebf50eb38c44039181946a473148b' e.map_dir 'asio/include' => 'dev/asio' end MxxRu::arch_externals :nodejs_http_parser do |e| e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz' e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*' e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*' end MxxRu::hg_externals :eigen do |ext| ext.url = 'https://bitbucket.org/eigen/eigen' ext.tag = '3.2.5' ext.map_dir 'Eigen' => 'dev' ext.map_file 'INSTALL' => 'INSTALL.eigen' end 5 MxxRu::git_externals :asio do |e| e.url 'https://github.com/chriskohlhoff/asio.git' e.commit 'f5c570826d2ebf50eb38c44039181946a473148b' e.map_dir 'asio/include' => 'dev/asio' end
  • 6.
    Забрать зависимость изHg require 'mxx_ru/externals' MxxRu::git_externals :asio do |e| e.url 'https://github.com/chriskohlhoff/asio.git' e.commit 'f5c570826d2ebf50eb38c44039181946a473148b' e.map_dir 'asio/include' => 'dev/asio' end MxxRu::arch_externals :nodejs_http_parser do |e| e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz' e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*' e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*' end MxxRu::hg_externals :eigen do |ext| ext.url = 'https://bitbucket.org/eigen/eigen' ext.tag = '3.2.5' ext.map_dir 'Eigen' => 'dev/Eigen' ext.map_file 'INSTALL' => 'INSTALL.eigen' end 6 MxxRu::hg_externals :eigen do |ext| ext.url = 'https://bitbucket.org/eigen/eigen' ext.tag = '3.2.5' ext.map_dir 'Eigen' => 'dev' ext.map_file 'INSTALL' => 'INSTALL.eigen' end
  • 7.
    Забрать зависимость изархива require 'mxx_ru/externals' MxxRu::git_externals :asio do |e| e.url 'https://github.com/chriskohlhoff/asio.git' e.commit 'f5c570826d2ebf50eb38c44039181946a473148b' e.map_dir 'asio/include' => 'dev/asio' end MxxRu::arch_externals :nodejs_http_parser do |e| e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz' e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*' e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*' end MxxRu::hg_externals :eigen do |ext| ext.url = 'https://bitbucket.org/eigen/eigen' ext.tag = '3.2.5' ext.map_dir 'Eigen' => 'dev' ext.map_file 'INSTALL' => 'INSTALL.eigen' end 7 MxxRu::arch_externals :nodejs_http_parser do |e| e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz' e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*' e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*' end
  • 8.
    Как это работает? 1.Подготавливается нужная структура каталогов. 8 ~/my_project ├── dev/ ├── LICENSE └── README.md
  • 9.
    Как это работает? 2.В корень помещается externals.rb 9 ~/my_project ├── dev/ ├── externals.rb ├── LICENSE └── README.md require 'mxx_ru/externals' MxxRu::git_externals :asio do |e| e.url 'https://github.com/chriskohlhoff/asio.git' e.commit 'f5c570826d2ebf50eb38c44039181946a473148b' e.map_dir 'asio/include' => 'dev/asio' end MxxRu::arch_externals :nodejs_http_parser do |e| e.url 'https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz' e.map_file 'http_parser.h' => 'dev/nodejs/http_parser/*' e.map_file 'http_parser.c' => 'dev/nodejs/http_parser/*' end MxxRu::hg_externals :eigen do |ext| ext.url = 'https://bitbucket.org/eigen/eigen' ...
  • 10.
    Как это работает? 3.В корне запускается mxxruexternals 10 ~/my_project ├── dev/ ├── externals.rb ├── LICENSE └── README.md $ cd ~/my_project $ mxxruexternals [Info] Generation of auxilary rakefile: ./mxxruexternals-temp20171011-19367-10hgydw [Info] Launching rake with: rake -f ./mxxruexternals-temp20171011-19367-10hgydw install mkdir -p .externals git clone https://github.com/chriskohlhoff/asio.git .externals/asio.19369.10694860 Cloning into '.externals/asio.19369.10694860'...
  • 11.
    Как это работает? 11 ~/my_project ├──dev ... └── .externals ├── asio │ ├── asio │ └── .git ├── eigen │ ├── bench ... │ └── .hg └── nodejs_http_parser └── contrib mxxruexternals загружает все зависимости в отдельный подкаталог └── .externals ├── asio │ ├── asio │ └── .git ├── eigen │ ├── bench ... │ └── .hg └── nodejs_http_parser └── contrib
  • 12.
    Как это работает? 12 ~/my_project ├──dev │ ├── asio │ │ └── include │ ├── Eigen │ │ └── src │ └── nodejs │ └── http_parser └── .externals ├── asio │ ├── asio │ └── .git ├── eigen │ ├── bench ... │ └── .hg └── nodejs_http_parser └── contrib Затем mxxruexternals копирует только то, что нам нужно и туда, куда нужно: └── dev ├── asio │ └── include ├── Eigen │ └── src └── nodejs └── http_parser
  • 13.
    Как это работает? 4.Получаем результат 13 ~/my_project ├── dev │ ├── asio │ │ └── include │ ├── Eigen │ │ └── src │ └── nodejs │ └── http_parser └── .externals ├── asio │ ├── asio │ └── .git ├── eigen │ ├── bench ... │ └── .hg └── nodejs_http_parser └── contrib
  • 14.
    Ну и каконо? Очень удобно! Полтора года в активном использовании. Пока не довелось попробовать с большими зависимостями вроде Boost, ICU, Qt и т.п. Что доводилось подключать чужого: ACE, Asio (standalone), Beast, C++REST SDK, Catch, Pistache, RapidJSON, RestBed, SOCI, fmt, libmosquitto, spdlog 14
  • 15.
    Как взять ипопробовать? Установить Ruby (и RubyGems) Установить Mxx_ru: gem install Mxx_ru Поискать примеры и описания здесь: eao197.blogspot.com До нормальной документации пока руки не дошли. 15
  • 16.
    Будущее? Не факт, чтооно есть у самого MxxRu::externals... Но может быть это кого-то подтолкнет к созданию чего-то более удачного. Поскольку conan, hunter, cppan, vcpkg и пр. менеджеры с репозиториями пакетов ‒ это хорошо, но вряд ли подходит для очень сегментированного мира C++. 16