为什么在更改源文件时 make 不重建?
Why is make not rebuilding when source files are changed?
我目前正在尝试 CS50 课程中的问题集 4(拼写)。这是我们有多个头文件和多个源文件的第一个问题集,所以他们给了我们一个 Makefile 来使用,将每个 .c 文件编译成 .o,然后 link 个 .o 文件形成编译二进制。
这是生成文件
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
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 文件,否则不会重建应用程序。请注意,这两个 都不处理任何 header 文件。如果您的 .c 文件包含任何本地 header,则还需要将它们添加到依赖项中。
@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
的某些版本提供了更多的机会来解决这个问题。
除其他事项外,请注意编译器和构建标志是如何在顶部附近分别指定一次的。现在,如果您想更改这些内容,可以在一个容易找到的地方进行。
您需要添加依赖项。使用GNU make时,小项目可以跳过.o
这一步,整体编译程序
speller: speller.c dictionary.c
${CLANG} ${CFLAGS} ${LDFLAGS} $(filter %.c,$^) -o $@ ${LIBS}
我目前正在尝试 CS50 课程中的问题集 4(拼写)。这是我们有多个头文件和多个源文件的第一个问题集,所以他们给了我们一个 Makefile 来使用,将每个 .c 文件编译成 .o,然后 link 个 .o 文件形成编译二进制。
这是生成文件
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
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 文件,否则不会重建应用程序。请注意,这两个 都不处理任何 header 文件。如果您的 .c 文件包含任何本地 header,则还需要将它们添加到依赖项中。
@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
的某些版本提供了更多的机会来解决这个问题。
除其他事项外,请注意编译器和构建标志是如何在顶部附近分别指定一次的。现在,如果您想更改这些内容,可以在一个容易找到的地方进行。
您需要添加依赖项。使用GNU make时,小项目可以跳过.o
这一步,整体编译程序
speller: speller.c dictionary.c
${CLANG} ${CFLAGS} ${LDFLAGS} $(filter %.c,$^) -o $@ ${LIBS}