Gnu make:仅在不构建另一个目标时构建目标

时间:2015-05-27 13:08:45

标签: makefile gnu-make

我正在尝试构建一个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,我不想发生。

2 个答案:

答案 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