在MacOS Sierra上用clang工具链编译JDK9

2017-10-05  本文已影响0人  nbzhaosq

  假期得闲,想着最近Java 9已发布,要不来编译一下OpenJDK 9吧。
  说干就干,首先就是获取源码。OpenJDK的源码使用mercurial管理,所以没有安装过mercurial的话需要先安装mercurial,使用brew的话,可以直接用brew进行安装。

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这个脚本用于辅助获取jdk9相关的所有子项目(包括corba、jdk、jaxp、jaxws、hotspot、nashorn等)。
  jdk9使用autotools生成Makefile,支持多种工具链(如gcc、xlc、clang),由于我自己的开发机是mac,所以在此就介绍如何使用clang工具链来进行编译。

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 用于开启调试功能
# --with-target-bits=64 用于指定基于64位进行编译
# --with-jvm-variants=server 用于指定只编译server版本的jdk
# --disable-warnings-as-errors 是为了编译通过不要把警告当错误处理
# --with-toolchain-type=clang 则是指定编译用的工具链为clang

  执行以上命令后就会生成编译jdk9项目使用的相关文件(Makefile和make目录),此时执行make就可以进行编译了,但编译的时候可能会遇到一些错误,我遇到的错误主要是关于指针和零值比较的。我遇到过3处报错,可供参考,我的修改方式也较为简单,只是把比较去掉,直接判断是否为空指针。

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) {
      ~~~~~~ ^ ~

  执行make命令进行编译。

make

  如果顺利的话最终会看到类似的输出。

Finished building target 'default (exploded-image)' in configuration 'macosx-x86_64-normal-server-fastdebug'

  编译完后的输出文件在build目录下,因为只编译了server版本,所以输出的目录是build/macosx-x86_64-normal-server-fastdebug。这个目录下的hotspot和jdk就是我们想要的东西了。其中hotspot目录中含有一个名为hotspot的脚本,用于辅助调试jvm,先尝试执行一下hotspot脚本。

cd hotspot/variant-server/libjvm
bash hotspot

  我得到的是类似下面的输出

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'.

  问题也比较明确,缺少了libjvm.dylib这个文件来支持jvm的启动。那就打开hotspot脚本来看一下问题出在哪。其中有一段这样的内容

REL_MYDIR=`dirname $0`
MYDIR=`cd $REL_MYDIR && pwd`
...
JPARMS="-XXaltjvm=$MYDIR -Dsun.java.launcher.is_altjvm=true"

  缺啥补啥,既然缺libjvm.dylib,那我们就来搜一下生成的目录下有没有这个文件,在build/macosx-x86_64-normal-server-fastdebug目录下进行查找。

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

  最简单的方式就是把gtest目录下的libjvm.dylib复制到libjvm目录下(注意:这几个libjvm.dylib的功能并不一致,md5校验也不同,此处只是为了让hotspot脚本运行起来)。

cp hotspot/variant-server/libjvm/gtest/libjvm.dylib hotspot/variant-server/libjvm/

  由于之前编译使用的clang工具链,所以调试也就基于lldb进行,但原来的hotspot脚本中并没有lldb调试的相关内容,需要进行添加。修改hotspot脚本

...
# 约在85行左右,此处添加对lldb参数对识别
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
...

  为了接下去的调试方便,先在当前的终端设置一下新的jdk目录变量,在build/macosx-x86_64-normal-server-fastdebug目录下执行下面的命令。

FASTDEBUG_HOME=`pwd`
NEW_JDK_HOME=`pwd`/jdk

  创建一个工作目录,在工作目录下新建一个测试文件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调试Hello.class

$FASTDEBUG_HOME/hotspot/variant-server/libjvm/hotspot -lldb -cp . Hello

  这样就进入了lldb的调试终端,使用b main打下我们的第一个断点。

/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.

  然后执行run就可以让jvm跑起来了,通过c指令来让进程继续,直到看到输出"Hello,world!"进程退出为止。

Target 0: (java) stopped.
(lldb) c
Process 3500 resuming
Hello, world!
Process 3500 exited with status = 0 (0x00000000)

  至此,jdk9的编译和简单的调试算是完成了。

上一篇下一篇

猜你喜欢

热点阅读