我目前正在尝试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
答案 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编译器以及CC
和CFLAGS
变量指定的标志它这样做(它将这样做)。它还使用特殊变量$@
,该特殊变量在规则的配方中扩展为规则目标的名称。 make
的某些版本提供了更多的机会来对此进行干燥。
除其他事项外,请注意如何分别在顶部附近指定一次编译器和构建标志。现在,如果您要更改这些内容,可以在一个易于查找的位置进行。
答案 2 :(得分:0)
您需要添加依赖项。使用GNU make时,对于小型项目,您可以跳过.o
步骤,然后将程序整体编译
speller: speller.c dictionary.c
${CLANG} ${CFLAGS} ${LDFLAGS} $(filter %.c,$^) -o $@ ${LIBS}