You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何强制make工具始终执行指定目标?

如何强制make工具始终执行指定目标?

在Makefile里,默认情况下make会检查目标文件和依赖文件的时间戳,只有当依赖更新时才会重新构建目标。但如果我们需要某个目标每次执行make都必须运行(比如动态生成的封面、clean清理操作这类),有两种常用的可靠方法,我结合你提供的Asciidoc转PDF的Makefile场景来详细说:

方法一:使用.PHONY伪目标标记

这是最标准、推荐的做法。.PHONY的作用就是告诉make:“这个目标不是一个实际的文件,别去检查它的时间戳,直接执行对应的规则”。

比如你提供的Makefile里,已经把需要强制执行的目标都加入了.PHONY列表:

.PHONY: all html pdf clean $(COVER)

这里的$(COVER)就是你需要每次构建都重新生成的SVG封面——毕竟你要注入最新的版本号(从git HEAD获取)、年份,还要根据标题长度调整元素,不可能依赖旧的封面文件。

对应的封面生成规则(补充完整后)大概是这样:

$(COVER): $(COVER_TEMPLATE)
    # 替换模板里的占位符,生成新封面
    sed -e 's/{{REV}}/$(REV)/g' \
        -e 's/{{YEAR}}/$(shell date +%Y)/g' \
        -e 's/{{APPNAME}}/$(APPNAME)/g' \
        $(COVER_TEMPLATE) > $(COVER)

因为$(COVER)被标记为.PHONY,不管当前目录下有没有cover.svg,也不管它比模板新还是旧,make每次都会执行上面的sed命令,确保封面内容是最新的。

另外像clean、all这类不需要生成文件的操作,也必须标记为.PHONY——不然如果刚好有个叫clean的文件,make就会误以为目标已经完成,不会执行清理命令了。

方法二:依赖一个“永远更新”的FORCE目标

如果你不想用.PHONY,也可以定义一个空的FORCE目标,让需要强制执行的目标依赖它:

FORCE:

$(COVER): $(COVER_TEMPLATE) FORCE
    # 生成封面的命令

因为FORCE没有任何依赖和规则,make会认为它“永远需要更新”,所以依赖它的$(COVER)也会每次都重新构建。不过这种方法不如.PHONY直观,而且如果不小心创建了一个叫FORCE的文件,就会失效,所以还是推荐用.PHONY。

完整的示例Makefile(补充clean规则)

SHELL := /bin/bash

.DEFAULT_GOAL := all

# document revision
REV := "0.1.$(or $(shell git rev-parse HEAD), 0)"

# source directory
SRCDIR := ${CURDIR}/src

# theme directory
THEMEDIR := ../theme

# images directory
IMGDIR := images

# source files
ADOC_FILES := $(wildcard $(SRCDIR)/*.adoc)

# document cover
COVER_TEMPLATE := $(SRCDIR)/$(IMGDIR)/cover-template.svg
COVER := $(SRCDIR)/$(IMGDIR)/cover.svg

# output directories
OUTDIR := ${CURDIR}/build
HTML_OUTDIR := $(OUTDIR)/html
PDF_OUTDIR := $(OUTDIR)/pdf

# output files
BASENAME := $(shell basename `pwd`)-$(REV)
HTML_FILE := $(HTML_OUTDIR)/$(BASENAME).html
PDF_FILE := $(PDF_OUTDIR)/$(BASENAME).pdf

# custom attributes
APPNAME=MyApp

.PHONY: all html pdf clean $(COVER)

all: html pdf

html: $(HTML_FILE)

pdf: $(PDF_FILE)

clean:
    rm -rf $(OUTDIR)
    rm -f $(COVER)

$(COVER): $(COVER_TEMPLATE)
    # 注入版本、年份等信息到SVG封面模板
    sed -e 's/{{REV}}/$(REV)/g' \
        -e 's/{{YEAR}}/$(shell date +%Y)/g' \
        -e 's/{{APPNAME}}/$(APPNAME)/g' \
        $(COVER_TEMPLATE) > $(COVER)

总结一下:

  • 对于不需要生成文件的操作(如clean、all),直接加入.PHONY
  • 对于需要生成文件但必须每次重建的目标(如动态封面),把该文件目标加入.PHONY列表
  • .PHONY是官方推荐的方式,避免了文件冲突的风险

备注:内容来源于stack exchange,提问作者j3d

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 12:59:31