美文网首页
在MacOS Sierra上用clang工具链编译JDK9

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

作者: nbzhaosq | 来源:发表于2017-10-05 20:03 被阅读0次

      假期得闲,想着最近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的编译和简单的调试算是完成了。

    相关文章

      网友评论

          本文标题:在MacOS Sierra上用clang工具链编译JDK9

          本文链接:https://www.haomeiwen.com/subject/mmdkyxtx.html