[О блоге]
[наверх]
[пред]
[2025-11-26 10:47:42+03:00]
[a90196c10bd21225eeae8dd3ca73e76b90c7635e]
Темы: [c][djb][redo]
Снова изменение процесса конфигурации сборки проекта
Чего только не напридумывало человечество чтобы сконфигурировать
параметры сборки проекта. ./configure из autohell, которому передаются
различные --опции и переменные окружения. CMake со своими опциями и
способами задания всего этого. Где-то только переменные окружения,
возможно используемые сразу же при вызове целей из Makefile.
Я точно такой же человек и у меня всякое было в проектах. В последнее
годы это был "config" файл, который просто являлся sourceable shell
скриптом, где выставляются различные переменные, на основе которых
генерируется конфигурация сборки. Выставили переменную "CC" -- вот тебе
и путь до нужного компилятора. CFLAGS, PREFIX, и т.д..
Но уже давно глаз зацепился за подход в DJB софте. Просто есть файлик
conf-cc, где первая строка указывает на компилятор (или всю строку его
запуска), которую можно прочитать банальным: read CC <conf-cc
А это значит, что после первой строки может идти документация,
описывающая опцию.
-- conf-cc --
cc -O2
This will be used to compile .c files.
-- conf-break --
-
This character is the user-ext delimiter. The default delimiter is -,
meaning that user joe controls joe-anything. Some system administrators
prefer + or =.
You can override this choice at run time with the qmail-users mechanism.
Multicharacter delimiters are not permitted.
-- conf-users --
alias
qmaild
qmaill
root
qmailp
qmailq
qmailr
qmails
The qmail system is heavily partitioned for security; it does almost
nothing as root.
The first eight lines of this file are the alias user, the daemon user,
the log user, the owner of miscellaneous files such as binaries, the
passwd user, the queue user, the remote user, and the send user.
И эта идея меня не отпускает. Вообще я её применил в KEKS Си реализации,
где только ar/cc/cflags/ldflags/objcopy/prefix выставляются. Но там всё
просто.
Вчера один рабочий проект перевёл на такой же подход, но конечные
значения опций всё же выставляются через генерирование redo do-целями.
$ conf/list
cmd/ar
cmd/cc
cmd/clang-format
cmd/clang-tidy
cmd/include-what-you-use
cmd/objcopy
cmd/pkgconf
flags/cflags
flags/gcl3.pc.rc
flags/gmp.pc.rc
flags/keks.pc.rc
flags/ldflags
flags/ldlibs
flags/probes
flags/tap.pc.rc
paths/incdir
paths/libdir
paths/pkg-config-dir
paths/pkg-config-path
paths/prefix
-- conf/flags/probes.do --
# Set to 0 to disable probes.
what=$1 . ../local-if-exists.rc
echo 1
-- conf/flags/ldflags.do --
what=$1 . ../local-if-exists.rc
cat <<EOF
$LDFLAGS
-Wl,--gc-sections
-Wl,-z,relro,-z,now
EOF
-- conf/cmd/default.do --
what=$1 . ../local-if-exists.rc
command -v $1
-- conf/list --
#!/bin/sh
cd "$(dirname "$(realpath -- "$0")")"
sed "s#^#cmd#" <cmd/.gitignore
sed "s#^#flags#" <flags/.gitignore
sed "s#^#paths#" <paths/.gitignore
Вот только если руками поменять конкретное значение выхлопа цели, то, в
зависимости от redo реализации, она перезапишется вызовом .do файла, или
будет (в случае с apenwarr/redo или goredo) сыпать предупреждениями о
том, что цель была изменена не под контролем redo, что сильно шумит на
экране. Изменение .do файла приведёт к грязному git status, надо с ним
быть аккуратнее чтобы не закоммитить.
Вот для этого был сделан:
-- conf/local-if-exists.rc --
redo-ifchange ../local-if-exists.rc
_src=../local/$what
if [ -e $_src ] || [ -e $_src.do ] ; then
redo-ifchange $_src
cp $_src $3
exit
fi
redo-ifcreate $_src $_src.do
который проверит нет ли форсированного переопределения выставляемой
опции в conf/local директории. Это, похоже, второй раз в жизни когда
штатно используется redo-ifcreate со стороны человека.
echo /another/ar >conf/local/ar -- переопределит значение ar, не делая
.do цель по его поиску. Ничто не мешает его даже автоматически сгенерировать:
-- conf/local/pkg-config-path.do --
PKG_CONFIG_PATH="/foobar/lib/pkgconfig:$PKG_CONFIG_PATH"
PKG_CONFIG_PATH="/tmp/keks/libdata/pkgconfig:$PKG_CONFIG_PATH"
echo $PKG_CONFIG_PATH
$ redo conf/paths/pkg-config-path
redo . ../local/pkg-config-path (0.002s)
redo conf/paths/pkg-config-path (0.010s)
$ cat conf/paths/pkg-config-path
/tmp/keks/libdata/pkgconfig:/foobar/local/lib/pkgconfig:/home/stargrave/env/...
А как было до этого? 17aa5a765f6ab4a81dc3e14bf8ecdcd5a88ac820. Имелся
автоматически генерируемый, не тривиальным скриптом, список vars.list --
переменных которые можно выставить. Есть vars, где все эти переменные
прописываются агрегировано из config+config.local файлов. Куча conf/*
целей его source-ят и на основе переменных выставляют требуемые флаги
или действия (если выставлен *_{CFLAGS,LDFLAGS,LDFLAGS}, то не будет
использоваться pkgconf для их поиска для библиотеки). Сейчас все эти
скрипты с Perl-ом ушли. Пропало "отображение" одного пространства
настроечных параметров в виде переменных (окружения) в иное пространство
опций. Надо узнать *FLAGS для такой то библиотеки? По умолчанию будет
pkgconf. Надо переопределить? Просто сразу же прописываешь их в
conf/local/xxx.rc файл, а не ищешь какими переменными окружения (хотя
это просто переменные из config файла) можно повлиять на генерирование
результирующего файла. Если в config файле по умолчанию надо поменять
какую-то опцию, то возможно пришлось бы inplace редактирование файла
проводить, что не очень приятно и чревато ошибками. Теперь со всем этим
нет потенциальных проблем. Плюс возможность redo целями генерирования
нужных значений, автоматически их кэшируя, а не делая eval
config+config.local снова и снова.
Недостатков пока не нашёл. Плюсов вижу много. Как минимум, исчезновение
целого пласта переменных влияющих на выхлопные файлы конфигурации,
меньше кода, простоту переопределения опций машиной (без хрупкого sed -i).
Из-за наличия default.do файлов, доку красиво не вышло встроить. Ничто
не мешает для каждого отдельного случая просто сделать отдельный .do, но
тут уже просто лень. Но если бы тут не было redo, то это бы всё
выродилось в в DJB-like подход, хотя цели такой не стояло.
[оставить комментарий]