Disclaimer: I am not a tup user but nevertheless very interested in tup because I am part of a small team that is busy implementing a build system that is heavily inspired by Mike’s paper Build system rules and algorithms and by tup itself.
I do not understand why cyclic directory dependencies are different from cyclic file dependencies. How does tup behave when an output file is both read and written by a command? Does it ignore the read dependency? Or does it raise an error? Or does it always re-execute the command at next build?
For me the main concern with detecting directory dependencies is that this may result in unnecessary re-execution of commands.
E.g. the C/C++ compiler will lookup an include file in the directories specified by the -I flags or listed in the INCLUDE path environment variable. It can do so by using stat but it can also do so by (ab)using readdir.
In the stat case a file dependency is detected (also in case the file does not exist). This file dependency only causes recompilation when the file is created/modified/deleted. Exactly what we want. In the readdir case a directory dependency is detected. Any change to the directory will cause, mostly unnecessary, recompilation.
What we really need is a glob dependency. A glob obviously depends on a directory. Changes in the directory will cause the glob to re-execute. Re-execution of a command that depends on the glob however is only necessary when the glob result changes.
But how to detect which glob a program is executing? I am afraid that this is not possible. Remains the solution provided by tup: perform globs in the input section of a rule.