

Anything from djb can be expected to be good 👍
The simplest tool I had come across was memoize.py (and others like it). Given a build script, it uses strace
on a from-scratch build to figure out dependencies. On future builds, it rebuilds only what has changed. It naturally captures edge cases like, rebuilding everything if the compiler changes! But also the typical case, of include files etc.
That is what Delta Chat and Monocles do on different protocols, with WebXDC. https://webxdc.org/