Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

10. Gradle's own source code compilation process

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/02 Report--

Summarize Gradle's own source code compilation process in one sentence-compile Gradle with gradle

Let's officially start the analysis:

Because after we get the source code, the first thing we come into contact with is gradlew.bat, that is, the command compiled by the Gradle source code itself. So, let's start with this script.

one。 Eclipse opens the source code

In order to make it easier to modify the code, I chose to open the project with Eclipse. The steps are:

File- > New- > Java Project- > Use default location uncheck-> Browse Select Gradle source code directory-> finish

two。 Gradlew.bat script

1. Or start with our command to compile the Gradle source code

Gradlew.bat assemble

First, let's take a look at gradlw.bat:

@ if "% DEBUG%" = "" @ echo off@rem # @ rem@rem Gradle startup script for Windows@rem@rem # # @ rem Set local scope for the variables with windows NT shellif "% OS%" = = "Windows_NT" setlocalset DIRNAME=%~dp0if "% DIRNAME%" = "" set DIRNAME=.set APP_BASE_NAME=%~n0set APP_HOME=%DIRNAME%@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.set DEFAULT_JVM_OPTS=-Xmx1024m-Dfile.encoding=UTF-8@rem Find java.exeif defined JAVA_HOME goto findJavaFromJavaHomeset JAVA_EXE=java.exe%JAVA_EXE%-version > NUL 2 > & 1if "% ERRORLEVEL%" = = "0" goto initecho.echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.echo.echo Please set the JAVA_HOME variable in your environment to match theecho location of your Java installation.goto fail : findJavaFromJavaHomeset JAVA_HOME=%JAVA_HOME: "=% set JAVA_EXE=%JAVA_HOME%/bin/java.exeif exist"% JAVA_EXE% "goto initecho.echo ERROR: JAVA_HOME is set to an invalid directory:% JAVA_HOME%echo.echo Please set the JAVA_HOME variable in your environment to match theecho location of your Java installation.goto fail:init@rem Get command-line arguments Handling Windows variantsif not "% OS%" = = "Windows_NT" goto win9xME_args:win9xME_args@rem Slurp the command line arguments.set CMD_LINE_ARGS=set _ SKIP=2:win9xME_args_slurpif "x% gradle-wrapper.jar@rem Execute Gradle 1" = "x" goto executeset CMD_LINE_ARGS=%*:execute@rem Setup the command lineset CLASSPATH=%APP_HOME%\ gradle\ wrapper\ gradle-wrapper.jar@rem Execute Gradle "% JAVA_EXE%"% DEFAULT_JVM_OPTS%% JAVA_OPTS%% GRADLE_OPTS% " -Dorg.gradle.appname=%APP_BASE_NAME% "- classpath"% CLASSPATH% "org.gradle.wrapper.GradleWrapperMain% CMD_LINE_ARGS%:end@rem End local scope for the variables with windows NT shellif"% ERRORLEVEL% "= =" 0 "goto mainEnd:failrem Set variable GRADLE_EXIT_CONSOLE if you need the _ script_ return code instead ofrem the _ cmd.exe / c _ return codes if not" = "% GRADLE_EXIT_CONSOLE%" exit 1exit / b 1:mainEndif "% OS%" = = "Windows_NT" endlocal:omega

When you execute gradlew.bat assemble, first look at the values of each variable in the script:

CLASSPATH:gradle-3.1\\ gradle\ wrapper\ gradle-wrapper.jar

It represents the gradle-wrapper.jar in the gralde\ wrapper\ directory of the gradle source code, and this jar is also the jar to be run by the compilation operation to be performed later.

DEFAULT_JVM_OPTS:-Xmx1024m-Dfile.encoding=UTF-8 represents the Java virtual machine configuration

JAVA_OPTS: empty

GRADLE_OPTS: empty

CMD_LINE_ARGS:assemble indicates the name of the gradle task to be executed

Then, an important sentence is executed to start the GradleWrapperMain.main function in gradle-wrapper.jar.

Rem Execute Gradle "% JAVA_EXE%"% DEFAULT_JVM_OPTS%% JAVA_OPTS%% GRADLE_OPTS% "- Dorg.gradle.appname=%APP_BASE_NAME%"-classpath "% CLASSPATH%" org.gradle.wrapper.GradleWrapperMain% CMD_LINE_ARGS%

Then there may be a question here, that is, at this time, the Gradle source code has not been compiled, where is the gradle-wrapper.jar? This problem is like the question of chicken and egg, chicken or egg first.

Gradle's practice is to have the chicken before the egg, so where did the first chicken come from? Gradle built a chicken for it himself.

Please see gradle\ wrapper\ gradle-wrapper.jar

So here is a small detail to remind you. After you have modified the GradleWrapperMain class, such as printing a log, if you want to verify its results, you need to perform a few steps first.

Gradlew.bat assemble

Compile and overwrite the compiled gradle-wrapper.jar to the gradle\ wrapper\ directory.

Execute another gradlew.bat assemble and you can verify it on the command line.

three。 GradleWrapperMain

File path:

Gradle-3.1\ subprojects\ wrapper\ src\ main\ java\ org\ gradle\ wrapper\ GradleWrapperMain.java

GradleWrapperMain location subprojects, the Gradle source code splits each project into modules, similar to the way plug-ins do.

In other words, each function is split into a plug-in, and then configured when it is used, such as which plug-ins a plug-in needs to rely on, then just configure it.

The configuration path is in each plug-in's jar package, called xxx-classpath.properties, with a projects attribute that configures the plug-in on which the plug-in depends (which can also be called a project or module).

This design idea can make the whole project level clear and facilitate cooperative development among multiple teams at the same time.

Take a look at GradleWrapperMain's main function:

Public class GradleUserHomeLookup {public static final String DEFAULT_GRADLE_USER_HOME = System.getProperty ("user.home") + "/ .gradle"; public static final String GRADLE_USER_HOME_PROPERTY_KEY = "gradle.user.home"; public static final String GRADLE_USER_HOME_ENV_KEY = "GRADLE_USER_HOME"; public static File gradleUserHome () {String gradleUserHome If ((gradleUserHome = System.getProperty (GRADLE_USER_HOME_PROPERTY_KEY))! = null) {return new File (gradleUserHome);} if ((gradleUserHome = System.getenv (GRADLE_USER_HOME_ENV_KEY))! = null) {return new File (gradleUserHome);} return new File (DEFAULT_GRADLE_USER_HOME) } public static void main (String [] args) throws Exception {File wrapperJar = wrapperJar (); System.out.println ("wrapperJar:" + wrapperJar); File propertiesFile = wrapperProperties (wrapperJar); File rootDir = rootDir (wrapperJar); File gradleUserHome = gradleUserHome (options); System.out.println ("gradleUserHome:" + gradleUserHome + "rootDir:" + rootDir + "options:" + options+ "propertiesFile:" + propertiesFile); addSystemProperties (gradleUserHome, rootDir); Logger logger = logger (options); WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile (propertiesFile) WrapperExecutor.execute (args, new Install (logger, new Download (logger, "gradlew", wrapperVersion ()), new PathAssembler (gradleUserHome)), new BootstrapMainStarter ();}

The printed log is:

WrapperJar: e:\ work_space\ gradle-source-from-csdn\ gradle-3.1\ gradle\ wrapper\ gradle-wrapper.jargradleUserHome: d:\ gradle_jar_cache rootDir: e:\ work_space\ gradle-source-from-csdn\ gradle-3.1 options: options:, extraArguments: 'assemble', removedOptions: propertiesFile: e:\ work_space\ gradle-source-from-csdn\ gradle-3.1\ gradle\ wrapper\ gradle-wrapper.properties

The value of each variable is clearly stated in this log.

The point to note is gradleUserHome, which is the address where Gradle downloads other Jar packages. The default is the user/xxx/.gradle/ directory of disk c.

But this directory is configurable, just configure the GRADLE_USER_HOME environment variable.

This can be seen clearly from the code getUserHome above.

In addition, the last Gradle of the program executes the WrapperExecutor.execute (xxxx) method, which is critical.

four。 WrapperExecutor.execute

1. Execute

Public void execute (String [] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {File gradleHome = install.createDist (config); bootstrapMainStarter.start (args, gradleHome);}

You can see that there is nothing in the execute, but the incoming install.createDist and bootstrapMainStarter.start methods are called, so you need to analyze these two methods.

2. Install.createDist

New Install (logger, new Download (logger, "gradlew", wrapperVersion (), new PathAssembler (gradleUserHome)) public File createDist (final WrapperConfiguration configuration) throws Exception {final URI distributionUrl = configuration.getDistribution (); final String distributionSha256Sum = configuration.getDistributionSha256Sum (); final PathAssembler.LocalDistribution localDistribution = pathAssembler.getDistribution (configuration); final File distDir = localDistribution.getDistributionDir (); final File localZipFile = localDistribution.getZipFile () System.out.println ("distributionUrl:" + distributionUrl + "distributionSha256Sum:" + distributionSha256Sum + "localDistribution:" + localDistribution + "distDir:" + distDir + "localZipFile:" + localZipFile) Return exclusiveFileAccessManager.access (localZipFile, new Callable () {public File call () throws Exception {final File markerFile = new File (localZipFile.getParentFile (), localZipFile.getName () + ".ok"); if (distDir.isDirectory () & & markerFile.isFile ()) {return getAndVerifyDistributionRoot (distDir, distDir.getAbsolutePath ()) } boolean needsDownload =! localZipFile.isFile (); if (needsDownload) {File tmpZipFile = new File (localZipFile.getParentFile (), localZipFile.getName () + ".part"); tmpZipFile.delete (); logger.log ("Downloading" + distributionUrl); download.download (distributionUrl, tmpZipFile) TmpZipFile.renameTo (localZipFile);} List topLevelDirs = listDirs (distDir); for (File dir: topLevelDirs) {logger.log ("Deleting directory" + dir.getAbsolutePath ()); deleteDir (dir) } verifyDownloadChecksum (configuration.getDistribution (). ToString (), localZipFile, distributionSha256Sum); logger.log ("Unzipping" + localZipFile.getAbsolutePath () + "to" + distDir.getAbsolutePath ()); unzip (localZipFile, distDir); File root = getAndVerifyDistributionRoot (distDir, distributionUrl.toString ()); setExecutablePermissions (root); markerFile.createNewFile () Return root;});}

This is the printed log:

DistributionUrl: https://services.gradle.org/distributions/gradle-3.1-rc-1-bin.zip distributionSha256Sum: null localDistribution: org.gradle.wrapper.PathAssembler$LocalDistribution@4a574795 distDir: d:\ gradle_jar_cache\ wrapper\ dists\ gradle-3.1-rc-1-bin\ 3uhcvxvcic1j9jh0j26e3y151 localZipFile: d:\ gradle_jar_cache\ wrapper\ dists\ gradle-3.1-rc-1-bin\ 3uhcvxvcic1j9jh0j26e3y151\ gradle-3.1-rc-1-bin.zip

Here are a few questions:

a. Download the zip package

CreateDist is actually downloading the zip package described by distributionUrl.

In fact, this is still a chicken and egg problem, the Gradle source code is compiled with Gradle, now we only have the source code, how to compile it?

So you have to download the Gradle zip package from the server first.

B. distributionUrl definition location

Gradle source code root directory / gradle/wrapper/gradle-wrapper.properties

That is:

# Mon Sep 12 15:17:35 CEST 2016distributionBase=GRADLE_USER_HOMEdistributionPath=wrapper/distszipStoreBase=GRADLE_USER_HOMEzipStorePath=wrapper/distsdistributionUrl=https\: / / services.gradle.org/distributions/gradle-3.1-rc-1-bin.zip

The configuration file location can be seen in the constructor of WrapperExecutor:

Ublic static WrapperExecutor forProjectDirectory (File projectDir) {return new WrapperExecutor (new File (projectDir, "gradle/wrapper/gradle-wrapper.properties"), new Properties ();}

c. Calculate the storage directory of zip files according to md5

DistDir: d:\ gradle_jar_cache\ wrapper\ dists\ gradle-3.1-rc-1-bin\ 3uhcvxvcic1j9jh0j26e3y151

The distDir directory, that is, the downloaded zip file storage directory, contains a string of strings, which is calculated according to md5 to ensure uniqueness. The code is as follows:

File path:

Subprojects\ wrapper\ src\ main\ java\ org\ gradle\ wrapper\ PathAssembler.java

/ * * This method computes a hash of the provided {@ code string}. *

* The algorithm in use by this method is as follows: * * Compute the MD5 value of {@ code string}. * Truncate leading zeros (i.e., treat the MD5 value as a number). * Convert to base 36 (the characters {@ code 0-9a-z}) * * / private String getHash (String string) {try {MessageDigest messageDigest = MessageDigest.getInstance ("MD5"); byte [] bytes = string.getBytes (); messageDigest.update (bytes); return new BigInteger (1, messageDigest.digest ()) .toString (36);} catch (Exception e) {throw new RuntimeException ("Could not hash input string.", e) }}

d. Timing of execution

The first time the gradlew.bat assemble is executed, it will be downloaded and unzipped.

So the first time you execute a gradlew.bat assemble, you get a log like this:

Downloading xxxx.

Unzipping.

3. BootstrapMainStarter.start

File path:

Subprojects\ wrapper\ src\ main\ java\ org\ gradle\ wrapper\ BootstrapMainStarter.java

Public void start (String [] args, File gradleHome) throws Exception {System.out.println ("BootstrapMainStarter gradleHome:" + gradleHome); if (args! = null) {for (int I = 0; I < args.length; I +) {System.out.println ("args [" + I + "] =" + args [I]) }} File gradleJar = findLauncherJar (gradleHome); URLClassLoader contextClassLoader = new URLClassLoader (new URL [] {gradleJar.toURI () .toURL ()}, ClassLoader.getSystemClassLoader () .getParent ()); Thread.currentThread () .setContextClassLoader (contextClassLoader); Class mainClass = contextClassLoader.loadClass ("org.gradle.launcher.GradleMain") Method mainMethod = mainClass.getMethod ("main", String [] .class); mainMethod.invoke (null, new Object [] {args}); if (contextClassLoader instanceof Closeable) {((Closeable) contextClassLoader) .class () }} private File findLauncherJar (File gradleHome) {for (File file: new File (gradleHome, "lib") .listFiles () {if (file.getName (). Matches ("gradle-launcher-.*\\ .jar")) {return file }} throw new RuntimeException (String.format ("Could not locate the Gradle launcher JAR in Gradle distribution'% slots.", gradleHome));}

Print the log as follows:

BootstrapMainStarter gradleHome: d:\ gradle_jar_cache\ wrapper\ dists\ gradle-3.1-rc-1-bin\ 3uhcvxvcic1j9jh0j26e3y151\ gradle-3.1-rc-1args [0] = assemble

So now let's explain what the above code is doing:

a. Find gradle-launcher-.*\\ .jar from the lib folder of the unzipped directory downloaded from gradle bin.

b. Then execute the org.gradle.launcher.GradleMain.main function in the launcher-xxx.jar package.

c. At the same time, pass in the parameter assemble that we entered.

Then the next thing to execute is the launcher-xxx.jar function in the gradle we downloaded, not in our source code, which should be distinguished clearly.

Execute the code in the downloaded gradle to compile the Gradle source code, just like gradle compiles other programs.

That's why the compilation process of Gradle source code is to use gradle to compile Gradle.

This place is the difference between gradlew.bat and gradle.bat that we talked about earlier.

D. the difference between gradlew.bat and gradle.bat

Gradlew.bat is a bat script at compile time for Gradle source code itself.

The gralde/wrapper/gradle-wrapper.jar package under the current directory is loaded and the GradleWrapperMain.main method is executed.

Then download gradle bin and extract it. Then execute the GradleMain.main function in gradle-launcher-xxx.jar in gradle lib.

Gradle.bat is a bat script that gradle compiles other programs.

What is loaded is the GradleMain.main function in gradle-launcher-xxx.jar in gradle lib.

e. Thoughts on the naming of gradlew.bat

I wonder why the script that compiles Gradle's own source code is called gradlew.bat? It's only one word different from the script gradle.bat that compiles other programs. What does "w" mean?

What gradlew.bat does is compile the Gradle source code itself, so it's called gradle_compile_self.bat straightforward?

Maybe we can understand that "w" is an acronym for wrapper, because that's the difference between the Jar loaded by the two scripts; and what wapper does is really the packaging job. For example, it just downloads gradle bin and then calls gradle bin's grale-launcher-xxx.jar directly.

So, maybe this is the Gradle team's understanding of "w".

Next, the process of compiling Gradle's own source code is the same as that of a normal program; let's analyze the process of compiling the application with gradle.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report