使用Criterion框架编译C单元测试失败,请求修正Makefile
问题:使用Criterion框架编译C单元测试时Makefile报错
我尝试用Criterion为C项目编写单元测试,但运行tests_run规则时编译失败,报错提示找不到目标文件的生成规则。
项目结构
. ├── include │ └── mysh.h ├── Makefile ├── obj ├── src │ ├── arrays_handler.c │ ├── builtin_env.c │ ├── delete_from_env.c │ ├── display_env.c │ ├── display_prompt.c │ ├── doubly_linked_list.c │ ├── env_handler.c │ ├── execute_command.c │ ├── mysh.c │ ├── my_strcmp.c │ ├── my_strcpy.c │ ├── my_strdup.c │ ├── my_strlen.c │ ├── my_strncmp.c │ ├── my_strndup.c │ ├── my_strrchr.c │ ├── my_str_to_word_array.c │ ├── name_slice.c │ ├── parse_command.c │ ├── sanitize.c │ ├── shell_handler.c │ └── strbind.c └── tests ├── Makefile └── sanitize_test.c
根目录Makefile(可正常编译)
INCLUDE_DIR := include OBJ_DIR := obj SRC_DIR := src NAME := mysh CC := gcc CFLAGS := -Wall -Wextra -Werror -ggdb3 CPPFLAGS := -I$(INCLUDE_DIR) SRC_FILES := $(wildcard $(SRC_DIR)/*.c) OBJ_FILES := $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC_FILES)) all: $(NAME) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(NAME): $(OBJ_FILES) @$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS) clean: @$(MAKE) -C ./tests tests_clean @rm -rf $(OBJ_DIR)/*.o fclean: clean @$(MAKE) -C ./tests tests_fclean @rm -rf $(NAME) tests_run: fclean @$(MAKE) -C ./tests tests_run re: fclean all .PHONY: all clean fclean tests_run re
测试目录原Makefile(报错版本)
CC := gcc CFLAGS := -Wall -Wextra -Werror -ggdb3 CPPFLAGS := -I../include LDFLAGS := -Lcriterion/lib LDLIBS := -lcriterion NAME = ../unit-tests OBJ_DIR = ../obj SRC = $(shell find ../src -name '*.c' ! -name 'mysh.c') TEST_SRC = $(shell find . -name '*.c') OBJ = $(patsubst ../src/%.c,$(OBJ_DIR)/%.o,$(SRC)) TEST_OBJ = $(patsubst ./%.c,$(OBJ_DIR)/%.o,$(TEST_SRC)) $(OBJ_DIR)/%.o: %.c @mkdir -p $(OBJ_DIR) @$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ tests_run: $(OBJ) $(TEST_OBJ) @$(CC) $(CFLAGS) $(LDFLAGS) $(filter-out ../obj/mysh.o,$(TEST_SRC) $(SRC)) $(LDLIBS) -o $(NAME) @./$(NAME) tests_clean: @rm -rf $(OBJ) @rm -f ../*.gcda @rm -f ../*.gcno tests_fclean: tests_clean @rm -f $(NAME) .PHONY: tests_run tests_clean tests_fclean
报错信息
make[1]: enter the "[...]/tests" directory make[1]: exit the "[...]/tests" directory make[1]: enter the "[...]/tests" directory make[1]: exit the "[...]/tests" directory make[1]: enter the "[...]/tests" directory make[1]: *** No rule to make target "../obj/display_prompt.o", required for "tests_run". Stop. make[1]: exit directory "[...]/tests". make: *** [Makefile:29: tests_run] Error 2
修正后的测试目录Makefile
CC := gcc CFLAGS := -Wall -Wextra -Werror -ggdb3 CPPFLAGS := -I../include LDFLAGS := -Lcriterion/lib LDLIBS := -lcriterion NAME = ../unit-tests OBJ_DIR = ../obj # 排除mysh.c,只取src下的其他源文件 SRC = $(filter-out ../src/mysh.c, $(wildcard ../src/*.c)) TEST_SRC = $(wildcard ./*.c) # 生成src对应目标文件路径 OBJ = $(patsubst ../src/%.c, $(OBJ_DIR)/%.o, $(SRC)) # 生成测试源文件对应目标文件路径,添加test_前缀避免重名 TEST_OBJ = $(patsubst ./%.c, $(OBJ_DIR)/test_%.o, $(TEST_SRC)) # 规则1:编译src目录下的.c文件到obj目录 $(OBJ_DIR)/%.o: ../src/%.c @mkdir -p $(OBJ_DIR) @$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ # 规则2:编译当前目录(tests)下的.c文件到obj目录 $(OBJ_DIR)/test_%.o: ./%.c @mkdir -p $(OBJ_DIR) @$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ tests_run: $(OBJ) $(TEST_OBJ) # 链接所有目标文件生成测试可执行文件 @$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $(NAME) @./$(NAME) tests_clean: @rm -rf $(OBJ) $(TEST_OBJ) @rm -f ../*.gcda ../*.gcno tests_fclean: tests_clean @rm -f $(NAME) .PHONY: tests_run tests_clean tests_fclean
关键修改点说明
- 源文件匹配优化:用
wildcard替代find,符合Makefile常规写法,避免不必要的子shell调用。 - 目标文件规则修复:
- 新增专门处理
../src/%.c到$(OBJ_DIR)/%.o的规则,解决原规则无法匹配上层目录源文件的问题。 - 测试文件目标文件添加
test_前缀,避免和src目录的目标文件重名冲突。
- 新增专门处理
- 链接命令修正:原命令错误使用源文件而非目标文件,改为用
$^引用所有依赖目标文件,逻辑清晰且正确。 - 清理规则完善:确保测试生成的目标文件也被清理。
内容的提问来源于stack exchange,提问作者Nayrosk
相关产品推荐
相关产品推荐

