In recent years many new build systems have emerged to replace traditional make. Although they all have different strengths and weaknesses, one common theme is improving execution performance of the build system.
Traditional multiprocessor make systems are generally efficient at scheduling tasks within a given Makefile. Given a dependency graph, child processes can be executed when their dependencies are satisfied and processor cores are available.
Unfortunately, this breaks down where multiple Makefiles are used across different directories or modules. The choice that a build system maintainer faces becomes:
Using per-directory Makefiles allows developers to compile individual directories in isolation, but doing so means a full build needs to drain out child processes at various points in the build, because the engine cannot recognize dependencies natively;
Using fewer Makefiles means more efficient full builds but more difficult isolated compilation, as the developer would need to change directories and specify the correct target to build.
However, there’s no reason that this choice is inevitable. If the full build can construct a single global dependency graph, but each directory still contains a partial dependency graph, a directory build can operate as well as traditional make and a full build can operate as efficiently as a newer build system. YMAKE attempted to build such a system, and do so without requiring any changes to per-directory Makefiles.
Specifying the global graph requires a new syntax to logically graft a child directory into the dependency graph. The remainder of Makefile syntax does not need to change, and conditionals can be used to fall back to recursive navigation if a global dependency graph is not supported. This means that the build system does not require developers to install new build tools to compile, so it still benefits from the ubiquity of make, but having YMAKE just makes the existing build system faster.