更改源文件后,为什么不进行make重建?

时间:2019-03-18 20:17:32

标签: c makefile cs50

我目前正在尝试CS50课程中的问题4(错位)。这是第一个问题集,其中有多个头文件和多个源文件,因此它们给了我们一个Makefile以供使用,将每个.c文件编译为.o,然后将.o文件链接以形成编译后的二进制文件。

这是makefile文件

speller:
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o speller.o speller.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o dictionary.o dictionary.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -o speller speller.o dictionary.o

ls的输出:

dictionaries  dictionary.h  keys      speller    speller.o dictionary.c  dictionary.o  Makefile  speller.c  texts

当我第一次运行make时,它编译拼写器没有问题。但是,当我在dictionary.c中进行更改并保存时(特别是,我故意将对printasdasdsa()的所有printf()调用搞砸了,是的,您知道了),然后运行make,它总是说make: 'speller' is up to date,并且即使我更改了dictionary.c的源代码,也拒绝重建。

您知道我构建拼写器的方式有什么问题吗?我的makefile出问题了吗?

我知道有一种方法可以通过传递“ -B”标志来强制make进行重建,但是惯例是每当您对代码进行更改时总是那样做吗?

这是任务:https://docs.cs50.net/2019/x/psets/4/speller/hashtable/speller.html

3 个答案:

答案 0 :(得分:1)

仅当目标不存在或目标早于其依赖项之一时,Make才会重建目标。在您的情况下,您有一个目标speller,没有依赖性。第一次运行它时,请进行检查并没有找到它,因此它将构建它。下次生成时,它将检查文件是否存在,并且由于它没有任何依赖性,因此不会重新生成。您可能想要做类似的事情:

speller:  speller.c dictionary.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o speller.o speller.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o dictionary.o dictionary.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -o speller speller.o dictionary.o

或者,更好的是:

speller: speller.o dictionary.o
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -o speller speller.o dictionary.o

speller.o: speller.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o speller.o speller.c

dictionary.o: dictionary.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o dictionary.o dictionary.c

除非.c文件更改,否则不会重建.o文件,除非重新构建.o文件之一,否则不会重建应用程序。请注意,这两个文件中的 都不处理任何头文件。如果您的.c文件包含任何本地标头,则也需要将其添加到依赖项中。

答案 1 :(得分:1)

@HardcoreHenry在他的回答中很好地说明了make的行为(不接受该行为)。但是,我想指出的是,make在构建软件方面具有相当多的内置智能功能,以至于它可以完成相对简单的构建而根本不需要任何Makefile。而且,当您编写Makefile时,通常认为这种样式可以减少重复。

因此,我建议将其作为更好的替代方案:

CC = clang
CFLAGS = -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 \
  -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare       \
  -Wno-unused-parameter -Wno-unused-variable -Wshadow

speller: speller.o dictionary.o
    $(CC) -o $@ $(CFLAGS) speller.o dictionary.o

这依赖于make知道如何从C源文件构建目标文件(它确实这样做),并在需要时使用C编译器以及CCCFLAGS变量指定的标志它这样做(它将这样做)。它还使用特殊变量$@,该特殊变量在规则的配方中扩展为规则目标的名称。 make的某些版本提供了更多的机会来对此进行干燥。

除其他事项外,请注意如何分别在顶部附近指定一次编译器和构建标志。现在,如果您要更改这些内容,可以在一个易于查找的位置进行。

答案 2 :(得分:0)

您需要添加依赖项。使用GNU make时,对于小型项目,您可以跳过.o步骤,然后将程序整体编译

speller:  speller.c dictionary.c
         ${CLANG} ${CFLAGS} ${LDFLAGS} $(filter %.c,$^) -o $@ ${LIBS}