In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
# = alarm mode 1 use Wechat official API = to be added # = alarm mode 2 =
© 2024 shulou.com SLNews company. All rights reserved.