??假期得閑,想著最近Java 9已發(fā)布,要不來(lái)編譯一下OpenJDK 9吧笔宿。
??說(shuō)干就干火鼻,首先就是獲取源碼。OpenJDK的源碼使用mercurial管理藻雪,所以沒(méi)有安裝過(guò)mercurial的話需要先安裝mercurial秘噪,使用brew的話,可以直接用brew進(jìn)行安裝勉耀。
brew install mercurial
??安裝完mercurial后就可以獲取源碼了指煎,mercurial的命令是hg。
hg clone http://hg.openjdk.java.net/jdk9/jdk9 jdk9
cd jdk9
bash ./get_source.sh
??get_source.sh這個(gè)腳本用于輔助獲取jdk9相關(guān)的所有子項(xiàng)目(包括corba便斥、jdk至壤、jaxp、jaxws椭住、hotspot崇渗、nashorn等)。
??jdk9使用autotools生成Makefile京郑,支持多種工具鏈(如gcc宅广、xlc、clang)些举,由于我自己的開(kāi)發(fā)機(jī)是mac跟狱,所以在此就介紹如何使用clang工具鏈來(lái)進(jìn)行編譯。
cd jdk9
chmod u+x configure
./configure --enable-debug --with-target-bits=64 --with-jvm-variants=server --disable-warnings-as-errors --with-toolchain-type=clang
# --enable-debug 用于開(kāi)啟調(diào)試功能
# --with-target-bits=64 用于指定基于64位進(jìn)行編譯
# --with-jvm-variants=server 用于指定只編譯server版本的jdk
# --disable-warnings-as-errors 是為了編譯通過(guò)不要把警告當(dāng)錯(cuò)誤處理
# --with-toolchain-type=clang 則是指定編譯用的工具鏈為clang
??執(zhí)行以上命令后就會(huì)生成編譯jdk9項(xiàng)目使用的相關(guān)文件(Makefile和make目錄)户魏,此時(shí)執(zhí)行make就可以進(jìn)行編譯了驶臊,但編譯的時(shí)候可能會(huì)遇到一些錯(cuò)誤,我遇到的錯(cuò)誤主要是關(guān)于指針和零值比較的叼丑。我遇到過(guò)3處報(bào)錯(cuò)关翎,可供參考,我的修改方式也較為簡(jiǎn)單鸠信,只是把比較去掉纵寝,直接判斷是否為空指針。
jdk9/hotspot/src/share/vm/opto/lcm.cpp:42:35: error: ordered comparison between pointer and zero ('address' (aka 'unsigned char *') and 'int')
if (Universe::narrow_oop_base() > 0) { // Implies UseCompressedOops.
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~
jdk9/hotspot/src/share/vm/opto/loopPredicate.cpp:903:73: error: ordered comparison between pointer and zero ('const TypeInt *' and 'int')
assert(rng->Opcode() == Op_LoadRange || _igvn.type(rng)->is_int() >= 0, "must be");
~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~
jdk9/hotspot/src/share/vm/memory/virtualspace.cpp:584:14: error: ordered comparison between pointer and zero ('char *' and 'int')
if (base() > 0) {
~~~~~~ ^ ~
??執(zhí)行make命令進(jìn)行編譯星立。
make
??如果順利的話最終會(huì)看到類(lèi)似的輸出爽茴。
Finished building target 'default (exploded-image)' in configuration 'macosx-x86_64-normal-server-fastdebug'
??編譯完后的輸出文件在build目錄下,因?yàn)橹痪幾g了server版本绰垂,所以輸出的目錄是build/macosx-x86_64-normal-server-fastdebug室奏。這個(gè)目錄下的hotspot和jdk就是我們想要的東西了。其中hotspot目錄中含有一個(gè)名為hotspot的腳本劲装,用于輔助調(diào)試jvm胧沫,先嘗試執(zhí)行一下hotspot腳本昌简。
cd hotspot/variant-server/libjvm
bash hotspot
??我得到的是類(lèi)似下面的輸出
Error: missing `/xxx/jvm/jdk9/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/libjvm' JVM at `/xxx/jvm/jdk9/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/libjvm/libjvm.dylib'.
??問(wèn)題也比較明確,缺少了libjvm.dylib這個(gè)文件來(lái)支持jvm的啟動(dòng)琳袄。那就打開(kāi)hotspot腳本來(lái)看一下問(wèn)題出在哪江场。其中有一段這樣的內(nèi)容
REL_MYDIR=`dirname $0`
MYDIR=`cd $REL_MYDIR && pwd`
...
JPARMS="-XXaltjvm=$MYDIR -Dsun.java.launcher.is_altjvm=true"
??缺啥補(bǔ)啥,既然缺libjvm.dylib窖逗,那我們就來(lái)搜一下生成的目錄下有沒(méi)有這個(gè)文件址否,在build/macosx-x86_64-normal-server-fastdebug目錄下進(jìn)行查找。
find . -name 'libjvm.dylib'
??我得到的輸出如下碎紊。
./hotspot/variant-server/libjvm/gtest/libjvm.dylib
./jdk/lib/server/libjvm.dylib
./jdk/lib/server/libjvm.dylib.dSYM/Contents/Resources/DWARF/libjvm.dylib
./support/modules_libs/java.base/server/libjvm.dylib
./support/modules_libs/java.base/server/libjvm.dylib.dSYM/Contents/Resources/DWARF/libjvm.dylib
??最簡(jiǎn)單的方式就是把gtest目錄下的libjvm.dylib復(fù)制到libjvm目錄下(注意:這幾個(gè)libjvm.dylib的功能并不一致佑附,md5校驗(yàn)也不同,此處只是為了讓hotspot腳本運(yùn)行起來(lái))仗考。
cp hotspot/variant-server/libjvm/gtest/libjvm.dylib hotspot/variant-server/libjvm/
??由于之前編譯使用的clang工具鏈音同,所以調(diào)試也就基于lldb進(jìn)行,但原來(lái)的hotspot腳本中并沒(méi)有l(wèi)ldb調(diào)試的相關(guān)內(nèi)容秃嗜,需要進(jìn)行添加权均。修改hotspot腳本
...
# 約在85行左右,此處添加對(duì)lldb參數(shù)對(duì)識(shí)別
case "$1" in
-gdb)
MODE=gdb
shift
;;
-lldb)
MODE=lldb
shift
;;
-gud)
MODE=gud
shift
;;
...
# 約在200行左右锅锨,此處添加lldb的模式
case "$MODE" in
gdb)
init_gdb
$GDB -x $GDBSCR --args $LAUNCHER $JPARMS "$@" $JAVA_ARGS
rm -f $GDBSCR
;;
lldb)
lldb -- $LAUNCHER $JPARMS "$@" $JAVA_ARGS
;;
gud)
init_gdb
...
??為了接下去的調(diào)試方便叽赊,先在當(dāng)前的終端設(shè)置一下新的jdk目錄變量,在build/macosx-x86_64-normal-server-fastdebug目錄下執(zhí)行下面的命令必搞。
FASTDEBUG_HOME=`pwd`
NEW_JDK_HOME=`pwd`/jdk
??創(chuàng)建一個(gè)工作目錄必指,在工作目錄下新建一個(gè)測(cè)試文件Hello.java。
mkdir $FASTDEBUG_HOME/workspace
cd $FASTDEBUG_HOME/workspace
??Hello.java
public class Hello {
public static void main(String[] args) throws Exception {
System.out.println("Hello, world!");
}
}
??編譯Hello.java恕洲。
$NEW_JDK_HOME/bin/javac Hello.java
??使用lldb調(diào)試Hello.class
$FASTDEBUG_HOME/hotspot/variant-server/libjvm/hotspot -lldb -cp . Hello
??這樣就進(jìn)入了lldb的調(diào)試終端塔橡,使用b main打下我們的第一個(gè)斷點(diǎn)。
/xxx/jvm/jdk9/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/libjvm
(lldb) target create "/xxx/jvm/jdk9/build/macosx-x86_64-normal-server-fastdebug/jdk/bin/java"
Current executable set to '/xxx/jvm/jdk9/build/macosx-x86_64-normal-server-fastdebug/jdk/bin/java' (x86_64).
(lldb) settings set -- target.run-args "-XXaltjvm=/xxx/jvm/jdk9/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/libjvm" "-Dsun.java.launcher.is_altjvm=true" "-cp" "." "Hello"
(lldb) b main
Breakpoint 1: 19 locations.
??然后執(zhí)行run就可以讓jvm跑起來(lái)了霜第,通過(guò)c指令來(lái)讓進(jìn)程繼續(xù)葛家,直到看到輸出"Hello,world!"進(jìn)程退出為止。
Target 0: (java) stopped.
(lldb) c
Process 3500 resuming
Hello, world!
Process 3500 exited with status = 0 (0x00000000)
??至此泌类,jdk9的編譯和簡(jiǎn)單的調(diào)試算是完成了惦银。