How Gradle Works: StartupFebruary 09, 2023
This is the first article of a series How Gradle Works, which includes the following topics:
- How Gradle starts up
- How many JVMs are involved in a Gradle build
- What happens in each JVM during the build
We'll explain the first topic How Gradle Starts Up in this blog.
Before reading on, we assume you are familiar with basic JVM/Gradle concepts (jar, classpath, wrapper, daemon, project, task, etc.).
How Gradle Starts Up
There are many ways to start a Gradle build:
- Local Gradle Distribution in CLI:
- Gradle Wrapper in CLI:
- Click a button in your IDE to import a Gradle project or run some tests/tasks
What's the difference? What happens under the hood?
Before we start, we need to remember that Gradle is software running on top of a JVM (Java Virtual Machine).
Local Gradle Distribution in CLI
You may have downloaded a Gradle distribution to your local computer, either manually or by some package management tools.
Suppose you start a Gradle build by typing
What happens next?
/path/to/local/distribution/bin/gradle in your favorite text editor, you'll find that it's nothing magic but a plain text file, or more precisely, a shell script file. When you say
/path/to/local/distribution/bin/gradle ,a shell process is started and starts executing the code in the script. At the end of this script, you can see a line:
exec "$JAVACMD" "$@"
So the script's job is simple: it finds the
java command, determines the parameters, and starts a JVM by invoking
exec executes a command in the same process, i.e. replaces the current process with a JVM process.
The entry point of
Gradle Client JVM is
The JVM started by
exec is a very lightweight JVM. Let's call it
Gradle Client JVM because it doesn't run any real build logic.
It searches for a compatible Gradle Daemon and connects to it via a local socket if found.
If there is no such daemon running, it will start a daemon, which is also a JVM (
Gradle Daemon JVM).
Gradle Client JVMforwards input (command line arguments, environment variables, stdin, etc.) to the
Gradle Daemon JVM.
Gradle Daemon JVMruns the build, and sends output (stdout/stderr) back to the
Gradle Client JVM.
- After the build finishes, the
Gradle Client JVMwill exit, but the
Gradle Daemon JVMmay stay running for some time.
However, there is one exception for this workflow. If you pass
--no-daemon to the Gradle build, the client JVM may convert itself into a daemon JVM if it is compatible with build requirements.
In this case, there is no daemon, no communication, no input/output forwarding at all - the build happens inside the single JVM:
--no-daemon is present and the client JVM is not compatible with build requirements, a new disposable JVM will still be started for the build and exit at the end of the build:
This is how local Gradle distribution starts up on UNIX OSes. On Windows, the mechanism is very similar - the only difference is that we invoke
/path/to/distribution/bin/gradle.bat instead of
Gradle Wrapper in CLI
As you may know, Gradle Wrapper is the recommended way to execute Gradle builds.
What happens when you type
./gradlew ? What's the difference with running from local Gradle distribution?
If you open
gradlew in a text editor, you'll find it very similar to what we have explained in the last section: there is no magic, just a shell script. It starts a tiny JVM from
gradle/wrapper/gradle-wrapper.jar in your project.
This JVM will locate or download a specific version of Gradle distribution declared in
gradle/wrapper/gradle-wrapper.properties, then it will start Gradle inside the same JVM via Java reflection. After that, this tiny JVM acts as the
Gradle Client JVM in the way explained in the last section.
The entry point of
Gradle Wrapper JVM is the
Gradle in IDE
In the previous sections,
Gradle Client JVM is a dedicated JVM started via CLI.
Actually, it doesn't have to be a dedicated JVM.
Gradle client can be a part of another JVM, i.e. a JVM that loads some Gradle jars dynamically and acts as a "Gradle client": searches/connects to the daemon, starts a new daemon, and communicates with the daemon.
This programmatic API is called Tooling API.
For example, when you click
Gradle Sync button in IntelliJ IDEA, IDEA will start a special Gradle build to fetch necessary information (project structure, dependencies, tasks, etc.) of the project via the Tooling API.
Still, all the build logic happens in a
Gradle Daemon JVM, and the Tooling API just reads a build result and returns it to the caller.
In the next blog post of the series we'll explain how many JVMs are involved in a Gradle build.