make
依赖于 makefile 作者告诉它每个目标的先决条件是什么——也就是说,哪些其他目标或文件会影响相关目标的构造,因此,如果它们较新或本身已过时,则目标已过时并且应该重建。正如您的其他答案已经表明的那样,您没有为目标指定任何先决条件,因此make
当且仅当它们根本不存在时才认为它们已经过时。
这实际上是有问题的both目标,尽管方式不同。对于目标consoleapp
,它代表您想要构建的实际文件,如果未能指定任何先决条件,则会产生您询问的问题:make
不认识到对源文件的更改需要重建。解决这个问题的最简单方法是将源文件名添加到配方的标题行的冒号后面:
consoleapp: consoleapp.cpp
g++ consoleapp.cpp -o consoleapp
然而,一般来说,明智的做法是尽量减少 makefile 代码中的重复,为此,您可以使用一些make
的自动变量,以避免在规则配方中重复目标和先决条件名称。我特别推荐always using $@
在其配方中指定规则的目标:
consoleapp: consoleapp.cpp
g++ consoleapp.cpp -o $@
对于先决条件来说,这更具情境性。在这种情况下,所有的必备条件都是要编译的源文件,而且只有一个。如果您愿意依赖 GNU 扩展,那么在配方中您可以通过以下任一方式表示源$<
(这代表first先决条件),或作为$^
(它代表整个先决条件列表,删除了所有重复项)。例如,
consoleapp: consoleapp.cpp
g++ $^ -o $@
如果您不使用 GNUmake
但是,或者如果您想支持其他不支持的人,那么您就必须在这里进行一些重复。您仍然可以节省一些精力,特别是在源列表发生更改的情况下,通过创建make
源的变量并复制该变量,而不是复制源列表本身:
consoleapp_SRCS = consoleapp.cpp
consoleapp: $(consoleapp_SRCS)
g++ $(consoleapp_SRCS) -o $@
我之前提到过,存在以下问题both你的规则。但可能有什么问题clean
规则,你可能会问?它不会创建名为“clean”的文件,因此每次执行时都会运行其配方make clean
,如你所愿,对吧?不必要。虽然那条规则不会创建名为“clean”的文件,如果这样的文件是通过其他方式创建的,那么突然您的clean
规则将停止工作,因为将发现该文件就其(空)先决条件列表而言已经是最新的。
POSIX标准make
没有解决方案,但 GNUmake
为其提供特殊目标.PHONY
。对于 GNU make,指定为先决条件的任何目标.PHONY
总是被认为是过时的,并且文件系统甚至不会检查它们。这正是为了支持诸如clean
,用于指定要执行的操作,这些操作不会在文件系统上产生持久工件。虽然这是一个 GNU 扩展,但它是可移植的,因为它使用标准make
语法和目标的形式是为扩展保留的,所以make
不支持.PHONY
在 GNU 意义上,很可能要么忽略它,要么将其视为普通规则:
.PHONY: clean
clean:
rm -rf *.o consoleapp