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

为何Makefile中被两个目标依赖的write目标仅执行一次?

Why does my Makefile dependency target run only once, and how to calculate target execution time properly?

I have this Makefile:

write:
	@echo `date`
file_1: write file_2
	@echo "file_1 begin"
	$(shell sleep 3)
	@echo "file_1 end"
file_3: write file_4
	@echo "file_3 begin"
	$(shell sleep 3)
	@echo "file_3 end"
all: file_1 file_3
.PHONY: write

When I run make, the output is:

Sat Oct 9 15:22:45 CST 2021
file_1 begin
file_3 begin
file_1 end
file_3 end

I noticed that the write target only runs once, even though it's a dependency for both file_1 and file_3. My goal is to use the write target to log start times so I can calculate the execution time of file_1 and file_3, but this behavior breaks that plan.

Why does this happen? And is there a better way to calculate the execution time of Makefile targets?


Great question! Let's break this down step by step.

Why write only runs once

This is core Make behavior: every target (including .PHONY ones) is executed exactly once per make session, no matter how many other targets list it as a dependency.

The .PHONY marker just tells Make that write isn't associated with a physical file, so it should always run the target's commands instead of checking if a file is up-to-date. But it doesn't override Make's fundamental rule of avoiding redundant work. When Make processes file_1, it runs write; when it later gets to file_3's dependencies, it sees write has already been executed in this session, so it skips running it again.

Better ways to calculate target execution time

If you want to track the start/end time (and elapsed duration) for each individual target, here are a few clean approaches:

1. Inline time tracking per target

Add start/end time capture directly in each target's command sequence. This is straightforward and easy to read:

file_1: file_2
	@start_time=$$(date +%s); \
	echo "file_1 begin at $$(date)"; \
	sleep 3; \
	end_time=$$(date +%s); \
	echo "file_1 end at $$(date), elapsed time: $$((end_time - start_time)) seconds"

file_3: file_4
	@start_time=$$(date +%s); \
	echo "file_3 begin at $$(date)"; \
	sleep 3; \
	end_time=$$(date +%s); \
	echo "file_3 end at $$(date), elapsed time: $$((end_time - start_time)) seconds"

all: file_1 file_3

2. Use the time command

If you just need a quick duration without custom logging, use the shell's built-in time command. Wrap your target's commands in parentheses to time the entire sequence:

file_1: file_2
	@echo "file_1 begin"
	@time (sleep 3)
	@echo "file_1 end"

file_3: file_4
	@echo "file_3 begin"
	@time (sleep 3)
	@echo "file_3 end"

all: file_1 file_3

This will output standard time stats (real, user, sys) after the target finishes.

3. Reusable Make function for consistency

If you have many targets to track, define a reusable function to avoid repetition:

# Define a function that takes target name and command as arguments
define timed_target
	@start_time=$$(date +%s); \
	echo "$(1) started at $$(date)"; \
	$(2); \
	end_time=$$(date +%s); \
	echo "$(1) finished at $$(date) | Elapsed: $$((end_time - start_time)) seconds"
endef

file_1: file_2
	$(call timed_target,file_1,sleep 3)

file_3: file_4
	$(call timed_target,file_3,sleep 3)

all: file_1 file_3

4. Per-target start logging (if you still want per-target timestamps)

If you specifically want a "start time" log entry for each target (like your original write idea), don't use a shared dependency. Instead, call a logging snippet directly in each target:

# Helper to log start time for a target
define log_start
	@echo "$$(date) - $(1) starting"
endef

file_1: file_2
	$(call log_start,file_1)
	@sleep 3
	@echo "file_1 end"

file_3: file_4
	$(call log_start,file_3)
	@sleep 3
	@echo "file_3 end"

all: file_1 file_3

This way, each target gets its own start timestamp, which you can pair with an end timestamp to calculate duration.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 17:42:34