Support for rules not changing their output

163 views
Skip to first unread message

Johannes Lerch

unread,
Mar 10, 2021, 2:16:29 AM3/10/21
to ninja-build
Hello, 

does Ninja somehow support rules that may not always change their output? Our use case for this is that we do have code generators that must be run if their inputs change, but they are able to detect whether the change in the input will actually result in a change of the output. For example, you may change some comments in the input file, which doesn't result in changes of the output, i.e., they do not write the output files again. That in theory allows to stop the build right there as further steps depending on the outputs do not need to be rebuild.

I tried setting up a minimal ninja example that shows the problem I have right now - and why I assume Ninja doesn't support this use case, unfortunately.

rule foo
   command = cmd /c if not exist $out echo foo > $out

build second: foo first
build third: foo second

default third

Now create file 'first' and call ninja:
-> output second doesn't exist; both build statements executed.

Run ninja again:
-> No work to do

Change input file 'first' and call ninja:
-> output second older than most recent input first; second is dirty. Both build statements executed.

Without changes, run ninja again:
-> output second older than most recent input first; second is dirty. Both build statements executed.

Always writing the output file doesn't help here either, as even with unchanged content Ninja will assume the file to be changed and executes the second build statement.

Is there anything that I have missed? How do you deal with such use cases in your build setup?

Regards,
Johannes

Brett Wilson

unread,
Mar 10, 2021, 11:42:27 AM3/10/21
to Johannes Lerch, ninja-build
Ninja has exactly what you want. You need to put

  restat = 1

under your build rule.

It will check the timestamp after your rule has run and I think will do exactly what you're asking for.

Brett


--
You received this message because you are subscribed to the Google Groups "ninja-build" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ninja-build...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ninja-build/f11981e3-495b-4dbb-a417-1d7cc027a6b1n%40googlegroups.com.

Johannes Lerch

unread,
Mar 10, 2021, 12:49:40 PM3/10/21
to ninja-build
Hello again,

I just stumbled across the "restat" property, which seems to solve exactly that problem. For anyone interested, here is a modified version of the example:

rule foo
   command = cmd /c FC $in $out || copy /Y $in $out
   restat = 1

build second: foo first
build third: foo second

default third

This basically copies file "first" to "second" and then "second" to "third" if file content is not equal. If content of files is equal, it doesn't do anything, i.e., it also does not write the ouput file thus not changing the timestamp in the filesystem.
However, restat makes Ninja update its internal timestamp of each file, which seems to do the trick.
Moreover, if updating the timestamp of file "first" without changing its content Ninja will trigger the first build statement, but as file "second" won't be updated it doesn't execute the second build statement. On the next invocation of ninja, it sucessfully states "no work to do".

Regards,
Johannes
Reply all
Reply to author
Forward
0 new messages