对于Makefile中目录中的每个文件

时间:2018-03-18 19:11:32

标签: c makefile

我有这个项目结构:

/project
    |
    |____/bin
    |
    |
    |____/obj
    |
    |
    |____/include
    |    |
    |    |____aaa.h
    |    |
    |    |____bbb.h
    |    |
    |    |____ccc.h
    |
    |
    |____/src
    |    |
    |    |____aaa.c
    |    |
    |    |____bbb.c
    |    |
    |    |____ccc.c
    |
    |
    |____/test
    |    |
    |    |____aaa_test.c
    |    |
    |    |____bbb_test.c
    |    |
    |    |____ccc_test.c
    |
    |
    |____Makefile

我需要编写一个Makefile来测试这个项目中的每个模块。对于test文件夹中的每个文件,我应该在src文件夹中编译相关模块(不带" _test"同名),并在文件夹bin中创建可执行文件。

要执行的命令列表:

gcc -Wall -g -I include -c src/aaa.c -o obj/aaa.o
gcc -Wall -g -I include -c test/aaa_test.c -o obj/aaa_test.o
gcc obj/aaa.o obj/aaa_test.o -o bin/aaa_test.exe

gcc -Wall -g -I include -c src/bbb.c -o obj/bbb.o
gcc -Wall -g -I include -c test/bbb_test.c -o obj/bbb_test.o
gcc obj/bbb.o obj/bbb_test.o -o bin/bbb_test.exe

gcc -Wall -g -I include -c src/ccc.c -o obj/ccc.o
gcc -Wall -g -I include -c test/ccc_test.c -o obj/ccc_test.o
gcc obj/ccc.o obj/ccc_test.o -o bin/ccc_test.exe

我当前的Makefile:

CC := gcc
CCFLAGS := -Wall -g
INC := -I include
BINDIR := bin
OBJDIR := obj
SRCDIR := src
TESTDIR := test

all: $(BINDIR)/aaa_test.exe $(BINDIR)/bbb_test.exe $(BINDIR)/ccc_test.exe

NAME = aaa

$(BINDIR)/$(NAME)_test.exe: $(OBJDIR)/$(NAME).o $(OBJDIR)/$(NAME)_test.o
    $(CC) $^ -o $@

$(OBJDIR)/$(NAME).o: $(SRCDIR)/$(NAME).c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

$(OBJDIR)/$(NAME)_test.o: $(TESTDIR)/$(NAME)_test.c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

NAME = bbb

$(BINDIR)/$(NAME)_test.exe: $(OBJDIR)/$(NAME).o $(OBJDIR)/$(NAME)_test.o
    $(CC) $^ -o $@

$(OBJDIR)/$(NAME).o: $(SRCDIR)/$(NAME).c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

$(OBJDIR)/$(NAME)_test.o: $(TESTDIR)/$(NAME)_test.c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

NAME = ccc

$(BINDIR)/$(NAME)_test.exe: $(OBJDIR)/$(NAME).o $(OBJDIR)/$(NAME)_test.o
    $(CC) $^ -o $@

$(OBJDIR)/$(NAME).o: $(SRCDIR)/$(NAME).c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

$(OBJDIR)/$(NAME)_test.o: $(TESTDIR)/$(NAME)_test.c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

我可以读取test文件夹中每个文件的名称并优化我的Makefile吗?

2 个答案:

答案 0 :(得分:1)

我认为使用常规源文件(foo.c),测试源(foo_test.c),头文件(foo.h),目标文件(foo.o)和可执行文件(foo.exe)位于不同的目录中,编写一个可以处理它的makefile并不困难。

让我们从您当前的makefile开始:

NAME = aaa

$(BINDIR)/$(NAME)_test.exe: $(OBJDIR)/$(NAME).o $(OBJDIR)/$(NAME)_test.o
    $(CC) $^ -o $@

$(OBJDIR)/$(NAME).o: $(SRCDIR)/$(NAME).c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

$(OBJDIR)/$(NAME)_test.o: $(TESTDIR)/$(NAME)_test.c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

# repeated for bbb and ccc

但我们不是使用NAME变量进行复制粘贴,而是将其写为https://oracle-base.com/articles/misc/ftp-from-plsql

$(BINDIR)/%_test.exe: $(OBJDIR)/%.o $(OBJDIR)/%_test.o
    $(CC) $^ -o $@

$(OBJDIR)/%.o: $(SRCDIR)/%.c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

$(OBJDIR)/%_test.o: $(TESTDIR)/%_test.c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

# no repetition needed

如果您愿意,可以将最后两条规则合并为一条,使用pattern rules告诉Make在哪里搜索来源:

$(OBJDIR)/%.o: %.c
    $(CC) $(CCFLAGS) $(INC) -c $< -o $@

vpath %.c $(SRCDIR) $(TESTDIR)

现在不是拼写出所有的测试:

all: $(BINDIR)/aaa_test.exe $(BINDIR)/bbb_test.exe $(BINDIR)/ccc_test.exe

您可以使用vpath directive

在Make目录中查看
TEST_SOURCES := $(wildcard $(TESTDIR)/*.c)    
TESTS := $(patsubst $(TESTDIR)/%_test.c,$(BINDIR)/%_test.exe,$(TEST_SOURCES))

all: $(TESTS)

P.S。您还可以使用通配符根据您的命名约定查找模块的所有源代码,例如src / aaa_1.c和src / aaa_2.c,但这是另一回事,这个答案变得越来越长。

答案 1 :(得分:0)

Makefile看起来很奇怪。我建议你摆脱$(OBJDIR)$(BINDIR)所以Make可以编译到当前目录,我们可以使用它的内置规则来节省我们自己编写的内容。我们可以使用$(wildcard )查找*_test.c源文件,并使用$(patsubst )确定相应的目标,如下所示:

CC := gcc
CFLAGS := -Wall -g
CFLAGS += -Iinclude
SRCDIR := src
TESTDIR := test

# Source files locations
VPATH = $(SRCDIR):$(TESTDIR)

all-tests: $(patsubst $(TESTDIR)/%.c,%,$(wildcard $(TESTDIR)/*_test.c))

%_test: %_test.o %.o
    $(LINK.c) $^ $(LDLIBS) -o $@

(请注意,我已将CCFLAGS更改为CFLAGS,因此我们可以允许默认的%.o: %.c规则执行此操作。它现在更短更简单,维护更少。