[О блоге] [наверх] [пред] [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 подход, хотя цели такой не стояло.

    [оставить комментарий]