Как мне передать make
что скрипт может условно изменить файл, чтобы make
ждет stat
все файлы, пока этот скрипт не завершит работу?
Рассмотрим следующую серию файлов игрушек:
// version
2
// foo.h - note the space between the 1 and the semicolon
static constexpr int VERSION = 1 ;
//update.py
import sys
with open(sys.argv[1]) as f:
cur = int(f.readlines()[0].split()[5])
with open('version') as f:
exp = int(f.readlines()[0].strip())
if cur < exp:
with open(sys.argv[1], 'w') as f:
print >> f, 'static constexpr int VERSION = {} ;'.format(exp)
// main.cxx
#include "foo.h"#include <iostream>
int main() {
std::cout << VERSION << std::endl;
}
// makefile
all : a.out updater
a.out : main.o
g++ -o a.out main.o
main.o : main.cxx
g++ -std=c++11 -o main.o -c main.cxx -MP -MMD -MF main.d
.PHONY : updater
updater :
python update.py foo.h
-include main.d
Намерение здесь заключается в том, что у меня есть файл, foo.h
, который условно обновляется скриптом, update.py
(если вы увеличите число в version
, foo.h
будет обновляться — иначе ничего не будет). Я хотел бы передать это понятие make
как-то — это не stat
foo.h
чтобы определить, нужно ли переделывать main.o
до тех пор update.py
заканчивает работу Как мне обеспечить этот заказ?
Замечания: version
это просто заполнитель для сложной серии предпосылок, которые нелегко выразить. Просто добавив foo.h : version
это не решение
Во-первых, если вы не хотите, чтобы сделать, чтобы обновить main.o
и т. д. до foo.h
был обновлен, вы должны перечислить foo.h
в качестве обязательного условия:
main.o : main.cxx foo.h
g++ -std=c++11 -o main.o -c main.cxx -MP -MMD -MF main.d
(Хотя, конечно, я бы никогда не написал так, я бы всегда использовал такие переменные:
CXX = g++
CXXFLAGS = -std=c++11
DEPFLAGS = -MP -MMD -MF $*.d
main.o : main.cxx foo.h
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(DEPFLAGS) -o $@ -c $<
но это я …)
Во-вторых, вы должны иметь правило для обновления foo.h
, Как вы предлагаете, это должно быть .PHONY
поэтому он всегда запущен, хотя и не всегда обновляется foo.h
:
.PHONY: updater
updater:
python update.py foo.h
Теперь вам нужно соединить эти два правила, поэтому вы должны создать правило, которое связывает foo.h
в updater
:
foo.h : updater ;
Обратите внимание на точку с запятой здесь, это критический. Вот как это работает: updater
является фальшивым, поэтому он всегда будет работать, а это означает, что любая цель, от которой он зависит, всегда будет выполняться. Так ясно, что вы не можете перечислить main.o : main.cxx updater
как это перестроит main.o
каждый раз.
Таким образом, вы можете ввести промежуточное правило, foo.h : updater
, Вы должны сделать это в любом случае, так как вам нужно перечислить foo.h
в качестве предварительного условия, поэтому вам нужна цель, чтобы построить его.
Тем не менее, само по себе это не поможет, потому что make видит, что нет рецепта для сборки foo.h
так что он не понимает, что когда updater
был запущен это построен foo.h
, Вы можете обойти это, создав пустой рецепт foo.h
; вот что ;
для:
foo.h : updater ;
что создает пустой рецепт для этой цели foo.h
и этого достаточно, чтобы заставить make проверить, есть ли файл foo.h
был изменен или нет. Когда это модифицируется ( updater
) затем main.o
будет перестроен. Когда это не изменено, main.o
не будет восстановлен (если нет другой причины перестроить его).
Если вы хотите восстановить main.o
а также a.out
когда и только когда скрипт модифицируется foo.h
это может быть работа для рекурсивный Make:
all : updater
@$(MAKE) a.out
...
main.o : main.cxx foo.h
...