implement "make"-like chained cache objects

a cache object can:

- hold a simple datum (e.g. string, number)
- auto-load from a file
- be built from a list of dependencies (other cache objects)
and a "recipe", like a target item in a Makefile

Invalidating a cache object invalidates its ascendants recursively,
forcing a refresh and re-cache at next fetch. Each cache object has
its own mutex to assure synchronization.