У меня следующая ситуация:
find-deps
— это внешняя программа, которая очень быстро запускается и обнаруживает информацию о зависимостях, аналогичнуюghc -M
. Его вывод — некоторый файлdeps
.compile
— это внешняя программа, которая работает очень медленно; в отличие отghc --make
, он очень медленный, даже если ни один из входных данных не изменился.
Таким образом, идея состоит в том, чтобы добавить правило Shake, которое запускает find-deps
для создания deps
, анализирует его в список файлов srcs
, а затем правило компиляции будет need srcs
гарантировать, что compile
будет повторно запущен только в том случае, если какой-либо из источников, обнаруженных find-deps
, измененный.
Сложность заключается в том, что find-deps
нужно alwaysRerun
, чтобы обнаруживать новые зависимые исходные файлы. Так что теперь, если правило compile
зависит от deps
для получения списка файлов, оно также будет alwaysRerun
. Стандартным решением было бы использование оракула: мы можем добавить оракул, который need
s deps
и анализирует его в список файлов, а затем правило compile
сначала запросит этот список исходных файлов и только need
их. Таким образом, в цепочке need
из compile
нет alwaysRerun
.
Однако в моем случае я не пишу конкретный Shakefile. Вместо этого я пишу библиотеку многократного использования Rules
, которую пользователи могут использовать для создания своего собственного основного Shakefile. Так что мне нужно было бы упаковать его как что-то вроде
myRules :: FilePath -> Rules ()
myRules dir = do
dir </> "deps" %> \depFile -> do
alwaysRerun
cmd_ (Cwd dir) "find-deps" ["-o", depFile]
dir </> "exe" %> \exeFile -> do
srcs <- askOracle $ Sources dir
need srcs
cmd_ (Cwd dir) "compile" ["-o", exeFile]
Но куда бы я поместил часть addOracle $ \Sources dir -> ...
, которая бы need [dir </> "deps"]
проанализировала ее и вернула список исходных файлов? Я не могу поместить его в rules
, потому что тогда два вызова rules
с разными каталогами попытаются установить обработчик оракула два раза для одного и того же типа. И я не могу сделать dir
частью типа вопроса оракула, потому что это переменная уровня термина, поэтому я не могу поднять ее в индекс Symbol
запроса.
И это оставляет меня с чем-то супер-хромым, например, с includeThisOnlyOnce :: Rules ()
, который пользователь должен не забыть включить ровно один раз в свой Shakefile.
Итак, мой вопрос:
- Есть ли способ отслеживать зависимости (т. е. избегать запуска
compile
, когда исходные файлы не изменились) без участия оракула? - В качестве альтернативы, есть ли способ разделить оракулы одного типа, каким-то образом определив их область действия, чтобы я мог добавить этот
Sources
оракул только в контекст каждого отдельного вызоваmyRules someDir
?