无论文件是否更改都进行重建
Make rebuilds regardless of whether files are changed
我使用 make
构建一个不包含任何 C/C++ 文件的项目。
我的项目中有 python
目录,其中包含一些 python 代码,如果 python
中的任何内容发生更改,我将在构建过程中执行这些代码。
这是我的 Makefile
:
.PHONY: all python
all: python
python: python/
python python/code.py
但是,如果我连续调用 make
两次,它会一遍又一遍地构建所有内容。
我不太确定你期望发生什么,但你已经声明目标 python
是一个虚假目标并且 make 手册明确指出虚假目标 always 被认为已过时并总是重建:
The prerequisites of the special target .PHONY are considered to be phony targets. When it is time to consider such a target, make will run its recipe unconditionally, regardless of whether a file with that name exists or what its last-modification time is.
所以,很明显,当您 运行 您的 makefile 时,假目标 python
的配方将始终是 运行。
此外,如果您删除虚假设置,则此规则将永远不会 运行,因为您说的是目录 python
依赖于自身。文件永远不会过时。
我还应该指出,将目录列为先决条件并不是一个神奇的 shorthand 意思是“检查此目录中的每个文件”。它的字面意思是,检查目录的时间戳。目录的时间戳仅在该目录中的文件被重命名、删除或创建时更新。当该目录中的文件被修改时,它不会更新。
“如果 python
中的任何内容已更改” 并非 100% 明确。如果这意味着您在 python
中有一组 python 源文件,并且您希望每次更改其中一个时 运行 配方,如 MadScientist 解释得非常清楚,您不能使用 python
作为先决条件,这将不起作用,因为如果现有文件发生更改,python
的时间戳不会。声明 python
为 phony 没有帮助,它只是告诉 make 总是 运行 这个食谱。并且将 python
声明为自身的先决条件并没有真正意义,因为只有当某些先决条件比目标更新时,make 才会比较目标和先决条件的时间戳以及 运行s 配方。
一个选项是将所有这些 python 源文件声明为目标的先决条件,该目标将是一个真实文件,并且哪个时间戳将对应于配方的最后一次 运行。由于您没有说明配方的作用是什么,我们不知道我们可以基于哪个产品文件。因此,让我们为此创建一个空文件(如果有的话,用真实的产品文件替换它):
PYDIR := python
PYSRC := $(wildcard $(PYDIR)/*.py)
.PHONY: all
all: .python.done
.python.done: $(PYSRC)
python $(PYDIR)/code.py
touch $@
当然,如果您在 python
中有子目录,或者如果您的 python 源文件具有除 .py
之外的其他扩展名,或者存在除 [=43] 之外的其他文件=] 应该触发重建的源文件,或者如果某些源文件可以使用旧时间戳创建,或者如果某些源文件可以删除或任何其他更复杂的情况,这个简单的建议是不够的。
例如,如果可以在 python
中创建或删除文件(但不能在其子目录中创建或删除),并且您希望在发生这种情况时 运行 配方,您确实可以声明python
作为 .python.done
的先决条件,因为它的时间戳恰好在发生这种情况时发生变化:
.python.done: $(PYSRC) $(PYDIR)
如果您在 python
中有子目录,则必须将 wildcard
替换为:
PYSRC := $(shell find $(PYDIR) -type f -name '*.py')
如果要考虑 python
下的任何文件:
PYSRC := $(shell find $(PYDIR) -type f)
对我的问题的简洁明了的回答是,如果您不想保留构建的“产品”,make
是不可能的磁盘上的进程。原因如下:
- 声明不是目录或文件的目标的唯一方法是使用一些特殊目标(参见 documentation). As per .PHONY targets documentation,
.PHONY
目标是用作“名称”要执行的配方”。因此,.PHONY
目标似乎适合此目的。
- 但是,
.PHONY
目标总是重新运行 从头开始,无论它们的依赖项是否已更改。
我没有坚持使用 make
,而是编写了一个简单的 shell 脚本来调用 git 来了解 python
目录是否已更改并相应地构建。重要的是,在我的例子中,构建过程不会在本地磁盘上留下任何文件,因为所有生成的文件都会立即传输到远程。
对那些坚持使用 make
的人的补充说明:
make
需要构建过程的“产品”出现在磁盘上。否则,make
没有检测构建已经 运行. 的机制
- 不要使用
.PHONY
目标。相反,将构建的“产品”用作目标,将源文件用作依赖项。但是,要实现这一点,您首先需要拥有一些您想要保留的构建过程“产品”。不保留任何“产品”可能是完全合理的,但仍然要求构建过程 运行 只有在之前没有完成的情况下。
我使用 make
构建一个不包含任何 C/C++ 文件的项目。
我的项目中有 python
目录,其中包含一些 python 代码,如果 python
中的任何内容发生更改,我将在构建过程中执行这些代码。
这是我的 Makefile
:
.PHONY: all python
all: python
python: python/
python python/code.py
但是,如果我连续调用 make
两次,它会一遍又一遍地构建所有内容。
我不太确定你期望发生什么,但你已经声明目标 python
是一个虚假目标并且 make 手册明确指出虚假目标 always 被认为已过时并总是重建:
The prerequisites of the special target .PHONY are considered to be phony targets. When it is time to consider such a target, make will run its recipe unconditionally, regardless of whether a file with that name exists or what its last-modification time is.
所以,很明显,当您 运行 您的 makefile 时,假目标 python
的配方将始终是 运行。
此外,如果您删除虚假设置,则此规则将永远不会 运行,因为您说的是目录 python
依赖于自身。文件永远不会过时。
我还应该指出,将目录列为先决条件并不是一个神奇的 shorthand 意思是“检查此目录中的每个文件”。它的字面意思是,检查目录的时间戳。目录的时间戳仅在该目录中的文件被重命名、删除或创建时更新。当该目录中的文件被修改时,它不会更新。
“如果 python
中的任何内容已更改” 并非 100% 明确。如果这意味着您在 python
中有一组 python 源文件,并且您希望每次更改其中一个时 运行 配方,如 MadScientist 解释得非常清楚,您不能使用 python
作为先决条件,这将不起作用,因为如果现有文件发生更改,python
的时间戳不会。声明 python
为 phony 没有帮助,它只是告诉 make 总是 运行 这个食谱。并且将 python
声明为自身的先决条件并没有真正意义,因为只有当某些先决条件比目标更新时,make 才会比较目标和先决条件的时间戳以及 运行s 配方。
一个选项是将所有这些 python 源文件声明为目标的先决条件,该目标将是一个真实文件,并且哪个时间戳将对应于配方的最后一次 运行。由于您没有说明配方的作用是什么,我们不知道我们可以基于哪个产品文件。因此,让我们为此创建一个空文件(如果有的话,用真实的产品文件替换它):
PYDIR := python
PYSRC := $(wildcard $(PYDIR)/*.py)
.PHONY: all
all: .python.done
.python.done: $(PYSRC)
python $(PYDIR)/code.py
touch $@
当然,如果您在 python
中有子目录,或者如果您的 python 源文件具有除 .py
之外的其他扩展名,或者存在除 [=43] 之外的其他文件=] 应该触发重建的源文件,或者如果某些源文件可以使用旧时间戳创建,或者如果某些源文件可以删除或任何其他更复杂的情况,这个简单的建议是不够的。
例如,如果可以在 python
中创建或删除文件(但不能在其子目录中创建或删除),并且您希望在发生这种情况时 运行 配方,您确实可以声明python
作为 .python.done
的先决条件,因为它的时间戳恰好在发生这种情况时发生变化:
.python.done: $(PYSRC) $(PYDIR)
如果您在 python
中有子目录,则必须将 wildcard
替换为:
PYSRC := $(shell find $(PYDIR) -type f -name '*.py')
如果要考虑 python
下的任何文件:
PYSRC := $(shell find $(PYDIR) -type f)
对我的问题的简洁明了的回答是,如果您不想保留构建的“产品”,make
是不可能的磁盘上的进程。原因如下:
- 声明不是目录或文件的目标的唯一方法是使用一些特殊目标(参见 documentation). As per .PHONY targets documentation,
.PHONY
目标是用作“名称”要执行的配方”。因此,.PHONY
目标似乎适合此目的。 - 但是,
.PHONY
目标总是重新运行 从头开始,无论它们的依赖项是否已更改。
我没有坚持使用 make
,而是编写了一个简单的 shell 脚本来调用 git 来了解 python
目录是否已更改并相应地构建。重要的是,在我的例子中,构建过程不会在本地磁盘上留下任何文件,因为所有生成的文件都会立即传输到远程。
对那些坚持使用 make
的人的补充说明:
make
需要构建过程的“产品”出现在磁盘上。否则,make
没有检测构建已经 运行. 的机制
- 不要使用
.PHONY
目标。相反,将构建的“产品”用作目标,将源文件用作依赖项。但是,要实现这一点,您首先需要拥有一些您想要保留的构建过程“产品”。不保留任何“产品”可能是完全合理的,但仍然要求构建过程 运行 只有在之前没有完成的情况下。