[О блоге] [наверх] [пред] [2020-12-01 20:29:28+03:00] [679136a9a37c25390c7cd9a605e2d4269c0e565b]
Темы: [redo]

Make vs redo на простой практике, снова

https://habr.com/ru/company/ruvds/blog/528434/
В одном из комментариев увидел пример того как человек конвертирует
.bmp в .png:

    BMPS := $(wildcard *.bmp)
    PNGS := $(patsubst %.bmp,%.png,$(BMPS))

    .PHONY: all
    all: $(PNGS)

    %.png: %.bmp
        convert $< $@
        touch -r $< $@
        rm $<

Это конечно не (POSIX) Make, а GNU Make. Почему это просто не сделать
shell циклом? Наверное потому что make будет распараллеливать эти
задачи. Но есть решение куда более короткое (требующее, вместо GNU Make,
GNU Parallel):

    parallel "convert {} {.}.png && touch -r {} {.}.png && rm {}" ::: *.bmp

По моему гораздо проще -- всё же однострочник, вмиг набираемый в
командной строке. Автор комментария отметил что Make не может тут ничего
поделать с именами с пробелами: с parallel их не возникнет.

Аналог на redo будет такой:

    all.do:
        find . -name "*.bmp" -maxdepth 1 |
        while read f ; do echo ${f%.bmp}.png ; done |
        xargs redo-ifchange

    default.png.do:
        convert $2.bmp $3.png
        mv $3.png $3
        touch -r $2.bmp $3
        rm $2.bmp

В отличии от GNU Make не требует знания сверх shell-а, без проблем будет
работать с пробелами. Если убрать -maxdepth, то и с иерархией файлов в
директориях будет отрабатывать без проблем (в parallel аналогично можно
сделать просто указав **.bmp или направив find). "mv $3.png $3" я делаю
только потому что мне лень искать как convert-у указать формат выходного
файла, поэтому подсказываю ему расширением. all.do можно конечно и
покороче записать, если файлов не много и они без пробелов:

    all.do:
        redo-ifchange `for f in *.bmp ; do echo ${f%.bmp}.png ; done`

Но у этих решений есть большой недостаток: а что будет если компьютер
упадёт? Нужны sync-и и только потом удалять оригинальный .bmp. Make
оставит за собой побитый .png мусор, но так как .bmp не удалён, можно
понять что задача не была завершена.

(Корректная реализация) redo делает sync на $3 файл автоматом, как DJB и
задумывал. goredo ещё явно делает и sync на директорию после
переименования. Но тут проблема с rm-ом: он выполняется до
автоматического redo sync-а. Руками вставить sync до rm --
гарантированно сбросит содержимое PNG, но не гарантирует что файл .png
будет создан переименованием. Можно сделать промежуточную .do цель,
которая заставит сначала сделаться (redo-ifchange) .png, а потом удалит
.bmp оригинальный.

Но по хорошему я бы просто ничего не удалял во время работы -- а
подчистил после отработки всего и вся. parallel, sync, rm *.bmp. redo
будет медленнее Make для этой задачи, так как 1) на диске хранит
состояние целей и зависимостей, 2) делает sync (ok, можно отключить
зачастую) и переименования файлов.

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