我试图了解sphinx-quickstart
自动生成的Makefile。这是:
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = myproj
SOURCEDIR = source
BUILDDIR = build
.PHONY: help Makefile
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
令我困惑的是:
.PHONY: help Makefile
%: Makefile
%
目标意味着捕获任何内容(通配符)。例如,如果我输入make html
,则%
会抓取html
。.PHONY Makefile
表示make
不应在其目录中查找名为Makefile
的文件,因此,不应检查文件的修改时间确定是否运行规则。为什么Makefile
被列为目标%
的先决条件。我解释这个的方式是:
%
捕获的目标规则应在Makefile
更改时运行。
但这在上下文中没有任何意义。我期望的是:
%
捕获的目标规则应在项目文档的源文件或API源文件发生更改时运行。
.
├── build
├── Makefile
├── source
└── utils
答案 0 :(得分:2)
.PHONY: foo
的效果是foo
永远不会被认为是最新的。 (但请参阅https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html以获取更详细的解释:主要用途是针对非文件名的目标)
如果您有bar: foo
,则bar
目标的规则将始终在make bar
上执行,因为目标取决于foo
,但foo
被视为bar
永远不会是最新的。这也可以通过将%
目标声明为PHONY本身来实现。
catch-all html
目标的问题在于Makefile所在的库存包含一个库或与Sphinx构建器同名的文件。比如说Makefile所在的库中有man
或make html
:如果%
没有依赖关系,则html
将不会执行任何操作,因为{{1}然后是一个没有依赖关系的文件或库,因此永远不会得到更新。
因此%
依赖于Makefile伪目标,Makefile本身声明为PHONY,因此它被认为永远不会是最新的。(*)即使汇编包含文件html
然后make html
将被执行(并且修改了构建目录中的html
库;不会修改Makefile库中的html
。
(*)编辑:我忘记了确切的细节:Makefile始终被视为目标,请参阅a surprising (?) behaviour of GNU Make when using ``%`` as target。由于这里解释的原因,%
依赖于Makefile,并且Makefile实际上被宣布为PHONY,以避免抱怨循环依赖......
这个想法是Makefile不应该包含所有可能的构建器的硬编码列表:否则它们可能已被单独声明为PHONY目标,但是然后Sphinx维护者将不得不担心Makefile模板保持最新添加新构建器时。当项目保持相同的Makefile但是新的Sphinx版本添加了新的构建器时,它也会导致问题。
如果将新的构建器添加到Sphinx,则不必修改sphinx-quickstart现在创建的Makefile。当然可以肯定,Makefile
永远不会成为建造者的名字......