[sisyphus] mk-configure -- lightweight replacement for GNU autotools

Mikhail Yakshin greycat на altlinux.org
Ср Июл 15 03:13:36 MSD 2009


Приветствую,

>> Perl/Python/Ruby с некоторой натяжкой есть на практических всех
>> современных Linux/BSD-системах.
> Мысль понял. Почему я не использую ЯП, вместо комбинации POSIX shell +
> unix tools? Ответ простой. Потому что средство подбирается не по
> принципу "крутости", современности или распространенности, а исходя из
> задачи.  Система сборки -- задача простая, и для ее реализации я выбрал
> подходящие на мой взгляд и простые средства.  Ни питон, ни руби, ни перл
> там не нужны. Тем более, что все они довольно громоздкие.

Система сборки - на мой взгляд - одна из самых сложных частей рабочего
окружения. Python/Ruby/Perl

>> "POSIX shell" фактически нет нигде. С некоторой натяжкой можно
>> считать, что bash есть везде, но:
> У меня достаточно большой опыт написания портабельных скриптов на шеле,
> авке и прочих под разные оси.

Позвольте в этом усомниться.

>> 1. К POSIX shell он имеет довольно приблизительное отношение.
> shell как шел, только очень медленный по сравнению с некоторыми другими.
> Где список претензий к bash по части POSIX?
>
>> 2. Его поведение сильно зависит от сборки в конкретном месте.
> Я не пользуюсь GNU-ыми расширениями.
>
>> 3. Авторы его регулярно ломают и это поведение меняют.
> В части POSIX? Где?

Обсуждение этого вопроса достаточно объемно и, думаю, выходит за рамки
тематики системы сборки и обсуждения в этом списке рассылки. Если
хотите - можно продолжить это обсуждение приватно.

Вашу точку зрения на портабельность POSIX shell, utilities и святую
веру в то, что там и правда всё хорошо и одинаково работает я понял.
Странно, что вы сами себе противоречите - перечислили столько
исключений, которые сами патчили

>> "NetBSD make", если понимать это буквально, еще более исчезающе редок.
> Этот аргумент я принимаю, но только как маркетоидный, но не как
> технический.
>
> NetBSD make нужно именно буквально понимать. bmake -- это портированный
> на другие платформы NetBSD make. Об-autotools-еный.  Регулярно синкается
> с репозиторием NetBSD. Где он не работает я просто не знаю.  Наверное,
> только на нативной винде. Не в курсе.

Собственно, нежелание поддерживать ничего, кроме POSIX, тоже вряд ли
приведет к чему-то хорошему. "Конкуренты" уже давно признали
существование Windows, OS X, Symbian. Зачем мне выбирать систему,
которая будет заведомо работать только на POSIX, когда я могу выбрать
систему, которая будет работать на еще 3 дополнительных платформах?
Даже если я не поддерживаю их сейчас - может быть я захочу облегчить
себе жизнь в будущем.

> Почему я не использую GNU make? Этот вопрос надо добавить в FAQ:
> - потому что для GNU make я не нашел аналога mk-files
>  (возможно, плохо искал)
> - потому что меня воротит от уродливой комбинации foreach/eval/call вместо
>  простого и элегантного bsdmake-овского .for/.endfor, который, кстати,
>  повсеместно используется в mk-configure.
> - потому что bmake проще и понятнее, чем GNU make.

Все 3 объяснения, мягко говоря, субъективны. Я, например, поверхностно
знаком с bmake - никаких восторгов от него не испытываю. Если
вдаваться в функционально-декларативную идею make - то конструкции
вида foreach вообще противоестественны.

>> Если будете пытаться генерировать Makefiles так, чтобы "работало
>> везде" - и на bmake, и на GNU make - потеряете массу
>> возможностей.
> Даже при поверхностном прочтении тех ссылок, что я давал, станет
> очевидно, что кодогенерация -- это как раз то, от чего я отказался.
> Там прямо так и написано.

Описался, извините. "Писать Makefiles".

>> Будете поддерживать только bmake - сильно осложняете
>> использование своего продукта для Linux-пользователей.
> Тут согласен. Но не так уж "сильно" и только на первых порах.  Думаю, не
> секрет, что пишущие на autoconf как правило очень плохо знают m4. Ну и
> пакетирование, к примеру, пакетов для pkgsrc тоже не требует глубинных
> знаний bmake-а, хотя все Makefile-ы пакетов написаны на нем. Есть
> несколько шаблонных конструкций, которые легко выучить и оперивать ими
> буквально годами, не вникая в детали bmake. Кроме того (повторюсь) bmake
> проще GNU make-а, поэтому изучить его значительно легче. Т.о. проблема
> обучения имеет место, но не очень серьёзная. Сравнивать же
> bmake/mk-configure с scons/waf (python!)  по сложности обучения я просто
> не буду. Это вообще не серьезно. И не надо говорить, что питон
> уже все знают.

Субъективно - scons/waf/cmake - проще, чем то, что я вижу в
mk-configure. И да, perl/python/ruby, как ни странно, прилично знают
действительно значительно большее количество человек, чем прилично
знают shell и Makefiles.

>> Критика любых make-подобных программ всё так же применима к нему
>> (полагаю, Вы с ней знакомы, но эту точку зрения не разделяете).
> С чем-то согласен, с чем-то нет. К критике make-ов я отношусь спокойно,
> без истерик. Альтернативы типа scons игнорирую, виду их чрезмерной
> массивности. python для реализации альтернативных make-ов -- выбор
> неудачный. Уж больно он толтый. Естественно, это тоже субъективно.

Единственное, чего не очень понимаю - в каком отношении "толстый".
Много места занимает? Давно проверяли? Медленно работает? Вообще-то
быстрее и эффективнее любых известных мне shell- и make-based решений.

>> Я сейчас как раз нахожусь на перепутии проектировании некоей
>> достаточно сложной configure-подобной системы для своего проекта и
>> анализирую массу информации на эту тему, но к mk-configure, к
>> сожалению, пока я серьезно рассматривать не могу.
> О! А можно списком набор требований к искомой системе?

Боюсь, что это будет опять же оффтопиком в этом постинге, но

Система состоит из 2 больших частей: "клиент" и "сервер".

Сборка возможна в 4 вариантах. "Варианты" - это набор из
десятка-другого типизированных опций и процедуры сборки:

1. Configure, собирается клиент, собирается сервер, все вместе в
каком-то виде пакуется в один бинарный пакет.

2. Configure, собирается клиент, пакуется отдельно, собирается сервер,
пакуется отдельно.

3. Configure, собирается клиент, пакуется в пакет, собирается root (из
кучи пакетов заданного дистрибутива + собранного пакета клиента).
Собирается bootstrap-пакет из серверной части. Копируется и
устанавливается на целевой сервер, тем самым производя его начальные
настройки. Собранный root копируется на целевой сервер (он будет
раздаваться по nfs, nfs-демон к этому моменту уже настроен
bootstrap-пакетом). Собирается серверная часть системы в несколько
пакетов. Пакеты передаются на сервер и там устанавливаются. В конце
(или лучше во время) производится множество тестов, призванные
проверить работоспособность всего комплекса в целом и выявить проблемы
на самом раннем этапе - например, выгрузили root на nfs - проверить,
отдается ли по nfs что-нибудь оттуда, настроили DHCP - проверить,
отдаются ли адреса в нужные сети.

4. Configure, собирается клиент, пакуется в пакет, собирается root с
этим пакетом, пакуется в squashfs/aufs/что-нибудь такое-эдакое,
производится магия с загрузчиком, пакуется в iso9660 => получается
загрузочный образ Live CD.

Сборка производится на некоей системе A (A может быть равно одному из
значений типа "ALT Linux", "Debian", "Ubuntu", "SuSE", "RedHat" и
т.п.). Клиент и root, в котором будет работать клиент могут быть от
системы B, а сервер может работать на системе C - в общем случае
A!=B!=C. Желательно, чтобы "C" кроме всего прочего мог быть равен
Windows.

Добавление поддержки новых вариантов A, B, C не должно быть чем-то
сверхъестественным и должно быть сравнительно простым.

Под словом "configure" понимается автонастройка сборочной системы - с
проверкой кучи всяких мелочей - таким образом, чтобы на системе A было
возможно собрать всё, что нужно, для систем B и C - плюс дается некая
возможность пользователю задать несколько десятков опций, в том числе
выбрать "вариант сборки" (что вытащит дефолты для "десятка-другого"
опций), а затем при желании перекрыть эти дефолты. Т.к. опций много и
они зависят друг от дружки (например, в зависимости от задания системы
"B" могут появляться какие-то специфичные для выбранной системы опции)
желательно наличие какого-то удобного конфигуратора - на уровне того,
что показывают рядовому пользователю при сборке ядра Linux.

Процесс "configure" вполне может быть итеративный или иметь более, чем
одну стадию. Например - пользователь имеет A = ALT Linux, B = Debian.
Он запускает configure, A детектится, пользователь выбирает B.
Configure проверяет наличие в системе кучи всяких инструментов (всяких
debhelper или dh-build, например). Если их нет - на этом месте мы
прерываемся и говорим пользователю, что у него не установлено то-то.
Если все нормально, то мы возвращаемся к простановке опций и даем на
этот раз пользователю настроить уже опции, специфичные для A и B или
их комбинации. После чего может следовать еще одна проверка и еще один
цикл донастройки и т.д. Опции имеет смысл как можно скорее
валидировать - если пользователь, сказал, например, "каталог для
установки - такой-то", то стоит убедиться в том, что он существует и в
него можно писать. Если пользователь сказал, что "целевой сервер -
такой-то", то стоит зайти на этот сервер, убедиться в наличии там
нужных прав и т.п.

Под словами "пакуется в пакет" понимается модульная поддержка упаковки
в один из возможных пакетов (в зависимости от выбранных систем B и C -
ALT-specific rpm, RH-specific rpm, SuSE-specific rpm, Debian deb,
Ubuntu deb и т.п.).

Под словами "собирается root", "собирается LiveCD" и т.п.
подразумеваются действия, которые зависят от выбранных опций - в
первую очередь от выбранных систем B и C. Предполагается, что каждое
из таких действий должно быть оформлено в виде некоторого семейства
модулей - при сборки выбирается модуль, соответствующий системам B или
C из данного семейства.

Разумеется, хочется, чтобы была система отслеживания зависимостей -
если пользователь задал конфигурацию #1, сказал "make all", у него
что-то не собралось или незадеплоилось - он чуть-чуть подправил
конфигурацию, сделав тем самым конфигурацию #2 - чтобы были
перевыполнены только нужны этапы сборки. Как можно догадаться, речь
явно не о file-level dependencies

Хочется, чтобы у всего этого был красивый и вменяемый пользовательский
интерфейс - чтобы было явно видно, на какой стадии мы находимся
сейчас, какой у нас прогресс, сколько еще осталось ждать. Чтобы от
всех действий по сборке сохранялись логи в каком-то иерархическом
хранилище. Чтобы это всё было привязано (но при желании могло _легко_
отвязываться) к системе контроля версий - чтобы в сборочные единицы
куда нужно попадали идентификаторы ревизий и т.п.

На саму систему можно посмотреть в районе http://www.inquisitor.ru/ -
сейчас вся сборочная система выполнена на GNU Makefiles, многого из
желаемого нет. Текущая система сборки работает, но она достаточно
сложна и провоцирует разработчиков делать ошибки, которые очень тяжело
потом находить и исправлять.

Если интересно дискутировать далее на эту тему - предлагаю опять же, в приват.

>> Даже если закрыть глаза на bmake, который предлагается заставлять
>> ставить всех пользователей, то фатальные, с моей точки зрения,
>> недостатки существующей системы такие:
>
>> * Подмена понятий при разделении хотя бы на 2 шага: интерактивный
>> (configure, пользователь долго взаимодействует с опциями и подбирает
>> нужную ему комбинацию) и неинтерактивный (make, пользователь пошел
>> пить кофе). То, что вы называете "configure" на практике просто
>> занимается проверками и кое-что строит на лету, а реальная
>> конфигурация на самом деле передается вместе с запуском bmake.
> На мой взгляд это совершенно несущественно. Я лично не вижу никакой
> двухстадийности. Стадия одна -- построить проект, учитывая особенности
> системы. Все.
>
> Запускаешь, к примеру
>
>   bmake PREFIX=/usr/pkg <other options here>
>
> и СРАЗУ идешь пить кофе.

И, вернувшись через полчаса, узнаешь, что сборка проработала две
минуты и упала где-то в начале из-за неправильно указанной опции. Тем
не менее, перед падением была проделана масса работы впустую и ее
придется всю переделать. А можно было отсечь неверно заданную опцию
еще до начала сборки.

>> * Достаточно медленная работа, отсутствие адекватного кэширования
>> результатов configure. В некотором смысле - это следствие используемых
>> инструментов - в том числе см. выше про критику всех make.
> Здесь просто полное несоответствие фактам. В mk-configure кеширование
> как раз есть, а нет его как раз в autoconf-е (между проектами).

Прочитайте, пожалуйста, полностью - "адекватного кэширования". Вы
как-то странно постоянно сравниваете себя с autotools

> Медленно работает? Глупости. Все работает быстро. Настолько быстро,
> насколько это вообще возможно. Количество fork(2)-ов можно даже
> посчитать.

Ну, для справки - именно fork(2) при выполнении configure проекта на
каком-нибудь scons будет в разы меньше - просто потому, что оно не
будет вызывать столько всяких внешний программ и столько раз дергать
шелл.

На глаз - ну посмотрите хотя бы, сколько ./EXAMPLE.configure --help
выполняется. По-моему - уже на грани фола, и как это ускорить, не
меняя парадигмы - я не представляю.

>> * Крайне плохо масштабируемая модель синтаксиса входных файлов.
> Здесь не понял. Можно развернуть?

Все, что можно передать в сборку из configure, запихивается в
environment и command line. Он относительно маленький и пользоваться
неирархическими плоскими путями типа

MODULE1_SUBMODULE2_SUBSUBMODULE3_SOMETHING_MORE_HERE_OPTION=2

при наличии нескольких сотен опций неудобно. Кроме того, и command
line, и environment не резиновые.

[...]

Остальное почти всё пропустил, надеюсь, про группы, иерархию опцию и
деплоймент я понаприводил примеров выше.

>> continuous integration и
> Я тоже знаю много страшных слов. Но CI не имеет никакого отношения к
> системе сборки, насколькоя его понимаю.

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

>> unit testing.
> unit testing добавить как раз не проблема. Пишется отдельный модуль
> mkc.test.mk, включай и используй. bmake test и оно поехало.  Записал в
> todo "на подумать", низкий поклон.  Хотя, конечно, unit тестирование --
> это явно не задача mk-configure.  Авторы приложений и библиотек сами
> могут себе написать подходящую для них систему.  Есть образцы для
> подражания?

Речь не о том, чтобы на пустом месте придумать что-то суперновое и
супергениальное. Есть масса сложившихся подходов к тестированию -
людьми написаны миллионы тестов под JUnit, CUnit, RUnit, Test::More и
т.п. Есть "стандарт" TAP (Test Anything Protocol). Идея в том, чтобы
обеспечить легкий запуск тестов всех этих форматов и хоть какую-то их
интеграцию в сборочную среду.

То же самое по сути относится к инструментам code coverage и генерации
документации. Современные сборочные фреймворки дают пользователю
возможность сделать "что-нибудь test", "что-нибудь coverage" или
"что-нибудь doc" и получить вменяемые результаты без написания единой
строчки кода, кроме, собственно, самих тестов и документации.

>> * Модель эмбеддинга системы сборки в продукт.
> В mk-configure эмбендинга как раз нет. mk-configure должен быть
> поставлен на систему ПЕРЕД сборкой. Об этом явно говорится в README.

Тогда, вероятно, я не так понял роль shell-скрипта "configure". Он не
распространяется с продуктом?

-- 
WBR, Mikhail Yakshin


Подробная информация о списке рассылки Sisyphus