我有这个项目结构:
/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吗?
答案 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
规则执行此操作。它现在更短更简单,维护更少。