使用`main`的多个文件的Makefile

时间:2015-08-25 14:40:12

标签: c makefile

我的目录结构如下:

tests\
        test1.c
        test2.c
        test3.c
        build\
                 test1
                 test2
                 test3

具体而言,我想构建test1.ctest2.ctest3.c并在tests\build中输出可执行文件。

为了实现这一点,我有以下Makefile片段:

TSTS = $(wildcard $(TEST_DIR)/*.c)
EXE = $(patsubst $(TEST_DIR)/%.c,$(TEST_BUILD)/%, $(TSTS))
TEST_DIR = tests
TEST_BUILD = tests/build

$(EXE): $(TSTS)
        $(CC) $< $(CFLAGS_OUT) $@ (CFLAGS_LIBS_FLAG)$(LIB_NAME)

这给了我类似的东西:

gcc -L/home/projects/loc/build -Iinclude tests/test1.c -o tests/build/test1 -lsalmalloc
gcc -L/home/projects/loc/build -Iinclude tests/test1.c -o tests/build/test2 -lsalmalloc
gcc -L/home/projects/loc/build -Iinclude tests/test1.c -o tests/build/test3 -lsalmalloc

输出路径是正确的,但源文件都是tests/test1.c

忽略include和其他lib相关文件,因为我删除了标记以使其变得简单。实质上,make正在从单个文件构建测试用例,也就是说,对于单个源文件test1.c,使用不同的名称生成三个构建,而不是每个测试都有自己的构建。我查看了herehereherehere,但找不到问题。

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

你的目标

$(EXE): $(TSTS)

扩展为

tests/build/test1 tests/build/test2 tests/build/test3: tests/test1.c tests/test2.c tests/test3.c

,阅读有关Multiple Targets in a Rule

的手册
  

具有多个目标的规则相当于编写许多规则,每个规则都有一个目标,除此之外都是相同的。相同的配方适用于所有目标,但其效果可能会有所不同,因为您可以使用'$ @'将实际目标名称替换为配方。该规则也为所有目标提供了相同的先决条件。

     

类似的食谱适用于所有目标。配方不需要完全相同,因为自动变量'$ @'可用于替换要重新映射到命令中的特定目标(请参阅自动变量)。例如:

bigoutput littleoutput : text.g
   generate text.g -$(subst output,,$@) > $@
     

相当于

bigoutput : text.g
   generate text.g -big > bigoutput
littleoutput : text.g
   generate text.g -little > littleoutput

相同
tests/build/test1: tests/test1.c tests/test2.c tests/test3.c
tests/build/test2: tests/test1.c tests/test2.c tests/test3.c
tests/build/test3: tests/test1.c tests/test2.c tests/test3.c

因此,当您在食谱中使用$<时,您始终会获得tests/test1.c

您想要的是pattern rule

  

因此,形式的规则

%.o : %.c ; recipe…
     

指定如何创建n.o文件,如果n.c存在或可以制作,则使用另一个文件n.c作为先决条件。

所以你想要

TSTS = $(wildcard $(TEST_DIR)/*.c)
EXES = $(patsubst $(TEST_DIR)/%.c,$(TEST_BUILD)/%, $(TSTS))

all: $(EXES)

$(TEST_BUILD)/%: $(TEST_DIR)/%.c
        $(CC) $< $(CFLAGS_OUT) $@ (CFLAGS_LIBS_FLAG)$(LIB_NAME)

答案 1 :(得分:1)

这根本不是multiple targets的工作方式。当你有:

test1 test2 test3 : test1.c test2.c test3.c
    $(CC) $< ...

这扩展到:

test1 : test1.c test2.c test3.c
    $(CC) $< ...

test2 : test1.c test2.c test3.c
    $(CC) $< ...

test3 : test1.c test2.c test3.c
    $(CC) $< ...

由于$<抓住了第一个先决条件,这就是你到处看到test1.c的原因。您想要做的是static pattern

$(EXE) : $(TEST_BUILD)/% : $(TEST_DIR)/%.c
    $(CC) $< ...

答案 2 :(得分:1)

您的规则相当于

tests/build/test1 tests/build/test2 tests/build/test3: \
    tests/test1.cc tests/test2.cc tests/test3.cc
        $(CC) $< $(CFLAGS_OUT) $@ (CFLAGS_LIBS_FLAG)$(LIB_NAME)

$<表示第一个先决条件,因此在这种情况下tests/test1.cc。您可能意味着$^,所有先决条件的名称,但这对您没有帮助,因为那样您将尝试将所有.cc文件一起编译为一个目标文件,三次。

您可能想要的是一种模式规则:

$(TEST_BUILD)/%: $(TEST_DIR)/%.cc
        $(CC) $< $(CFLAGS_OUT) $@ (CFLAGS_LIBS_FLAG)$(LIB_NAME)

您可能还需要添加虚拟目标

all: $(EXE)

取决于你在makefile中的其他内容。