带有条件生成文件的 makefile
makefile with conditionally generated file
我如何向 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
不是解决方案。
如果您想要在且仅当脚本修改 foo.h
时重建 main.o
和 a.out
,这可能是 递归 Make 的工作:
all : updater
@$(MAKE) a.out
...
main.o : main.cxx foo.h
...
首先,如果您不想让 make 更新 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
不会重建(除非有其他原因重建它)。
我如何向 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
不是解决方案。
如果您想要在且仅当脚本修改 foo.h
时重建 main.o
和 a.out
,这可能是 递归 Make 的工作:
all : updater
@$(MAKE) a.out
...
main.o : main.cxx foo.h
...
首先,如果您不想让 make 更新 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
不会重建(除非有其他原因重建它)。