Makefile 变量的 Makefile 通配符,用于定义通用规则

Makefile wildcard for makefile variables, to define generic rules

后台,我怀疑是XY问题

我在目录中有更简单的 C 模块。我想在子目录 test/ 中为这些编写单元测试。这些单元测试只不过是链接到被测模块的 C 程序,即上面的一个目录。我想要一个 Makefile 来定义多个构建目标并让我一步构建和 运行 测试可执行文件,或者单独构建。

我尝试的解决方案

我尝试了以下操作:

CC = gcc
CFLAGS = -ggdb -Wall -Wextra -Werror -O3 -std=c99

PARAM_LIST_TARGET = parameter_list_test
PARAM_LIST_SOURCE_FILES = \
    ../parameter_list.c \
    parameter_list_test.c
PARAM_LIST_OBJECT_FILES := $(addsuffix .o,$(basename $(PARAM_LIST_SOURCE_FILES)))

TARGETS = $(PARAM_LIST_TARGET)

all: $(TARGETS)

$(%_TARGET): $(%_OBJECT_FILES)
    $(CC) $(CFLAGS) $^ -o $@

.c.o:
    $(CC) -c $< -o $@ $(CFLAGS)

clean:
    $(RM) *.o $(TARGETS)

test: all
    @for t in $(TARGETS) ; do ./$$t ; done

这不起作用,这是因为 $(%_TARGET): 行。不足为奇,我没想到它会起作用,但我希望这能说明我正在努力实现的目标。

我想创建更多 _TARGET_SOURCE_FILES_OBJECT_FILES 形式的块,以测试 PARAM_LIST 之外的其他模块,例如:

PARAM_LIST_TARGET = parameter_list_test
PARAM_LIST_SOURCE_FILES = \
    ../parameter_list.c \
    parameter_list_test.c
PARAM_LIST_OBJECT_FILES := $(addsuffix .o,$(basename $(PARAM_LIST_SOURCE_FILES)))

OTHER_MODULE_TARGET = other_module_test
OTHER_MODULE_SOURCE_FILES = \
    ../other_module.c \
other_module_test.c
OTHER_MODULE_OBJECT_FILES := $(addsuffix .o,$(basename $(OTHER_MODULE_SOURCE_FILES)))

我知道 % 适用于文件名,因此尝试将其用于变量失败:

$(%_TARGET): $(%_OBJECT_FILES)
        $(CC) $(CFLAGS) $^ -o $@

如何编写一条规则,使 Makefile 变量 _TARGET 与其关联的 _OBJECT_FILES 相匹配,而无需为每个测试目标创建一个?

或者更重要的是,我应该如何做完全不同的事情?

编辑:我见过 this,但似乎每个可执行文件只使用一个源文件。

由于this answer

,单独定义依赖关系似乎可行
TARGETS = $(PARAM_LIST_TARGET) $(OTHER_MODULE_TARGET)

all: $(TARGETS)

$(PARAM_LIST_TARGET): $(PARAM_LIST_OBJECT_FILES)
$(OTHER_MODULE_TARGET): $(OTHER_MODULE_OBJECT_FILES)

$(TARGETS):
    $(CC) $(CFLAGS) $^ -o $@

这消除了对重复规则的需要(每个目标一个)。尽管如此,每个目标的依赖项定义看起来都是重复的,这些的模式匹配会很好。


除此之外,OBJECT_FILES 变量变得不必要了。这有效:

PARAM_LIST_TARGET = parameter_list_test
PARAM_LIST_SOURCE_FILES = \
    ../parameter_list.c \
    parameter_list_test.c
$(PARAM_LIST_TARGET): $(addsuffix .o,$(basename $(PARAM_LIST_SOURCE_FILES))) # The dependencies directly

将最后一行作为所有目标的一条规则仍然感觉不错。类似于 "for all variables ending with TARGET, build a dependency to the content of the variable with the same name, but ending with SOURCE_FILES instead".

您始终可以通过构造变量的名称来访问 make 变量:

MY_VAR := "my var"
HIS_VAR := "his var"
HER_VAR := "her var"
CATS_VAR := "cats var"
DOGS_VAR := "dogs var"

ALL_PERSONS := MY HIS HER CATS DOGS
ALL_VARS := $(foreach p,$(ALL_PERSONS),$($(p)_VAR))

$(info $(ALL_VARS))

输出:

$ make
"my var" "his var" "her var" "cats var" "dogs var"