隨著Android Studio的普及,,越來越多的Android開發(fā)者也要開始了解和學(xué)習(xí)Gradle這款強大的代碼構(gòu)建工具了,。我們在學(xué)習(xí)和了解一項新事物的時候,,最快速的方法往往是與已知的事物進行比較,,對于熟悉Makefile編譯機制的Linux程序員而言,認(rèn)識和掌握Gradle最好的方法莫過于比較它們之間的區(qū)別了,,本文不準(zhǔn)備詳細介紹Gradle的方方面面,,而是希望通過與Makefile的對比幫助Gradle初學(xué)者更快速地理解Gradle的基礎(chǔ)和原理。
Makefile是一種管理和編譯 Linux C/C++ 項目的工具,,而Gradle也是一種代碼構(gòu)建工具,,只不過是針對Java語言的,它同樣可以通過一些配置文件和腳本來完成代碼的依賴,、第三方庫的引入,、編譯的自動化配置等功能。
首先說說Makefile,,它是由一個個"規(guī)則"組成,,每個"規(guī)則"都是由"目標(biāo)"、"依賴",、"命令"構(gòu)成,, 一個最簡單的Makefile如下所示:
1 2 3 4 5 6 7 8 9 | .PHONY: clean
all: hello
hello: hello.c
gcc -o hello hello.c
clean:
rm hello
|
這里有三個"目標(biāo)",分別是: "all",,"hello",,"clean"
當(dāng)執(zhí)行"make"命令時,編譯器會默認(rèn)查找目標(biāo)"all" ,,如果沒有"all"則會查找Makefile文件的第一個目標(biāo),。本示例中有"all"目標(biāo),它依賴"hello"目標(biāo),,因此編譯器會轉(zhuǎn)而先構(gòu)建"hello"目標(biāo),,構(gòu)建前, 編譯器會先檢測"hello"目標(biāo)是否需要更新(通過判斷"hello"文件與它所依賴的源文件"hello.c"的修改時間),,如果需要,,則執(zhí)行后面的命令,而需要編譯的源文件則是通過手動或者相關(guān)函數(shù)的方式添加到編譯命令的參數(shù)中去的,。
這就是makefile最核心的構(gòu)建思想,,通過一個個"目標(biāo)"、"依賴",、"命令"來完成整個項目的關(guān)聯(lián)和編譯,。那么,,我們也根據(jù)這一思想來看看Gradle是怎么實現(xiàn)的。
1. Gradle是怎么識別源文件的 ?
Gradle是采取了一種"約定優(yōu)于配置"的思想來完成這一點的,,它通過"Plugin"來約定項目的目標(biāo)和源文件的布局,,例如: Java Plugin 定義的源文件布局如圖所示:
由該圖可以很清楚地看到,Java Plugin 直接約定好了源文件的目錄結(jié)構(gòu),,在Gradle中,,一般把這些源碼目錄的配置叫做"SourceSet",同理,,Android提供的Android Plugin同樣也定義了自己的源文件布局,,還加入了如 jni, AndroidManifest.xml 等目錄和文件,。對于Gradle項目而言,,需要在每個代碼模塊的"build.gradle"文件中定義使用哪一種Plugin, 例如:
1 2 3 4 5 6 7 8 | // 普通的Java項目
apply plugin: 'java'
//Android Application
apply plugin: 'com.android.application'
//Android Library
apply plugin: 'com.android.library'
|
2. Gradle是如何識別編譯目標(biāo)的 ?
在Gradle中,,與Makefile的"目標(biāo)"相對應(yīng)的概念是"任務(wù)",,即"task",Gradle的構(gòu)建過程,,就是執(zhí)行一條一條"task"任務(wù)的過程,, 同樣,一個"task"也是可以依賴另一個"task"的,,這樣,,通過這種依賴關(guān)系,就可以將整個項目中各個"task"鏈接到一起了,。
與Makefile中手寫目標(biāo)的方式不同,,Gradle將所有的"task"的定義全部交給Plugin來完成,由于每一種工程類型(Java項目,、Android項目等),,其構(gòu)建過程都是大同小異的,因此為每一種類型的項目定義好了一種通用的Plugin,,以后同類型的項目就可以直接使用該Plugin了,,非常的靈活和方便。
當(dāng)我們在項目中執(zhí)行"gradle build"命令時,,可以看到該項目使用的Plugin具體定義了哪些"task",,例如一個典型的Java Plugin定義的"task"如下所示:
1 2 3 4 5 6 7 8 9 10 11 | :compileJava
:processResources
:classes
:jar
:assemble
:compileTestJava
:processTestResources
:testClasses
: test
:check
:build
|
當(dāng)然,雖然同是Android類型的工程,,但不同的項目畢竟還是有配置上的差異,,因此,Gradle的Plugin中也可以定義和導(dǎo)出一些特定的"元素"用于傳遞用戶自定義的配置信息,,例如: Google提供的 "com.android.application"Plugin 就定義了一個"android"元素,,開發(fā)者可以在build.gradle中配置該元素的細節(jié),,比如定義一些: "項目的ID"、"sdk的版本",、"是否混淆"等等,,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 | android {
compileSdkVersion 21
buildToolsVersion "21.1.1"
defaultConfig {
applicationId "com.jhuster.test"
minSdkVersion 15
targetSdkVersion 21
versionCode 1
versionName "1.0.0"
}
}
|
3. Gradle命令怎么用 ?
gradle命令與make命令類似,,都是用來執(zhí)行編譯/清理任務(wù)的,,make命令默認(rèn)查找當(dāng)前目錄下的Makefile文件,并且開始構(gòu)建命令參數(shù)中所指定的"目標(biāo)",,例如:
同樣,,gradle命令也是類似的用法,,例如:
1 2 3 4 | $gradle build // 構(gòu)建和打包整個項目
$gradle clean // 清除之前的構(gòu)建
$gradle test // 執(zhí)行測試
$gradle compileJava // 編譯java
|
4. Gradle是如何引入第三方庫的 ?
對于Makefile而言,,通常需要將第三方庫的源碼下載下來,,編譯為庫后,放入到工程目錄下,,然后修改Makefile文件,,在gcc/g++的編譯鏈接參數(shù)中引用該第三方庫的,例如:
1 2 | hello: hello.c
gcc -o hello hello.c -L /libs/foo .a
|
而Gradle則是通過build.grade文件中的dependencies來配置的,,例如:
1 2 3 4 | dependencies {
compile files( 'libs/foo.jar' ) // 以jar的方式引用
compile project( ':foo' ) // 以library工程源碼的方式引用
}
|
另外,,Gradle還支持類似Ubuntu軟件源倉庫的方式來引用第三方庫,開發(fā)者可以將自己的第三方庫上傳到一些支持Gradle的中心倉庫中,,這樣,,其他人就可以通過配置build.gradle直接完成對第三方庫的引用了,代碼構(gòu)建的時候Gradle會自動完成第三方庫的下載和鏈接,。比較常用的兩個個中心倉庫: jcenter,,mavenCentral。
例如: 我們引用jcenter倉庫的okhttp庫,,則build.gradle配置如下:
1 2 3 4 5 6 7 8 9 | allprojects {
repositories {
jcenter()
}
}
dependencies {
compile 'com.squareup.okhttp:okhttp:2.4.0'
}
|
5. 小結(jié)
Gradle真的很強大很靈活,,它將最核心的構(gòu)建規(guī)都則交給了Plugin來完成,這樣,,輕松實現(xiàn)了構(gòu)建過程的通用性,,開發(fā)者只需要關(guān)注業(yè)務(wù)邏輯,以及少許的配置即可完成自動化編譯和部署的過程,,相比于Linux手寫makefile要方便很多,。好了,關(guān)于Gradle和Makefile的簡單對比就介紹到這里了,,希望對Gradle的初學(xué)者有所幫助,,有任何疑問或者建議歡迎留言或者來信[email protected]交流,或者關(guān)注我的新浪微博 @盧_俊 獲取最新的文章和資訊,。