无法使用我的 C 单元测试进行编译

问题描述 投票:0回答:1

我正在尝试使用 Criterion 框架编译我的项目以进行单元测试。这是我的项目的组织方式:

.
├── 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(位于根目录的 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(在测试文件夹中),它无法编译

tests_run
规则。其内容如下:

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

我在调用

tests_run
时收到以下错误:

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吗?

c makefile c-criterion
1个回答
0
投票

这条规则:

$(OBJ_DIR)/%.o: %.c

告诉 make,“如果你想构建一个文件

../obj/X.o
,你可以从文件创建它
X.c
”。

然后你要求 make 构建一个文件

../obj/display_prompt.o
,所以 make 会查找一个文件
display_prompt.c
。但是,该文件不存在。有一个源文件
../src/display_prompt.c
但这不是您告诉 make 可以使用的文件,因此它不会查找该文件。

有多种方法可以做到这一点。一种方法是添加新规则:

$(OBJ_DIR)/%.o: ../src/%.c
        ...

现在 make 知道如何从

../src
以及本地目录中的源文件构建目标文件。

或者,您可以假设其他人为您创建了目标文件,并且此 makefile 不需要构建它们:在这种情况下,将目标文件从先决条件列表中取出,然后将它们放入链接行中:

tests_run: $(NAME)
        ./$(NAME)

$(NAME): $(TEST_OBJ)
        $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

(让你的目标依赖于目标文件然后将源文件添加到链接行是错误的......为什么这样做?它会再次重新编译所有文件!)

您还可以使用VPATH来查找源文件。我个人认为第二种选择是最好的。使用两个包含构建相同目标文件的规则的不同 makefile 总是有问题的。

© www.soinside.com 2019 - 2024. All rights reserved.