You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用%通配符的Make目标无法正常执行,提示‘Nothing to be done’

这个问题我遇见过,核心问题出在两个地方:没有把FORCE标记为伪目标(.PHONY),以及当前的依赖规则不够精确。

1. FORCE目标未被声明为.PHONY

你写的FORCE: ;只是创建了一个带空命令的目标,但GNU Make默认会把它当作实际的文件目标处理。如果当前目录里没有名为FORCE的文件,Make第一次运行时会执行这个空命令,然后标记FORCE为“已完成”;后续运行时,Make会认为FORCE目标已经是最新的,不会触发依赖它的bin/%目标重新构建。

解决方法很简单:把FORCE声明为.PHONY目标,告诉Make这个目标不是实际文件,而是一个总是需要被“重新构建”的标记:

.PHONY: FORCE build

2. 依赖规则依赖目录而非源码文件

你的规则bin/%: cmd/% FORCE依赖的是cmd/%目录,但Unix系统中,目录的修改时间(mtime)只会在目录内的文件被添加、删除时更新,修改文件内容不会改变目录的mtime。这意味着如果你修改了cmd/my-app/main.go的内容,Make会认为cmd/my-app目录的时间没有变化,即使有FORCE也可能出现预期外的行为(当然加上.PHONY FORCE后会强制构建,但依赖具体文件更合理)。

建议把依赖改成具体的源码文件cmd/%/main.go,这样只要源码文件修改,Make就会自动触发构建:

bin/%: cmd/%/main.go FORCE
	$(BUILD_BINARY)

对应的,BUILD_BINARY宏里的./$<需要调整,因为现在$<指向的是main.go文件而非目录,你可以用$*匹配目标中的%部分(也就是应用名称),写法更清晰:

define BUILD_BINARY
	@echo go build $(GO_BUILD_FLAGS) -o $@ ./cmd/$*
	go build $(GO_BUILD_FLAGS) -o $@ ./cmd/$*
endef

修正后的完整Makefile

GO_BUILD_FLAGS = 
APPS = my-app another-app stuff
define BUILD_BINARY
	@echo go build $(GO_BUILD_FLAGS) -o $@ ./cmd/$*
	go build $(GO_BUILD_FLAGS) -o $@ ./cmd/$*
endef

.PHONY: FORCE build

bin/%: cmd/%/main.go FORCE
	$(BUILD_BINARY)

build: $(addprefix bin/,$(APPS))

现在运行make build或者make bin/my-app,就能正常触发编译了。如果想要强制重新构建(哪怕源码没改),这个配置也能满足需求;如果不需要强制,只在源码变化时构建,可以去掉FORCE依赖和.PHONY: FORCE

内容的提问来源于stack exchange,提问作者Marco

火山引擎 最新活动