我如何使用 GNU Make 指定目标依赖的先决条件?

How do I specify target dependant prerequisits with GNUMake?

假设我有这样一个源文件列表:

SOURCE=aaa.src bbb.src ccc.src

我想创建一个规则来在自己的文件夹中构建每个相应的目标,其名称取决于源文件。

Sourcefile ----> Corresponding output file / target


aaa.src -------------------> aaa/aaa.out

bbb.src -------------------> bbb/bbb.out

ccc.src -------------------> ccc/ccc.out

如何使用 GNUMake 为此编写规则?我最大的努力是以下 Makefile:

.PHONY: all clean

CC=somecompiler

SOURCE := aaa.src bbb.src ccc.src
RTARGS := $(SOURCE:%.src=%.out)
TDIRS := $(addsuffix /,$(basename $(SOURCE)))
TARGS := $(join $(TDIRS), $(RTARGS))

all:$(TARGS)

%.out: $(SOURCE)     # Better source specification?
    @[ ! -d "$(dir $*)" ] && mkdir "$(dir $*)"
    $(CC) "$(patsubst %/,%,$(dir $*)).src" "$@"

clean:
    rm -f $(TARGS)
    rmdir --ignore-fail-on-non-empty $(TDIRS)

这里的问题是,任何一个目标(即 .out 文件)都依赖于 每个 源(即 .src 文件),而不仅仅是具有相同基本名称的那个。我可以将注释行更改为 %.out: %.src 但源文件必须与输出文件位于同一目录中。我也可以像这样编译它:

%.out: %.src
    $(CC) "$>" -o "$*/$@"

但是 make 总是会编译每个目标,不管它是否已经存在。

如何让 make 只使用适当的源文件。 在通用规则中分别指定每个目标的依赖关系的正确方法是什么?

在 GNU Make 中,您可以从配方中单独指定先决条件,并且仍然具有适用于所有 .out 文件的通用/模式规则:

.PHONY: all clean

all :

SOURCES := aaa.src bbb.src ccc.src
OUTPUTS := $(foreach src,${SOURCES},$(basename ${src})/${src:%.src=%.out})

# Build dependencies in the form of x/x.out : x.src | x
define ESTABLISH_DEPENDENCY =
$(basename )/${1:%.src=%.out} :  | $(basename ) # Also depend on the output directory.
$(basename ) : # Rule to create the output directory.
    mkdir $$@
endef

$(foreach src,${SOURCES},$(eval $(call ESTABLISH_DEPENDENCY,${src})))

all : ${OUTPUTS}

# Generice rule for all .out files.
%.out :
    @echo "build $@ from $^"
    touch $@

%.src : # For debugging only.
    touch $@

.PHONY: all

输出:

$ make
touch aaa.src
mkdir aaa
build aaa/aaa.out from aaa.src
touch aaa/aaa.out
touch bbb.src
mkdir bbb
build bbb/bbb.out from bbb.src
touch bbb/bbb.out
touch ccc.src
mkdir ccc
build ccc/ccc.out from ccc.src
touch ccc/ccc.out

请注意,与让每个配方首先检查目录是否存在相比,对目录具有仅顺序依赖性并让 make 创建它们更加高效和优雅。