Все задачи

Однострочник для make

17 Mar 2014

У программиста в проекте был мейкфайл, в котором использовался perl-однострочник.

Makefile:

# ...
templating: 
	perl -pe 's@/usr@$(PREFIX)@g if /$$prefix=/' templates/lib.pm.templ > $(DESTDIR)$(PERLLIBDIR)/Dh_Lib.pm
# ...

С этим однострочником в этом контексте есть по крайней мере одна серьезная проблема. А какие проблемы видите вы?

Подсказка

Показать

Если файла templates/lib.pm.templ внезапно не окажется на месте – сборка не остановится на цели templating, и либо упадет где-то в неожиданном месте дальше, либо вообще завершится успешно (по коду выхода).

Подсказка-2

Показать

Что напечатает следующая команда:

perl -pe 's/a/b/g' some-non-existent-file && echo SUCCESS

?

Подсказка-3

Показать

Can't open some-non-existent-file: No such file or directory.
SUCCESS

Разоблачение

Показать

Неочевидной особенностью нашего однострочника является то, что даже если входного файла не существует – код возврата все равно 0, как если бы обработка прошла успешно. Соответственно, make продолжает работу дальше. В хорошем случае сборка упадет на следующих этапах (скорее всего, с весьма неожиданными ошибками), в плохом – сборка пройдет до конца, завершится с кодом 0, но пакет или дистрибутив, который собирается, будет с попорченным содержимым. В любом случае, happy debugging!

Что касается кода возврата однострочника – поведение вполне закономерное: неуспешный Perl’овый open сам по себе не делает die, в многострочных программах мы своими руками пишем open or die (или используем autodie).

Что же делать, чтобы отсутствие входного файла не оставалось незамеченным? Если хочется, чтобы при невозможности открыть файл сборка ломалась – лучше отдать открытие файлов shell’у. Сравните:

> perl -pe 's/q/j/g' nonexistent_file
Can't open nonexistent_file: No such file or directory.
> echo $?
0
> perl -pe 's/q/j/g' < nonexistent_file
zsh: no such file or directory: nonexistent_file
> echo $?
1
> sh -c 'perl -pe "s/q/j/g" < nonexistent_file'
sh: 1: cannot open nonexistent_file: No such file
> echo $?
2

Кстати, sed в этом отношении ведет себя хорошо, на несуществующем файле падает:

> sed 's/q/j/g' nonexistent_file
sed: can't read nonexistent_file: No such file or directory
> echo $?
2