Comments 72
Увы, у Conan есть одна фундаментальная проблема — он работает исключительно с репозиториями пакетов. Т.е. нельзя использовать проект на Github или в любом другом хранилище кода как зависимость. Объявлять локальные папки как зависимости вроде можно, но как минимум заморочно. Разработчики аргументируют это тем, что Conan умеет разрешать конфликты версий и хранить бинарные артефакты.
И правильно делают, имхо. Посмотрите какие в Go проблемы из-за того что изначально выбрали такую схему
Репозитории Git не должны быть ни основным ни, тем более, единственным источником зависимостей. Но такая возможность должна быть, тем более в С++ мире, где разброд и шатания.
А разве я что-то говорил про хаскелевый Stack? :)
Конкретно go get
не умеет ни в коммиты, ни в теги, ни в ветки. То есть если у вас нет своего форка зависимости, вы постоянно ссылаетесь на HEAD дефолтной ветки репозитория.
То есть, ни репродьюсибл билдов, ни нормального версионирования зависимостей и понимания вообще что попадает в бинарь (если самому это не трекать в какой-то мета файл).
Ну и, в принципе, всё, помимо коммита, при стягивании зависимостей из гит репозиториев ненадежно, тк можно сделать force-push.
Как люди живут с этим, делают CI и CD и потом спят спокойно мне вообще непонятно.
Ну и, конечн, поражает, как Go комьюнити к этому относится, многие не понимают причин хотеть стабильный билд, некоторые еще и дизлайкают лол:
- https://github.com/golang/go/issues/21933
- https://habrahabr.ru/post/250281/#comment_8276057
- https://stackoverflow.com/questions/24855081/how-do-i-import-a-specific-version-of-a-package-using-go-get
Благо другая часть комьюнити пришла с платформ где это норма и таки пытаются пропихнуть нормальный вендоринг, но, я так понимаю, в ванильный go get
это всё равно не вольют.
// P.S. сам не сварщик по Go, но много работаю с разными системами сборок/управления зависимостями.
В этом плане хорошо сделали в Meson, он поддерживает как архивы исходников, так и коммит из git + дополнительно наложение патчей. К сожалению, патчи нужны практически всегда, т.к. зависимостью может быть только такой же Meson-проект. С другой стороны, скрипты для сборки намного проще и нагляднее, чем у CMake, так что портировать несложные библиотеки можно быстро.
А у Conan, вроде, всё есть тоже, вот из примера в документации:
def source(self):
self.run("git clone https://github.com/memsharded/hello.git")
self.run("cd hello && git checkout static_shared")
Meson смотрел. Судя по доке, врапперы нельзя накладывать на репозитории исходников, только на архивы.
Ну а предложенный вами способ можно реализовать практически в любой системе сборки, менеджер пакетов для этого не нужен. Интересовала поддержка git как полноценного источника:
- Выкачивание в общую папку кеша
- Учёт случаев, когда один и тот же репозиторий запрашивается транзитивно несколькими зависимостями
- Автоматическая сборка и предоставление её результатов зависимым пакетам — конкретно папки с публичными заголовочными файлами плюс артефакты сборки.
При этом вполне можно было бы требовать, чтобы для такого источника было отдельное описание — какая версия какой ветке/коммиту соответствует. К сожалению, ни Conan, ни Meson не поддерживают такой кейз — по крайней мере в простом виде.
Похоже на то, как делает Maven, который я очень люблю и уважаю за практически беспроблемную сборку с нуля, в том числе на пустых новых системах, где есть только JDK и собственно мавен. Сам скачает, сам скомпилит, главное, чтобы сеть работала и всё было в актуальном состоянии. Увы, для C++ такой подход не работает по фундаментальным причинам. В Java байткод запускается на любой платформе, чем язык и ценен, а у C++ имеется большой набор факторов несовместимостей: версия компилятора, его разновидность (Clang/G++/Borland/...), версия стандарта языка (98, 11, 14, 17), способ связи с внешними зависимостями (статическая линковка, динамическая, рантаймовая через dlopen/LoadLibrary/...) и, возможно, другие. Всё это порождает несовместимые ABI, число комбинаций которых быстро выходит из-под контроля. В Google давно поняли эти нюансы и сделали свой инструмент Bazel, который собирает абсолютно все библиотеки с нуля, так что получается предсказуемый и стабильный билд, но он как-то не очень популярен за пределами гугла, и с зависимостями у него тоже не всё гладко. В этом аспекте бинарный сетевой кэш Conan не выглядит сильно привлекательным — помимо и так немалого числа проблем при сборке проекта добавятся ещё и потенциальные нюансы собранных мейнтейнерами библиотек. Лучше уж всё качать в исходниках и собирать на локальной машине (я знаю, что Conan так может, но это не дефолтное поведение).
Это к тому, что общий кэш и общие результаты компиляции, при всей их удобности, не всегда лучшее решение, особенно, в больших проектах. Инвалидация кэша — одна из сложнейших задач, как известно, так что не факт, что сэкономленное на сборке время пойдёт действительно в плюс, когда проект перестанет собираться из-за обновления компилятора. Транзитивные зависимости — тоже головная боль, ведь в этом случае одна библиотека может оказаться двух разных версий по двум путям зависимостей. Maven в этом случае предпочитает более новую автоматически, но если таких случаев много, за всеми не уследишь, и это может ВНЕЗАПНО породить проблемы на ровном месте (обновил библиотеку, а по её пятому колену зависимостей какая-то библиотека обновила свою зависимость, которая перекрыла такую же у другой, и всё превратилось в кашу).
В Meson с этим строго: все зависимости, включая транзитивные, должны явно прописываться в корневом проекте, это гарантирует, что всё будет собрано однократно и иметь одну версию. Подход не без явных минусов, но гарантии такого рода на деле важнее неудобств при обновлении библиотек.
Автосборка и выдача результатов как раз имеется в Meson, хотя и не стандартизована — subproject экспортирует две переменные, обычно inc и lib, которые достаточно добавить в проект верхнего уровня. Система добавит нужные флаги для инклудов и линковки с учётом всех путей до субпроекта, это реально удобно и работает! Вообще, меня Meson подкупил именно системой Wrap, которая сколь проста, столь и эффективна, хотя можно спорить, должна ли система сборки иметь управление зависимостями. Но сделали хорошо и надёжно, почему бы и нет.
Судя по доке, врапперы нельзя накладывать на репозитории исходников, только на архивы.
Да:
Note that in this case you cannot specify an extra patch file to use. The git repo must contain all necessary Meson build definitions.
Но нет большой проблемы организовать свой форк на том же гитхабе (или сервере организации), где сразу держать meson.build и обновлять его по мере необходимости при изменениях в апстриме, а во wrap-файл писать нужный коммит.
Это к тому, что общий кэш и общие результаты компиляции, при всей их удобности, не всегда лучшее решение, особенно, в больших проектах.
Я имел ввиду локальный кеш, т.е. репозитории втягиваются в подпапки какой-то папки в домашнем каталоге пользователя. Если репозиторий уже есть — его никто не тянет повторно.
В Meson с этим строго: все зависимости, включая транзитивные, должны явно прописываться в корневом проекте
Вот этого и не хочется совершенно. Разве Meson не умеет писать lock-файл с конкретными версиями зависимостей? Этот подход как раз и придумали чтобы иметь мягкое задание версий зависимостей и при этом воспроизводимые билды.
Я имел ввиду локальный кеш, т.е. репозитории втягиваются в подпапки какой-то папки в домашнем каталоге пользователя. Если репозиторий уже есть — его никто не тянет повторно.
Можно завести issue, но что-то мне подсказывает, что в реалиях C++ это создаст больше проблем, чем решит, могу быть неправ. Часто используемые библиотеки и репозитории вообще имеет смысл захостить локально в организации или на своём сервере, а там уже время доступа не будет особой роли играть.
Разве Meson не умеет писать lock-файл с конкретными версиями зависимостей? Этот подход как раз и придумали чтобы иметь мягкое задание версий зависимостей и при этом воспроизводимые билды.
Можете раскрыть, что подразумевается под мягким заданием версий и lock-файлами?
Пусть у нас есть конфиг с зависимостями
foo = "1.2"
bar = "0.4"
Версии указаны неточно, как можно видеть.
При первичной сборке, менеджер сгенерирует файл, в котором записаны точные версии всех зависимостей и их транзитивных зависимостей. Всех пакетов, как-либо использованных при сборке.
foo = "1.2.4"
// foo's deps
spam = "0.4.3"
eggs = "3.14.16"
// bar's deps
eggs = "3.14.16"
При повторной сборке, если менеджер видит такой лок-файл, он использует версии оттуда. Обновить их список можно отдельной командой. Таким образом, все версии будут зафиксированы до следующего принудительного апдейта — но автоматически, без ручной писанины.
В cargo, где я это наблюдал, обычной практикой является держать такой файл под контролем версий для исполняемых проектов (или любых "конечных") и игнорировать для библиотек.
Я думаю, в случае Meson этот подход не имеет смысла, т.к. у него, в отличие от Maven, нет единого репозитория зависимостей и индекса с версиями, поэтому найти «последнюю» версию на основе предложенной неточной не получится. Нужно указывать прямую ссылку на архив или коммит. В случае с git, возможно, прокатит резолв по тегам, но не факт, что будет работать стабильно — теги все оформляют по-разному.
Пакетные менеджеры для C++, которые сейчас есть, чудовищно сложны, либо неудобно встраиваются в процесс сборки, на мой взгляд. Либо в базе одного есть один пакет, но нет другого, а у другого — есть второй, но нет первого, а третий — устаревший.
Отсутствие какого-то де-факто стандарта убивает всю систему зависимостей, в таком случае проще иметь систему которая делает "бери отсюда, делай то, клади туда".
У cmake есть ExternalProject, но над ним приходится городить самопальные костыли, чтобы это было расширяемо.
Hunter добавляет функциональности, но подготовка пакетов для использования требует времени, становится неудобно.
cget почти не требует конфигурации самих зависисостей, но тоже со своими косяками.
Есть хоть один менеджер зависимостей, который просто работает с пакетами, которым достаточно cmake
или ./configure && make && make install
?
Хотели вот добавить SFML, но нужно добавить libflac, libogg и libvorbis в качестве отдельных пакетов + перепахать SFML'ный CMakeLists. Все дело в том, что все зависимости лежат в собранном виде — а это уже: 1)возможные проблемы с совместимостью компиляторов (рано или поздно зависимости устареют и перестанут жеваться более свежими компиляторами) 2)менеджер зависимостей должен сам разруливать зависимости. Честно говоря, геморрой ещё тот
Если же говорить о проблеме в целом, то корень один — нестандартизованность. Все проекты по-разному устроены и юзают разные плюшечки + параллельно пытаются выбиться вперед совершенно разные менеджеры пакетов — отсюда и проблемы. Как решить проблему — понятия не имею, она нетривиальна… :(
PS. С conan-ом дела не имел, поэтому не знаю, насколько хороша их собственная документация.
Вот тут очень хорошая документация, на мой взгляд.На меня эта документация произвела впечатление сделанной «на отвали». Может, чтобы опакетить какой-нибудь hello_world из одного .cpp-файла она и достаточна, но понимания того, как это все работает не оставляет.
А еще что-нибудь есть?
Что я ожидал увидеть второй строчкой статьи? Команду поиска пакета в удалённой репе.
conan search <package> -r conan-center
ZaMaZaN4iK, спасибо за наводку, конечно, инструмент хороший и всё такое, но не надо так. Сделай сначала «коротко, зачем это вам» со сценарием использования от установки до успешной сборки, а потом уже наматывай воду на вилы, как всё плохо с пакетными менеджерами на плюсах.- Не все могут в английский. И высказывания вида «Не знаешь английский — не программист» лично я не воспринимаю серьёзно.
- Целью и не являлся перевод, хотя явно с него взято очень много материала. И какие именно небрежности Вас печалят?
- Я, конечно, учту замечания, но не вижу большой проблемы в таком стиле изложения.
- Про антиреклмау не понял, если честно.
Например, строка из доков conan search Poco/1.7.8p3@pocoproject/stable не отобразит ничего.
Меня печалит, например, что ни слова не сказано про репы, где всё лежит. Точнее, мне любезно сообщили «А ещё есть conan remote». Спасибо, хорошая наводка, но что в пункте «я нуб» не понятно?
Меня печалит, что, например, что поиск по репозиториям чувствителен к раскладке, но об этом нигде не написано.
Меня печалит, что когда я сказал,
>conan search openssl -r conan-center
мне ответили
There are no packages matching the openssl pattern
Это, знаете ли, удар ниже пояса. Что ещё смешнее, я нашёл флаг --case-sensitive, гарантирующий чувствительный к раскладке поиск. Спасибо, хорошо, как мне от него избавиться? Никак? Ох, хорошо, спасибо.
И, к слову, я ни капельки не сказал про «перевод не нужен». Естественно, нужен. Актуальный для последнего релиза программы. И, желательно, достаточный для работы. Ну, то есть, стоило дойти хотя бы до docs.conan.io/en/latest/getting_started.html#inspecting-dependencies
И после этого я не должен называть ваш перевод небрежным? Ещё раз, спасибо, что хоть такой, без вас бы я не узнал об этом инструменте.
В моих проектах используется vcpkg и, если не считать детских болезней с прокси, на работе мы полностью довольны.
Если бы в мире был одна только винда, то vcpkg был бы хорошим решением.
Ещё стоит учитывать, кстати, что vcpkg пока в стадии активной разработки и, может быть, Microsoft однажды сделает его кроссплатформенным
Есть еще прикольная инициатива: cargo native называется.
https://internals.rust-lang.org/t/pre-rfc-cargo-build-and-native-dependency-integration-via-crate-based-build-scripts/5708
Если взлетит, то можно будет cargo просто юзать для c++ и не парится особо.
А вот собрать все это с учетом зоопарка компиляторов и платформ — вот это самое печальное. В Rust-е такой проблемы нет, т.к. сам Rust пока:
- во-первых, представлен всего одним компилятором, поэтому нет надобности заботиться о скриптах сборки для совершенно разных компиляторов/линкеров с совершенно разными наборами ключей;
- во-вторых, не страдает от того, что кто-то вынужден сидеть на компиляторах 3-, 5- или даже 10-ти летней давности. Из-за чего при сборке нужно проверить, какой компилятор в наличии и что он поддерживает. Да и не только компилятор, но и ОС (отчего autotools все еще в ходу на Unix-ах);
- в-третьих, Rust пока еще не представлен на таком же спектре платформ, как C и C++. Некоторые из которых весьма специфические и без какого-то аналога autotools там не обойтись.
Так что догонять Cargo в C++ — это в принципе бесполезное занятие. Нужно что-то, чтобы учитывало реалии C++.
2. убрать легаси из поддержи — это проблема? Кто на легаси сидит и так не имеет ничего, так почему из-за них остальные 99% должны страдать?
3. никто ж не запрещает использовать autotools (пусть и не как часть стандарта, а что-то навроде расширения)
1. поддержать разные компиляторы — это проблема? Ну так себе аргументСами-то пробовали? Где можно результаты ваших трудов увидеть?
2. убрать легаси из поддержи — это проблема?Очевидно, что вы даже не представляете себе насколько.
Кто на легаси сидит и так не имеет ничего, так почему из-за них остальные 99% должны страдать?Откуда 99%? Из вашего уютного менямирка? Как вы думаете, какую часть рынка C++ разработчиков сейчас составляет поддержка и развитие легаси кода?
2. Проблема напечатать в стандарте «это деприкейтед»? Охотно верю.
3. «Развитие легаси». Делом лучшей займитесь, тогда может и у вас появится система сборки, собирающая любой проект одной командой.
Впрочем прожект-лиду что-то объяснять бесполезно.
1. Некоторые вещи очевидны и без «пробовали».В переводе на русский это означает «не разбираюсь, но мнение имею».
2. Проблема напечатать в стандарте «это деприкейтед»? Охотно верю.Что вы собрались помечать как «деприкейтед»? Вот в C++11 так пометили std::auto_ptr, а из C++17 вообще уже выбросили. Что никак не отразилось на проектах, которые все еще живут на C++98/03, приносят деньги и в обновление которых владельцы кода не особо хотят вкладываться.
Но интересно, что вы собрались помечать в стандарте как «деприкейтед» касательно систем сборки и управления зависимостями?
3. «Развитие легаси». Делом лучшей займитесь, тогда может и у вас появится система сборки, собирающая любой проект одной командой.Удивлю вас, но у нас есть и своя система сборки, и своя система управления зависимостями. Свои проекты в итоге собираются одной командой. Главный вопрос при этом: «Что делать с не своими?». Так что я говорю о том, в чем хоть чуть-чуть разбираюсь, в отличии от.
Впрочем прожект-лиду что-то объяснять бесполезно.Можно ли развернуть подробнее? Если бы в профиле стоял какой-то другой шилдик, вроде «system architect» или «co-founder» — это что-то бы изменило?
При таком зоопарке тулинга может плюсам нужна container-based система сборки? Чтобы было воспроизводимое окружение и вот это все, но это правда только для таргетинга Linux.
- Это не так просто, как Вы думаете.
- А что Вы подразумеваете под легаси? Хочу напомнить, что не так просто брать и что-то депрекейтить. Потому что это что-то может активно кем-то использоваться. В этом весь C++
Ранее уже были попытки создания такого средства для C++. Может, некоторые из Вас помнят такую вещь как biicode. Он, к сожалению, приказал долго жить.
Первый раз слышу, но я не удивлён, что проект загнулся. Этот скорее всего сделает то же самое. "Менеджер пакетов к с++" — идея изначально сомнительная. Для кодинга в стиле "песочница с набором игрушек" уже есть всякие php/js/итд.
Ну и в конце концов во всех современных популярных ос кроме винды уже есть встроенные менеджеры пакетов, не привязанные в компиляторам.
"Менеджер пакетов к с++" — идея изначально сомнительная. Для кодинга в стиле "песочница с набором игрушек" уже есть всякие php/js/итд.
Два вопроса: почему изначально сомнительная идея и какой стиль кодинга на C++? В крупных проектах может быть > 50 библиотек зависимостей. Как поддерживать такой зоопарк? Мы сейчас используем CMake ExternalProject и тонны костылей, например. А вы?
Серьёзные крупные проекты обычно сильно индивидуальны, и обойтись "нашёл в инете менеджер — сказал — настроил — запустил — подошло" там скорее всего не получится (а если и получится, то выглядеть оно будет как раз костылём). А такие пакетные менеджеры претендуют именно на такую роль — законченный абстрактный продукт, который подходит всем.
"Стиль кодинга" — я возможно плохо выразился. Имелось ввиду то, что во всяких пхп-подобных языках принято тянуть в проект всё подряд, не особо разбираясь в том как оно работает. В серьёзных языках так обычно делать не принято (а те, у кого было принято раньше, плавно переходят на новые языки, более для этого подходящие), а значит затраты времени на знакомство с новой используемой библиотекой будут всё равно заметно больше, чем затраты времени на чисто техническое подключение её к проекту. А значит тут техническое подключение (а это и есть роль пакетных менеджеров) — не совсем то место, вокруг которого надо спешить строить автоматизирующий инструментарий. Я не утверждаю, что везде так, но в среднем сложившаяся ситуация, по-моему, такая.
И не совсем понимаю пункта про идеологию.
Зачем нужен Conan: там, где пакетного менеджера нет и есть кроссплатформенный проект. Вы имеете свои версии зависимостей и хотите сами ими управлять, а не надеяться на мейнтейнеров (не относите сюда всякие флатпаки, снапы и так далее).
Надеюсь, что понятно обьяснил :-)
там, где пакетного менеджера нет
То есть главным образом на винде. О чём я уже писал но меня почему-то заминусовали.
Всё очень просто. Если Вы готовы доверить мейнтейнить зависимости мейнтейнерам — то путь сами разбираются, с какими зависимостями прога работает. Если хотите управлять сами — flatpak, snap, AppImage.
Conan: менеджер зависимостей для C/C++