单元测试的 Makefile(通用文件)
Makefile for UnitTests (universal file)
我一直在研究 Makefile 以在 C 中自动化单元测试。主要目标是对于任何遵循源和测试目录结构的给定项目,make
编译函数和make test
编译并运行测试。
虽然 make
命令工作得很好,但 make test
却没有。在下面的配置中,test 的依赖调用 %.exe
目标,而不是 test_%.exe
.
如何成功调用任何以“test_”开头的测试目标?
我试过为它创建一个通配符,但没有成功。这可能仍然缺乏知识,但我希望能在这里找到一些帮助:)
CC := gcc
CFLAGS := -Wall -Werror
CSYNTAX := -fsyntax-only -Wall
SRC = $(wildcard ./src/*.c)
DEP = $(SRC:.c=.exe)
SRCTEST = ./test/UnitTests
PATHI = ./test/UnitTests/includes
PATHU = ./test/UnitTests/Unity
INC := ./src/includes
TEST = test_$.exe
# Compilation of main program
all: $(DEP)
syntax: *.c $(SRC) $(SRCTEST)/test_*.c
$(CC) $(CSYNTAX) $^ $(CFLAGS) -I$(INC) -I $(PATHI)
%.exe: *.c $(SRC)
$(CC) $^ $(CFLAGS) -I$(INC) -o $@
./$@
# Compilation and execution of tests
test: $(SRCTEST)/test_*.exe
test_%.exe: $(SRCTEST)/test_%.c $(SRC) $(PATHU)/unity.c
$(CC) $(CFLAGS) $^ -I $(INC) -I $(PATHI) -I $(PATHU) -o $@
./$@
clean:
del *.exe
我在 MinGW 8.1.0 上使用 GNU gcc,但也可以访问 gcc Ubunutu 7.5.0 (replit.com)
这里有很多微妙的问题。
首先,当你的测试目标依赖于一个通配符时,它的解析并不直观,因为它没有被 make
直接展开。如果匹配文件不存在,make
将尝试查找其中包含文字 *
的规则:
$ cat Makefile
SRC = $(wildcard ./src/*.c)
SRCTEST = ./test/UnitTests
%.exe: $(SRC)
echo Making $@ from $^
test: $(SRCTEST)/test_*.exe
test_%.exe: $(SRCTEST)/test_%.c $(SRC)
echo Making $@ from $^
$ make test -dr
...
Considering target file 'test'.
Looking for an implicit rule for 'test'.
No implicit rule found for 'test'.
Considering target file 'test/UnitTests/test_*.exe'.
File 'test/UnitTests/test_*.exe' does not exist.
Looking for an implicit rule for 'test/UnitTests/test_*.exe'.
Trying pattern rule with stem '*'.
Trying implicit prerequisite 'test/UnitTests/test/UnitTests/test_*.c'.
Trying pattern rule with stem 'test_*'.
Trying rule prerequisite 'src/foo.c'.
Found an implicit rule for 'test/UnitTests/test_*.exe'.
Considering target file 'src/foo.c'.
Looking for an implicit rule for 'src/foo.c'.
No implicit rule found for 'src/foo.c'.
Finished prerequisites of target file 'src/foo.c'.
No need to remake target 'src/foo.c'.
Finished prerequisites of target file 'test/UnitTests/test_*.exe'.
Must remake target 'test/UnitTests/test_*.exe'.
echo Making test/UnitTests/test_*.exe from src/foo.c
...
假设您不想创建一个字面上名为 test_*.exe
的文件,测试二进制文件应该具有预期的名称,即:
$ cat Makefile
SRC = $(wildcard ./src/*.c)
SRCTEST = ./test/UnitTests
%.exe: $(SRC)
echo Making $@ from $^
.PHONY: test
test: $(patsubst %.c,%.exe,$(wildcard $(SRCTEST)/test_*.c))
test_%.exe: $(SRCTEST)/test_%.c $(SRC)
echo Making $@ from $^
这将从测试源文件派生测试二进制名称,方法是将它们的后缀从 .c
转换为 .exe
。 (作为旁注,目标本身应该是假的,因为它不会创建真实文件)。
给定的文件结构:
$ ls -R
.:
Makefile src test
./src:
foo.c
./test:
UnitTests
./test/UnitTests:
test_foo.c
这导致尝试创建 test_foo.exe
而不是 test_*.exe
:
$ make test -dr
...
Considering target file 'test'.
File 'test' does not exist.
Considering target file 'test/UnitTests/test_foo.exe'.
File 'test/UnitTests/test_foo.exe' does not exist.
Looking for an implicit rule for 'test/UnitTests/test_foo.exe'.
Trying pattern rule with stem 'foo'.
Trying implicit prerequisite 'test/UnitTests/test/UnitTests/test_foo.c'.
Trying pattern rule with stem 'test_foo'.
Trying rule prerequisite 'src/foo.c'.
Found an implicit rule for 'test/UnitTests/test_foo.exe'.
Considering target file 'src/foo.c'.
Looking for an implicit rule for 'src/foo.c'.
No implicit rule found for 'src/foo.c'.
Finished prerequisites of target file 'src/foo.c'.
No need to remake target 'src/foo.c'.
Finished prerequisites of target file 'test/UnitTests/test_foo.exe'.
Must remake target 'test/UnitTests/test_foo.exe'.
echo Making test/UnitTests/test_foo.exe from src/foo.c
...
仍然,它没有遵循测试规则,而是遵循一般源代码规则。这是为什么?好吧,那是因为在匹配词干(%
部分)时,目录是 prepended 到搜索到的目标。您可以在上面的输出中看到,当 make
为 Considering target file 'test/UnitTests/test_foo.exe'
时,它将查找文件 test/UnitTests/test/UnitTests/test_foo.c
,该文件来自 $(SRCTEST)/test_%.c
,同时明确提及 $(SRCTEST)
也会自动从词干添加到前缀。当然这样的文件不存在,因此规则被拒绝。
正确的修复很简单:
$ cat Makefile
SRC = $(wildcard ./src/*.c)
SRCTEST = ./test/UnitTests
%.exe: $(SRC)
echo Making $@ from $^
.PHONY: test
test: $(patsubst %.c,%.exe,$(wildcard $(SRCTEST)/test_*.c))
test_%.exe: test_%.c $(SRC)
echo Making $@ from $^
$ make -s test
Making test/UnitTests/test_foo.exe from test/UnitTests/test_foo.c src/foo.c
请注意,它现在已经按预期从测试源构建了测试二进制文件。
我一直在研究 Makefile 以在 C 中自动化单元测试。主要目标是对于任何遵循源和测试目录结构的给定项目,make
编译函数和make test
编译并运行测试。
虽然 make
命令工作得很好,但 make test
却没有。在下面的配置中,test 的依赖调用 %.exe
目标,而不是 test_%.exe
.
如何成功调用任何以“test_”开头的测试目标?
我试过为它创建一个通配符,但没有成功。这可能仍然缺乏知识,但我希望能在这里找到一些帮助:)
CC := gcc
CFLAGS := -Wall -Werror
CSYNTAX := -fsyntax-only -Wall
SRC = $(wildcard ./src/*.c)
DEP = $(SRC:.c=.exe)
SRCTEST = ./test/UnitTests
PATHI = ./test/UnitTests/includes
PATHU = ./test/UnitTests/Unity
INC := ./src/includes
TEST = test_$.exe
# Compilation of main program
all: $(DEP)
syntax: *.c $(SRC) $(SRCTEST)/test_*.c
$(CC) $(CSYNTAX) $^ $(CFLAGS) -I$(INC) -I $(PATHI)
%.exe: *.c $(SRC)
$(CC) $^ $(CFLAGS) -I$(INC) -o $@
./$@
# Compilation and execution of tests
test: $(SRCTEST)/test_*.exe
test_%.exe: $(SRCTEST)/test_%.c $(SRC) $(PATHU)/unity.c
$(CC) $(CFLAGS) $^ -I $(INC) -I $(PATHI) -I $(PATHU) -o $@
./$@
clean:
del *.exe
我在 MinGW 8.1.0 上使用 GNU gcc,但也可以访问 gcc Ubunutu 7.5.0 (replit.com)
这里有很多微妙的问题。
首先,当你的测试目标依赖于一个通配符时,它的解析并不直观,因为它没有被 make
直接展开。如果匹配文件不存在,make
将尝试查找其中包含文字 *
的规则:
$ cat Makefile
SRC = $(wildcard ./src/*.c)
SRCTEST = ./test/UnitTests
%.exe: $(SRC)
echo Making $@ from $^
test: $(SRCTEST)/test_*.exe
test_%.exe: $(SRCTEST)/test_%.c $(SRC)
echo Making $@ from $^
$ make test -dr
...
Considering target file 'test'.
Looking for an implicit rule for 'test'.
No implicit rule found for 'test'.
Considering target file 'test/UnitTests/test_*.exe'.
File 'test/UnitTests/test_*.exe' does not exist.
Looking for an implicit rule for 'test/UnitTests/test_*.exe'.
Trying pattern rule with stem '*'.
Trying implicit prerequisite 'test/UnitTests/test/UnitTests/test_*.c'.
Trying pattern rule with stem 'test_*'.
Trying rule prerequisite 'src/foo.c'.
Found an implicit rule for 'test/UnitTests/test_*.exe'.
Considering target file 'src/foo.c'.
Looking for an implicit rule for 'src/foo.c'.
No implicit rule found for 'src/foo.c'.
Finished prerequisites of target file 'src/foo.c'.
No need to remake target 'src/foo.c'.
Finished prerequisites of target file 'test/UnitTests/test_*.exe'.
Must remake target 'test/UnitTests/test_*.exe'.
echo Making test/UnitTests/test_*.exe from src/foo.c
...
假设您不想创建一个字面上名为 test_*.exe
的文件,测试二进制文件应该具有预期的名称,即:
$ cat Makefile
SRC = $(wildcard ./src/*.c)
SRCTEST = ./test/UnitTests
%.exe: $(SRC)
echo Making $@ from $^
.PHONY: test
test: $(patsubst %.c,%.exe,$(wildcard $(SRCTEST)/test_*.c))
test_%.exe: $(SRCTEST)/test_%.c $(SRC)
echo Making $@ from $^
这将从测试源文件派生测试二进制名称,方法是将它们的后缀从 .c
转换为 .exe
。 (作为旁注,目标本身应该是假的,因为它不会创建真实文件)。
给定的文件结构:
$ ls -R
.:
Makefile src test
./src:
foo.c
./test:
UnitTests
./test/UnitTests:
test_foo.c
这导致尝试创建 test_foo.exe
而不是 test_*.exe
:
$ make test -dr
...
Considering target file 'test'.
File 'test' does not exist.
Considering target file 'test/UnitTests/test_foo.exe'.
File 'test/UnitTests/test_foo.exe' does not exist.
Looking for an implicit rule for 'test/UnitTests/test_foo.exe'.
Trying pattern rule with stem 'foo'.
Trying implicit prerequisite 'test/UnitTests/test/UnitTests/test_foo.c'.
Trying pattern rule with stem 'test_foo'.
Trying rule prerequisite 'src/foo.c'.
Found an implicit rule for 'test/UnitTests/test_foo.exe'.
Considering target file 'src/foo.c'.
Looking for an implicit rule for 'src/foo.c'.
No implicit rule found for 'src/foo.c'.
Finished prerequisites of target file 'src/foo.c'.
No need to remake target 'src/foo.c'.
Finished prerequisites of target file 'test/UnitTests/test_foo.exe'.
Must remake target 'test/UnitTests/test_foo.exe'.
echo Making test/UnitTests/test_foo.exe from src/foo.c
...
仍然,它没有遵循测试规则,而是遵循一般源代码规则。这是为什么?好吧,那是因为在匹配词干(%
部分)时,目录是 prepended 到搜索到的目标。您可以在上面的输出中看到,当 make
为 Considering target file 'test/UnitTests/test_foo.exe'
时,它将查找文件 test/UnitTests/test/UnitTests/test_foo.c
,该文件来自 $(SRCTEST)/test_%.c
,同时明确提及 $(SRCTEST)
也会自动从词干添加到前缀。当然这样的文件不存在,因此规则被拒绝。
正确的修复很简单:
$ cat Makefile
SRC = $(wildcard ./src/*.c)
SRCTEST = ./test/UnitTests
%.exe: $(SRC)
echo Making $@ from $^
.PHONY: test
test: $(patsubst %.c,%.exe,$(wildcard $(SRCTEST)/test_*.c))
test_%.exe: test_%.c $(SRC)
echo Making $@ from $^
$ make -s test
Making test/UnitTests/test_foo.exe from test/UnitTests/test_foo.c src/foo.c
请注意,它现在已经按预期从测试源构建了测试二进制文件。