Re: [PATCH] make: add valid-for and valid-max target TTL support

Britton Kerin <[email protected]> Tue, 17 Feb 2026 08:17:10 -0800
Newsgroups gmane.comp.gnu.make.bugs
Message-ID <CAC4O8c_ww=Mn2jwEtKzQvPjrWSTchbT=A_R7WC_d4-PqDRW2jw@mail.gmail.com>
--0000000000000d845f064b0768fd
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Mon, Feb 16, 2026, 1:46=E2=80=AFPM Yair Lenga <[email protected]> wro=
te:

> Hello,
>
> This patch introduces two optional target-specific variables,
> 'valid-for' and 'valid-max', that allow controlling the freshness
> and expiration of existing targets based on their modification time.
>
> Motivation
> ----------
>
> GNU make treats an existing target with no prerequisites as
> permanently up to date.  In practice, many build workflows generate
> cache or artifact files that should be reused while fresh but
> periodically regenerated even without explicit dependencies.  Today
> this:  requires introducing artificial phony prerequisites or external
> timestamp logic.
>
> The new variables provide a declarative mechanism for this:
>
>   valid-for =3D DURATION
>       If the target exists and its age is less than or equal to the
>       specified duration, make treats it as up to date and skips
>       dependency checking.
>
>   valid-max =3D DURATION
>       If the target exists and its age exceeds the specified duration,
>       make forces a rebuild even if the target has no prerequisites.
>
> Durations are specified as either an integer number of seconds or a
> sequence of <number><unit> segments without spaces, where unit is one
> of 's', 'm', 'h', 'd', or 'w' (e.g. "300", "5m", "1d5h").
>
> When both variables are present, 'valid-for' takes precedence for
> fresh targets, while 'valid-max' forces rebuild of expired targets.
>

I'm not sure I entirely understand this and think it could probably be
better expressed for documentation at least.  By fresh I assume you mean
otherwise up-to-date?


> Implementation
> --------------
>
> The logic is implemented in update_file_1() via a small helper that
> parses and evaluates the TTL variables.  Invalid values are ignored
> and reported under --debug=3Dv.  Successful use of the TTL is reported
> under --debug=3Db.
>
> This approach preserves existing make semantics while enabling
> expiration of leaf targets and optional dependency skipping for
> recent artifacts.
>

Is it usable only for leaves?  I guess these variables are not inherited by
dependent targets (as other target-local variables are) since that would
presumably add a bunch of undesired edges to the DAG?


> -------
> Example 1: Periodic reloading of remote resources that change very
> frequently.
>
>   cache.json: private valid-max=3D1d
>   cache.json:
>           curl -o $@ https://example/api
>
> The file will be regenerated once per day even without prerequisites.This
> can be useful when a test job is running every few minutes, but loading o=
f
> remote resources is time consuming.
>
> Other use cases include periodically refreshing generated version
> stamps, expiring downloaded resources in reproducible builds, and
> limiting reuse of expensive intermediate artifacts in CI or code
> generation workflows.
>
> ---
>
> Patch attached. Comments welcome.
>
> Best regards,
> Yair Lenga
>

--0000000000000d845f064b0768fd
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto"><div><br><br><div class=3D"gmail_quote gmail_quote_contai=
ner"><div dir=3D"ltr" class=3D"gmail_attr">On Mon, Feb 16, 2026, 1:46=E2=80=
=AFPM Yair Lenga &lt;<a href=3D"mailto:[email protected]">yair.lenga@gma=
il.com</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"m=
argin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"l=
tr">Hello,<br><br>This patch introduces two optional target-specific variab=
les,<br>&#39;valid-for&#39; and &#39;valid-max&#39;, that allow controlling=
 the freshness<br>and expiration of existing targets based on their modific=
ation time.<br><br>Motivation<br>----------<br><br>GNU make treats an exist=
ing target with no prerequisites as<br>permanently up to date.=C2=A0 In pra=
ctice, many build workflows generate<br>cache or artifact files that should=
 be reused while fresh but<br>periodically regenerated even without explici=
t dependencies.=C2=A0 Today<br>this:=C2=A0 requires introducing artificial =
phony prerequisites or external<br>timestamp logic.<br><br>The new variable=
s provide a declarative mechanism for this:<br><br>=C2=A0 valid-for =3D DUR=
ATION<br>=C2=A0 =C2=A0 =C2=A0 If the target exists and its age is less than=
 or equal to the<br>=C2=A0 =C2=A0 =C2=A0 specified duration, make treats it=
 as up to date and skips<br>=C2=A0 =C2=A0 =C2=A0 dependency checking.<br><b=
r>=C2=A0 valid-max =3D DURATION<br>=C2=A0 =C2=A0 =C2=A0 If the target exist=
s and its age exceeds the specified duration,<br>=C2=A0 =C2=A0 =C2=A0 make =
forces a rebuild even if the target has no prerequisites.<br><br>Durations =
are specified as either an integer number of seconds or a<br>sequence of &l=
t;number&gt;&lt;unit&gt; segments without spaces, where unit is one<br>of &=
#39;s&#39;, &#39;m&#39;, &#39;h&#39;, &#39;d&#39;, or &#39;w&#39; (e.g. &qu=
ot;300&quot;, &quot;5m&quot;, &quot;1d5h&quot;).<br><br>When both variables=
 are present, &#39;valid-for&#39; takes precedence for<br>fresh targets, wh=
ile &#39;valid-max&#39; forces rebuild of expired targets.<br></div></block=
quote></div></div><div dir=3D"auto"><br></div><div dir=3D"auto">I&#39;m not=
 sure I entirely understand this and think it could probably be better expr=
essed for documentation at least.=C2=A0 By fresh I assume you mean otherwis=
e up-to-date?</div><div dir=3D"auto"><br></div><div dir=3D"auto"><div class=
=3D"gmail_quote gmail_quote_container"><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div =
dir=3D"ltr"><br>Implementation<br>--------------<br><br>The logic is implem=
ented in update_file_1() via a small helper that<br>parses and evaluates th=
e TTL variables.=C2=A0 Invalid values are ignored<br>and reported under --d=
ebug=3Dv.=C2=A0 Successful use of the TTL is reported<br>under --debug=3Db.=
<br><br>This approach preserves existing make semantics while enabling<br>e=
xpiration of leaf targets and optional dependency skipping for<br>recent ar=
tifacts.<br></div></blockquote></div></div><div dir=3D"auto"><br></div><div=
 dir=3D"auto">Is it usable only for leaves?=C2=A0 I guess these variables a=
re not inherited by dependent targets (as other target-local variables are)=
 since that would presumably add a bunch of undesired edges to the DAG?</di=
v><div dir=3D"auto"><br></div><div dir=3D"auto"><div class=3D"gmail_quote g=
mail_quote_container"><blockquote class=3D"gmail_quote" style=3D"margin:0 0=
 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><br>-=
------<br>Example 1: Periodic reloading of remote resources that change ver=
y frequently.<br><br>=C2=A0 cache.json: private valid-max=3D1d<br>=C2=A0 ca=
che.json:<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 curl -o $@ <a href=3D"https=
://example/api" target=3D"_blank" rel=3D"noreferrer">https://example/api</a=
><br><br>The file will be regenerated once per day even without prerequisit=
es.This can be useful when a test job is running every few minutes, but loa=
ding of remote resources is time consuming.<div><br></div><div>Other use ca=
ses include periodically refreshing generated version<br>stamps, expiring d=
ownloaded resources in reproducible builds, and<br>limiting reuse of expens=
ive intermediate artifacts in CI or code<br>generation workflows.</div><div=
><br></div><div>---</div><div><br></div><div>Patch attached. Comments welco=
me.</div><div><br></div><div>Best regards,</div><div>Yair Lenga</div></div>
</blockquote></div></div></div>

--0000000000000d845f064b0768fd--