Recently I have been thinking about how can be Gradle more performant when doing partial builds. By partial builds, I mean only building a single project (and its dependencies) of a multi-project build. As is currently, Gradle eagerly executes each project’s script before attempting to run a task. Although it is a more safe approach (since any Gradle project might adjust the configuration of any other project), I believe that assuming that an unrelated project might adjust another project does not add more power to build scripts but hinders optimzations (especially in case of partial builds). That is, it should be sufficient for a build script to rely on itself; and no build script may assume that some other script configures it (code can still be separated in multiple files using “apply from”).
A more performant approach
The following proposal is likely to break lots of builds out there, so if implemented, must be opt-in.
To my understanding, as of currently, Gradle works in two phases: configure, run tasks. This clear separation is not necessary. Here is how I believe, Gradle could work (after reading settings.gradle):
-
Execute the build script of the currently selected project (the one whose directory is the current working directory).
-
Execute the build script of the child projects of the selected project recursively.
-
Start executing the requested tasks.
In the above code, whenever an ‘org.gradle.api.Project’ instance is retrieved (e.g.: ‘project(":parent-project:sub-project")’), Gradle should ensure that before the Project instance is returned to the caller, the script of the project to be returned is executed (except when prevention of infinite loop in the initialization is required). That is, in a very similar manner as the static initializers in Java are executed.
Benefits
Currently, I often find myself not adding a project to a multi-project build because the project is rarely needed and adding projects considerably slows down unrelated builds. The proposed changes would make Gradle scale better with projects containing lots of subprojects; even in the case of partial builds. The cost of adding a project to a multi-project build would be negligible.
With IDEs it would be possible not to load each project if you are not interested in each of them at the moment.