我正在尝试构建一个makefile,它来自*.cc
类型的源文件,可以优化某些文件的构建。有两组目标%.o
和%.vd
。构建%.o
构建%.vd
作为副作用,因此如果需要构建%.o
,我不希望明确构建%.vd
。但是,单独构建*.vd
的过程更为有效,因此如果没有必要构建%.o
,我希望仅构建%.vd
而不是%.o
。
这是我的开始(作为指导):
all:
CC_FILES := $(wildcard *.cc)
O_FILES := $(patsubst %.cc,%.o,$(CC_FILES))
VD_FILES := $(patsubst %.cc,%.vd,$(CC_FILES))
all: $(O_FILES) $(VD_FILES)
# rule to make %.o that makes %.vd as side-effect; relatively expensive
%.vd %.o: %.cc
# shell commands
# rule to make only %.vd, relatively fast
%.vd: %.cc
# different set of shell commands
但是,这始终会同时生成*.vd
和*.o
个文件,并且当*.vd
已经存在时,不会自动采用仅构建*.o
的有效路径最新,但冗余重建*.o
,我不想发生。
答案 0 :(得分:0)
这反映了make的常见任务,但可以通过两种不同的方式实现。
有时构建将通过文件类型的序列,但并不总是想要重新生成每个文件,而是在中途停止。举一个例子,当从lex和yacc构建一些东西时,我们可能会有一些模糊的东西:
%.l -> %.y -> %.c -> %.o -> ....
或从LaTex构建输出文件时:
%.tex -> %.dvi -> %.ps -> %.pdf (maybe)
我们只需要显示必要的Pattern Rules来显示依赖项:
%.y: %.c
bison -y $<
mv y.tab.c $@
%.c: %.o
$(CC) $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
# This rule is actually built into make
现在我们可以随时制作中间文件:
$ make mycompiler.c
和make只会从源mycompiler.y重新构建文件mycompiler.c,构建所需的任何早期* .l文件但不构建mycompiler.o或mycompiler.exe。它只是生成你要求的文件。
请注意,这只是一个GNU make recipe。还有一个Traditional Suffix rule用于其他类似的制作系统。它将写成这样:
.y.c: bison -y $< mv y.tab.c $@ ... etc...
如果你想构建所有 * .vd,下一个问题就是你如何指定。您可以传递* .vd文件的名称(如果它们存在),如下所示:
make *.vd
或在make文件中有一个 phony 目标,并将它们包含在依赖项列表中:
VD_FILES= 1.vd 2.vd ... etc ...
.PHONY: VD
VD: $(VD_FILES)
在您的示例中,您有选择,而不是序列。您可以从源文件中创建一个或两个目标文件。 make中有这样的语法,它是double colon rule。不幸的是double colons in patterns means something different的使用,所以我们必须使用双冒号规则和虚假目标来表达我们想要的构建。我们还必须小心规则的排序,因为早期的规则优先于后来的规则。在您的示例中,这可以通过以下方式实现 * :
CC_FILES := $(wildcard *.cc)
O_FILES := $(patsubst %.cc,%.o,$(CC_FILES))
VD_FILES := $(patsubst %.cc,%.vd,$(CC_FILES))
.PHONY: all VD
all: $(VD_FILES) $(O_FILES)
VD: $(VD_FILES)
# rule to make only %.vd, relatively fast
$(VD_FILES):: $(CC_FILES)
# different set of shell commands
touch $@
# rule to make %.o that makes %.vd as side-effect; relatively expensive
%.vd %.o:: %.cc
# shell commands
touch $*.o $*.vd
我们现在可以调用make来构建所有* .vd文件:
make VD
或只有一两个人:
make 1.vd 2.vd
但如果我们要求* .o文件,它将同时构建:
make 1.o
但是,因为我们首先在依赖项列表中列出了VD文件,所以它将在*.o
文件之前检查所有VD文件,这意味着它每次都会采用最佳构建。这意味着你现在有了选择;您可以手动询问是否要构建任何文件,仅询问VD文件或有效更新所有内容(默认设置)。
* 这已经过测试,是一个有效的makefile BTW
答案 1 :(得分:0)
我设计的解决方案将%.o
作为%.vd
的仅订单先决条件。在%.o
规则中,配方使用eval
函数设置变量O_RULE
以指示%.o
规则已运行。 %.vd
食谱仍在运行。但是配方封装在if
函数中,其测试为O_RULE
。仅当%.vd
未定义时,才会运行O_RULE
配方。
CC_FILES = $(wildcare *.cc)
O_FILES = $(patsubst %.cc,%.o,$(wildcard *.cc))
VD_FILES = $(patsubst %.cc,%.vd,$(wildcard *.cc))
.PHONY: all
all: $(O_FILES)
$(info MAKE_RESTARTS is $(MAKE_RESTARTS))
%.vd: | %.o
@echo run %.vd recipe
$(if $(DISABLE_$*_VD),,touch $@)
%.o: %.cc
@echo run %.o recipe
$(eval DISABLE_$*_VD := 1)
touch $@
touch $*.vd