вторник, 29 мая 2012 г.

"Улучшение" зависимостей в Makefile

Возникла тут задачка. Есть Makefile + набор скриптов, которые обрабатывают файл с данными и рисуют кучу картинок. Есть некий файл с параметрами, управляющими этим процессом. Проблема в том, что изменение различных параметров влияет на разные стадии работы. Изменение одного параметра потребует полной перестройки, другого - только отработки финального скрипта. Такую ситуацию, т. е. зависимость цели от значения переменной, а не от времени модификации файла, make обработать не может. Что ж, значит, надо ему помочь. Приведу общую концепцию решения.

Пусть есть скрипт script, создающий файл final. Пусть есть файл pars, содержащий как параметры, влияющие на работу script, так и безрачличные для него. Наша задача - сделать так, чтобы make запускал script только при изменении важных для него параметров, а не при любом изменении pars.


Понятно, что pars не может стоять в списке зависимостей final. Значит, final будет зависеть от некоторого файла dep_script (я ассоциирую зависимости с производящим скриптом, для моей задачи так удобнее), который должен быть создан скриптом mkdep.  Вот он:
Идея понятна из комментариев. Файл dep_script будет изменён только, если изменился какой-либо параметр из заданного списка в pars. Теперь Makefile:
  1. Цель по умолчанию - final.
  2. Указываем, что цель gendeps не  является файлом. Из этого следует, что правила для неё будут отрабатываться всегда, когда она появится в зависимостях.
  3. Правило для цели final. Она зависит от скрипта script и от его параметров dep_script. Обычная история.
  4. Описание цели gendeps. Обратите внимание, что цель для dep_script отсутствует, потому что обновление dep_script управляется условиями, отличными от тех, с которыми может работать make. Также и pars отсутствует в списке чьих-либо зависимостей, потому что всё равно он анализируется при каждом запуске make.
  5. Введение цели script с зависимостью от gendeps.
Получается следующая логика работы make.
  1. Попытка выполнить цель final, для чего делается поочерёдная проверка её зависимостей.
  2. Первая зависимость - script. Она сама зависит от gendeps. Так как gendeps не является файлом её команды выполняются всегда. То есть, первое что сделает make (и сделает это при каждом запуске), это выполнит команду ./mkdep.
  3. В результате выполнения mkdep, файл dep_script либо обновится, и тогда make запустит ./script final, либо нет, а на нет и суда нет.
Надо сказать, что в зависимостях final нужно, чтобы script стоял раньше, чем dep_script, иначе make будет ругаться, что он не знает как сделать dep_script.

Таким образом, мы частично перекладываем логику обновлений с make на пользовательский скрипт. За большую гибкость, в данном случае, мы расплачиваемся усложнением Makefile и работой нашего скрипта при каждом запуске make.

В настоящей моей задаче логика немного сложнее, в частности, списки зависимостей получаются опросом скриптов, но принцип остаётся тот же: анализ единого конфигурационного файла и выделение из него отдельных наборов параметров.

Комментариев нет:

Отправить комментарий