獲取OpenJDK源碼有兩種方式,其中一種是通過Mercurial代碼版本管理工具從Repository中直接取得源碼(Repository地址:http://hg.openjdk.java.net/jdk7u/jdk7u),獲取過程如以下代碼所示。
hg clone http://hg.openjdk.java.net/jdk7u/jdk7u-dev
cd jdk7u-dev
chmod 755 get_source.sh
./get_source.sh
這是最直接的方式,從版本管理中看變更軌跡比看Release Note效果更好。但不足之處是速度太慢,雖然代碼總容量只有300 MB左右,但是文件數量太多,全部復制到本地需要數小時。另外,考慮到Mercurial不如Git、SVN、ClearCase或CVS之類的版本控制工具那樣普及,建議采用第二種方式,即直接下載官方打包好的源碼包,讀者可以從Source Bundle Releases頁面(地址:http://jdk7.java.net/source.html)取得打包好的源碼,到本地直接解壓即可。一般來說,源碼包大概一至兩個月左右會更新一次,雖然不夠及時,但比起從Mercurial復制代碼的確方便和快捷許多。
構建編譯環境
對於MacOS來說
只有在OpenJDK 7u4和之后的版本才能編譯出Mac OS系統下的JDK包,之前的版本雖然在源碼和編譯腳本中也包含了Mac OS目錄,但是尚未完善。
對於Mac OS,需要安裝最新版本的XCode和Command Line Tools for XCode,在Apple Developer網站(https://developer.apple.com/)上可以免費下載,這兩個SDK包提供了OpenJDK所需的編譯器以及Makefile中用到的外部命令。另外,還要准備一個6u14以上版本的JDK,因為OpenJDK的各個組成部分(Hotspot、JDK API、JAXWS、JAXP……)有的是使用C++編寫的,更多的代碼則是使用Java自身實現的,因此編譯這些Java代碼需要用到一個可用的JDK,官方稱這個JDK為“Bootstrap JDK”。如果編譯OpenJDK 7,Bootstrap JDK必須使用JDK6 Update 14或之后的版本。最后需要下載一個1.7.1以上版本的Apache Ant,用於執行Java編譯代碼中的Ant腳本。
對於Linux來說
所需要准備的依賴與Mac OS差不多,Bootstrap JDK和Ant都是一樣的,在Mac OS中GCC編譯器來源於XCode SDK,而Ubuntu中GCC應該是默認安裝好的,需要確保版本為4.3以上,如果沒有找到GCC,安裝binutils即可,在Ubuntu 10.10下編譯OpenJDK 7u4所需的依賴可以使用以下命令一次安裝完成。
sudo apt-get install build-essential gawk m4 openjdk-6-jdk
libasound2-dev libcups2-dev libxrender-dev xorg-dev xutils-dev
x11proto-print-dev binutils libmotif3 libmotif-dev ant
進行編譯
需要下載的編譯環境和依賴項目都准備齊全了,最后還需要對系統的環境變量做一些簡單設置以便編譯能夠順利通過。OpenJDK在編譯時讀取的環境變量有很多,但大多都有默認值,必須設置的只有兩個:LANG和ALT_BOOTDIR,前者是設定語言選項,必須設置為:
export LANG=C
否則,在編譯結束前的驗證階段會出現一個HashTable內的空指針異常。另外一個ALT_BOOTDIR參數是前面提到的Bootstrap JDK,在Mac OS上設為以下路徑,其他操作系統對應調整即可。
export ALT_BOOTDIR=/Library/Java/JavaVirtualMachines/jdk1.7.0_04.jdk/Contents/Home
另外,如果之前設置了JAVA_HOME和CLASSPATH兩個環境變量,在編譯之前必須取消,否則在Makefile腳本中檢查到有這兩個變量存在,會有警告提示。
unset JAVA_HOME
unset CLASSPATH
編譯shell腳本:
#環境變量設置
#語言選項,這個必須設置,否則編譯好后會出現一個HashTable的NPE錯
export LANG=C
#Bootstrap JDK的安裝路徑。必須設置
export ALT_BOOTDIR=/Library/Java/JavaVirtualMachines/jdk1.7.0_04.jdk/Contents/Home
#允許自動下載依賴
export ALLOW_DOWNLOADS=true
#並行編譯的線程數,設置為和CPU內核數量一致即可
export HOTSPOT_BUILD_JOBS=6
export ALT_PARALLEL_COMPILE_JOBS=6
#比較本次build出來的映像與先前版本的差異。這對我們來說沒有意義,
#必須設置為false,否則sanity檢查會報缺少先前版本JDK的映像的錯誤提示。
#如果已經設置dev或者DEV_ONLY=true,這個不顯式設置也行
export SKIP_COMPARE_IMAGES=true
#使用預編譯頭文件,不加這個編譯會更慢一些
export USE_PRECOMPILED_HEADER=true
#要編譯的內容
export BUILD_LANGTOOLS=true
#export BUILD_JAXP=false
#export BUILD_JAXWS=false
#export BUILD_CORBA=false
export BUILD_HOTSPOT=true
export BUILD_JDK=true
#要編譯的版本
#export SKIP_DEBUG_BUILD=false
#export SKIP_FASTDEBUG_BUILD=true
#export DEBUG_NAME=debug
#把它設置為false可以避開javaws和瀏覽器Java插件之類的部分的build
BUILD_DEPLOY=false
#把它設置為false就不會build出安裝包。因為安裝包里有些奇怪的依賴,
#但即便不build出它也已經能得到完整的JDK映像,所以還是別build它好了
BUILD_INSTALL=false
#編譯結果所存放的路徑
export ALT_OUTPUTDIR=/Users/IcyFenix/Develop/JVM/jdkBuild/openjdk_7u4/build
#這兩個環境變量必須去掉,不然會有很詭異的事情發生(我沒有具體查過這些"詭異的
#事情",Makefile腳本檢查到有這2個變量就會提示警告)
unset JAVA_HOME
unset CLASSPATH
make 2>&1|tee $ALT_OUTPUTDIR/build.log
全部設置結束之后,可以輸入make sanity來檢查我們前面所做的設置是否全部正確。Makefile的Sanity檢查過程輸出了編譯所需的所有環境變量,如果看到“Sanity check passed.”,說明檢查過程通過了,可以輸入“make”執行整個OpenJDK編譯(make不加參數,默認編譯make all),使用Core i7 3720QM/16GB RAM的MacBook機器,啟動6條編譯線程,全量編譯整個OpenJDK大概需20分鍾,編譯結束后,將輸出類似下面的日志清單所示內容。如果之前已經全量編譯過,只修改了少量文件,增量編譯可以在數十秒內完成。
#--Build times----------
Target all_product_build
Start 2012-12-13 17:12:19
End 2012-12-13 17:31:07
00:01:19 corba
00:01:15 hotspot
00:00:14 jaxp
00:7:21 jaxws
00:8:11 jdk
00:00:28 langtools
00:18:48 TOTAL
-------------------------
編譯完成之后,進入OpenJDK源碼下的build/j2sdk-image目錄(或者build-debug、build-fastdebug這兩個目錄),這是整個JDK的完整編譯結果,復制到JAVA_HOME目錄,就可以作為一個完整的JDK使用,編譯出來的虛擬機,在-version命令中帶有用戶的機器名。
>./java-version
openjdk version"1.7.0-internal-fastdebug"
O p e n J D K R u n t i m e E n v i r o n m e n t(b u i l d 1.7.0-i n t e r n a l-f a s t d e b u g-icyfenix_2012_12_24_15_57-b00)
OpenJDK 64-BitServer VM(build 23.0-b21-fastdebug,mixed mode)
如果我們並不關心JDK中HotSpot虛擬機以外的內容,只想單獨編譯HotSpot虛擬機的話(例如調試虛擬機時,每次改動程序都執行整個OpenJDK的Makefile,速度肯定受不了,那么使用hotspot/make目錄下的Makefile進行替換即可,其他參數設置與前面是一致的,這時候虛擬機的輸出結果存放在build/hotspot/outputdir/bsd_amd64_compiler2目錄
在不同機器上,最后一個目錄名稱會有所差別,bsd表示Mac OS系統(內核為FreeBSD),amd64表示是64位JDK(32位是x86),compiler2表示是Server VM(Client VM表示是compiler1)。
進入后可以見到以下幾個目錄。
0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 debug
0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 fastdebug
0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:25 generated
0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 jvmg
0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 optimized
0 drwxr-xr-x 584 IcyFenix staff 19K 12 13 17:25 product
0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 profiled
這些目錄對應了不同的優化級別,優化級別越高,性能自然就越好,但是輸出代碼與源碼的差距就越大,難於調試,具體哪個目錄有內容,取決於make命令后面的參數。
運行虛擬機
在編譯結束之后、運行虛擬機之前,還要手工編輯目錄下的env.sh文件,這個文件由編譯腳本自動產生,用於設置虛擬機的環境變量,里面已經發布了“JAVA_HOME、CLASSPATH、HOTSPOT_BUILD_USER”3個環境變量,還需要增加一個“LD_LIBRARY_PATH”,內容如下:
LD_LIBRARY_PATH=.:${JAVA_HOME}/jre/lib/amd64/native_threads:${JAVA_HOME}/jre/lib/amd64:
export LD_LIBRARY_PATH
然后執行以下命令啟動虛擬機(這時的啟動器名為gamma),輸出版本號。
../env.sh
./gamma-version
Using java runtime at:/Library/Java/JavaVirtualMachines/jdk1.7.0_04.jdk/Contents/Home/jre
java version"1.7.0_04"
Java(TM)SE Runtime Environment(build 1.7.0_04-b21)
OpenJDK 64-BitServer VM(build 23.0-b21,mixed mode)