買了《深入理解Java虛擬機》 周志明著這本書一直沒有看,我們的程序都用JVM在跑,所以學習java必須掌握JVM,才能理解我們對象到底干嘛了。
1.為什么要編譯JDK
想要一探JDK內部的實現機制,最便捷的路徑之一就是自己編譯一套JDK,通過閱讀和跟蹤調試JDK源碼去了解Java技術體系的原理,雖然門檻高一點,但肯定比閱讀各種書籍,文章,博客更在貼切一點,另外,JDK的很多方法都是本地化(Native)的,需要跟蹤這些方法的運作或對JDK進行Hack的時候,都需要自己編譯一套JDK。
2.選擇JDK
現在網上有不少開源的JDK實現可以供我們選擇,如Apache Harmony,OpenJDK等,考慮到Sun系列的JDK是現在使用得最廣泛的JDK版本,所以我們選擇openJDK進行編譯。
關於openJDK?
openJDK是sun在2006年末把java開源而形成的項目。開源是通常意義上的源碼形式上開放,等同於源碼可被復用。商業版的oracle jdk和open jdk 除了版權注釋之外,其余代碼基本上都是相同的,都是建立在兩者共有的組件基礎上。oracle jdk還會存在一些open jdk沒有的,商用閉源的功能。oracle的項目發布經理Joe Darcy 在OSCON2011 上對兩者的關系上也證實了oracle jdk和open jdk程序上市非常接近。
3.環境准備
1.openJDK下載,獲取openJDk源碼有兩種方式.
(1)其中一種是通過一款代碼版本管理Mercurial上獲取
hg clone http://hg.openjdk.java.net/jdk8/jdk8 jdk8
cd jkd8
bash ./get_source.sh
這種是最直接的方式,但是由於文件很多,國內的網絡對Mercurial不如對git svn上不夠快,經常可能失敗,可以把鏡像換成國內的,這個可以自己找找。
把這里的下載地址前面的域名弄錯了,應該是http://download.java.net,把前面的域名換掉,后面的不變,就能下載打包好的源碼文件。參考1.7地址: http://download.java.net/openjdk/jdk7/promoted/b147/openjdk-7-fcs-src-b147-27_jun_2011.zip
2.安裝依賴軟件,如果沒有brew命令,可以先看看brew怎么安裝再繼續執行以上安裝命令。
(1)Xcode-select:安裝命令:xcode-select –install 進行x11鏈接
sudo ln -s /usr/X11/include/X11 /usr/include/X11 or sudo ln -s /usr/local/X11/include/X11 /usr/include/X11 (如果軟連接失敗,重啟mac時按住command+R 進入恢復模式,然后打開terminal 執行 csrutil disable,再重啟,這是mac對安全的一種校驗)
(3)安裝freetype,安裝命令:brew freetype
(4)安裝GC 安裝命令: brew install gcc49 據說安裝往上的版本會報錯。
(5) 安裝ccache提升編譯速度 brew install freetype
(6) 安裝ant 一般mac都會有這個環境,如果沒有執行:brew install ant
3.修改源碼
(1). 修改generated-configure.sh(路徑:common/autoconf/generated-configure.sh)
注釋20061行
// as_fn_error $? "GCC compiler is required. Try setting --with-tools-dir." "$LINENO" 5
注釋21640行
// as_fn_error $? "GCC compiler is required. Try setting --with-tools-dir." "$LINENO" 5
(2). 修改relocInfo.hpp(路徑:hotspot/src/share/vm/code/relocInfo.hpp)
修改367行
inline friend relocInfo prefix_relocInfo(int datalen);
修改472行
inline relocInfo prefix_relocInfo(int datalen = 0) {
assert(relocInfo::fits_into_immediate(datalen), "datalen in limits");
return relocInfo(relocInfo::data_prefix_tag, relocInfo::RAW_BITS, relocInfo::datalen_tag | datalen);
}
(3). 修改openjdk/hotspot/src/share/vm/opto/loopPredicate.cpp
修改775行為
assert(rng->Opcode() == Op_LoadRange || _igvn.type(rng)->is_int()->_lo >= 0, "must be");
(4).修改openjdk/hotspot/src/share/vm/runtime/virtualspace.cpp
修改331行為
if (base() != 0) {
4.設置環境變量
cd ~
open .bash_profile (這個在安裝jdk都會設置的,如果沒有這個文件去看看jdk安裝的教程)
添加變量:
export LANG=C
# 設定語言選項,必須設置
export LANG=C
# Mac平台,C編譯器不再是GCC,是clang
export CC=clang
# 跳過clang的一些嚴格的語法檢查,不然會將N多的警告作為Error
export COMPILER_WARNINGS_FATAL=false
# 鏈接時使用的參數
export LFLAGS='-Xlinker -lstdc++'
# 是否使用clang
export USE_CLANG=true
# 使用64位數據模型
export LP64=1
# 告訴編譯平台是64位,不然會按32位來編譯
export ARCH_DATA_MODEL=64
# 允許自動下載依賴
export ALLOW_DOWNLOADS=true
# 並行編譯的線程數,編譯時間長,為了不影響其他工作,我選擇為2
export HOTSPOT_BUILD_JOBS=2
export ALT_PARALLEL_COMPILE_JOBS=2
# 是否跳過與先前版本的比較
export SKIP_COMPARE_IMAGES=true
# 是否使用預編譯頭文件,加快編譯速度
export USE_PRECOMPILED_HEADER=true
# 是否使用增量編譯
export INCREMENTAL_BUILD=true
# 編譯內容
export BUILD_LANGTOOLS=true
export BUILD_JAXP=true
export BUILD_JAXWS=true
export BUILD_CORBA=true
export BUILD_HOTSPOT=true
export BUILD_JDK=true
# 編譯版本
export SKIP_DEBUG_BUILD=true
export SKIP_FASTDEBUG_BUILD=false
export DEBUG_NAME=debug
# 避開javaws和瀏覽器Java插件之類的部分的build
export BUILD_DEPLOY=false
export BUILD_INSTALL=false
最后干掉這兩個變量,不然會有詭異的事發生
unset JAVA_HOME
unset CLASSPATH
5.編譯, ( 遇到問題可以先看看下面的問題描述)
(1)cd 到下載好的openSDK目錄下,先授予權限給openJDK目錄 如: chmod -R 777 openjdk
(2)./configure 如果找不freetype 可以執行./configure --with-freetype-include=/usr/local/include/freetype2 --with-freetype-lib=/usr/local/lib/
(3) 開始執行make命令: 在執行make命令需要指定編譯環境,環境路徑在:./openjdk/build/下面 一般有兩個 macosx-x86_64-normal-server-release 和 macosx-x86_64-normal-server-slowdebug
如果一般編譯失敗會有失敗的文件,為了保險起見先執行:
make CONF=macosx-x86_64-normal-server-release clean 或者
make CONF=macosx-x86_64-normal-server-slowdebug clean
再執行:
make CONF=macosx-x86_64-normal-server-release install 或者
make CONF=macosx-x86_64-normal-server-slowdebug install
編譯成功如圖:
6.我執行./configure和編譯遇到的問題:
(1)./configure問題: configure: error: GCC compiler is required
解決方法:
jdk8/common/autoconf/generated-configure.sh文件中 注釋兩處代碼:第20061,21640行 #as_fn_error $? "GCC compiler is required. Try setting --with-tools-dir." "$LINENO" 5
(2)make問題:
Running nasgen
Exception in thread "main" java.lang.VerifyError:
class jdk.nashorn.internal.objects.ScriptFunctionImpl overrides final method setPrototype.(Ljava/lang/Object;)V
解決方法:
修改:vim ./openJDk/nashorn/make/BuildNashorn.gmk
80行原來 -cp 修改為:-Xbootclasspath/p: 如圖:
7.測試是否編譯成功
cd ./openjdk/build/macosx-x86_64-normal-server-release/jdk/bin
執行java -version
如圖則編譯成功: