JVM源码——Mac下编译JDK

引:好像是在大四的时候,自己按照《深入理解Java虚拟机》去编译JDK没有成功!但是在最近经历一些面试之后,感到JVM绝对是面试的一块重点,而看源码绝对是你深入理解JVM的一个很重要的点!在看源码,就需要调试,那么编译自己JDK越是必然的。这次我们在Mac下去编译OpenJDK9!!!
复联4.jpeg

4.24看完复联4,脑子太多的点化为爱你三千遍

进入今天的正题!!!

准备

关于编译JDK,其实在官方的源码包下有个帮助文件(openjdk/common/building.html/md)。这个文件会告诉我们在编译JDK之前需要做的准备以及编译的步骤。具体的大家可以仔细阅读看看。下次只讲述自己这次所编译的过程!

我们需要准备一些东西,首先你需要准备 homebrew,homwbrew是mac下的包管理器,如果你的mac上没有安装,可以按照下面的方式来安装:

1
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

homwbrew下载完成之后,接下来准备编译环境:

  • 安装openjdk的版本管理工具mercurial(hg)
  • 安装ccache和freetype,ccache用来加速编译,freetype在编译过程也会依赖到

安装脚本为:

1
2
3
brew install mercurial
brew install ccache
brew install freetype

准备好之后就可以开始具体的操作了!

下载源码

官方推荐hg

hg:Mercurial source code management system
我为源码专门创建了一个目录 ~/jvm ,然后运行下面的命令:

1
2
cd ~/jvm
hg clone http://hg.openjdk.java.net/jdk9/jdk9 jdk9

这条命令运行之后,openjdk的源码并没有下载下来,我们随后进入到~/jvm/jdk9目录,会发现有一个 get_source.sh 的文件,调用这个脚本下载完整的源码之前,需要做一下简单的修改,不然可能你在下载源码的过程中会数次中断。

1
2
3
4
5
# Get clones of all absent nested repositories (harmless if already exist)
sh ./common/bin/hgforest.sh clone "$@" || exit $?

# Update all existing repositories to the latest sources
sh ./common/bin/hgforest.sh pull -u

我们把上面几行的脚本删掉,替换成下面的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Get clones of all absent nested repositories (harmless if already exist)
sh ./common/bin/hgforest.sh clone "$@"

while [ $? -ne 0 ]
do
sh ./common/bin/hgforest.sh clone "$@"
done

# Update all existing repositories to the latest sources
sh ./common/bin/hgforest.sh pull -u

while [ $? -ne 0 ]
do
sh ./common/bin/hgforest.sh pull -u
done

然后,愉快地调用:

1
bash ./get_source.sh

本人表示这个这个方法我没有成功,hhh。我在执行hg clone 的时候就一直报网络错误,可能是由于the great wall吧,还好有下面的方法。

github

1
2
1. https://github.com/unofficial-openjdk/openjdk/
2. https://github.com/dmlloyd/openjdk

我选择了第二个,切换到了jdk/jdk9分支,因为我们这次要编译jdk9。操作如下:

1
2
3
4
cd ~/jvm
git clone https://github.com/dmlloyd/openjdk.git
cd openjdk
git checkout -b jdk9 origin/jdk9/jdk9

这个还是挺顺利的,哈哈!

configure

我们先进行编译前的配置(检查):

1
./configure --with-target-bits=64 --with-freetype=/usr/local/Cellar/freetype/2.8.1 --enable-ccache --with-jvm-variants=server,client --with-boot-jdk-jvmargs="-Xlint:deprecation -Xlint:unchecked" --disable-zip-debug-info --disable-warnings-as-errors --with-debug-level=slowdebug 2>&1 | tee configure_mac_x64.log

有日志,出问题查问题也很方便!
注意,上面的freetype,需要替换成本机实际安装的版本

如果出现如下的提示,那么恭喜你,接下来就可以执行编译了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
====================================================
The existing configuration has been successfully updated in
/Users/rex/jvm/openjdk/build/macosx-x86_64-normal-serverANDclient-slowdebug
using configure arguments '--with-target-bits=64 --with-freetype=/usr/local/Cellar/freetype/2.10.0 --enable-ccache --with-jvm-variants=server,client --with-boot-jdk-jvmargs='-Xlint:deprecation -Xlint:unchecked' --disable-warnings-as-errors --with-debug-level=slowdebug'.

Configuration summary:
* Debug level: slowdebug
* HS debug level: debug
* JDK variant: normal
* JVM variants: server client
* OpenJDK target: OS: macosx, CPU architecture: x86, address length: 64
* Version string: 9-internal+0-adhoc.rex.openjdk (9-internal)

Tools summary:
* Boot JDK: java version "9" Java(TM) SE Runtime Environment (build 9+181) Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode) (at /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home)
* Toolchain: clang (clang/LLVM from Xcode 9.4.1)
* C Compiler: Version 9.1.0 (at /usr/bin/clang)
* C++ Compiler: Version 9.1.0 (at /usr/bin/clang++)

Build performance summary:
* Cores to use: 4
* Memory limit: 8192 MB
* ccache status: Active (3.6)

NOTE: You have requested to build more than one version of the JVM, which
will result in longer build times.

WARNING: The result of this configuration has overridden an older
configuration. You *should* run 'make clean' to make sure you get a
proper build. Failure to do so might result in strange build problems.

make

我们执行下面的操作:

1
2
export LANG=C
make all LOG=debug 2>&1 | tee make_mac_x64.log

如果出现如下的提示,那么恭喜你,你的运气太好了!!!

1
2
3
4
5
6
7
8
9
10
11
----- Build times -------
Start 2019-04-25 18:55:19
End 2019-04-25 19:00:57

00:05:38 TOTAL
-------------------------
if test -f /Users/rex/jvm/openjdk/build/macosx-x86_64-normal-serverANDclient-slowdebug/make-support/exit-with-error ; then \
exit 1 ; \
fi
/usr/bin/printf "Finished building target 'all' in configuration 'macosx-x86_64-normal-serverANDclient-slowdebug'\n" > >(/usr/bin/tee -a /Users/rex/jvm/openjdk/build/macosx-x86_64-normal-serverANDclient-slowdebug/build.log) 2> >(/usr/bin/tee -a /Users/rex/jvm/openjdk/build/macosx-x86_64-normal-serverANDclient-slowdebug/build.log >&2) && wait
Finished building target 'all' in configuration 'macosx-x86_64-normal-serverANDclient-slowdebug'

最后,验证一下

1
2
cd build/macosx-x86_64-normal-serverANDclient-slowdebug/jdk/bin
./java -version

出现下面的提示就完美了:

1
2
3
openjdk version "9-internal"
OpenJDK Runtime Environment (slowdebug build 9-internal+0-adhoc.rex.openjdk)
OpenJDK 64-Bit Server VM (slowdebug build 9-internal+0-adhoc.rex.openjdk, mixed mode)

编译过程中的问题

根据墨菲定律

1
2
3
4
一、任何事都没有表面看起来那么简单;
二、所有的事都会比你预计的时间长;
三、会出错的事总会出错;
四、如果你担心某种情况发生,那么它就更有可能发生。

这个时间会比较长,出错是大概率事件,而我就碰到网上该有的所有错!!!!

Xcode版本问题

我的Xcode版本原来为10+,XCode升级到10之后, 删除了底层目录下的libstdc++文件。导致在JDK的Make时会报错, 无法识别类似这样的C++语法。而在XCode9时对应文件还是存在的。官方给出的意思是libstdc++已经被标记为过期5年了, 现在统一使用自己libc++。这个问题最简单的问题就是XCode版本回退到9之前即可。重新下载地址

三个空指针转换

日志被覆盖了,忘记存了,但是可能会出现这样的问题,下面的更改的答案:

1
2
3
4
5
6
7
8
9
10
11
#1\. src/hotspot/share/memory/virtualspace.cpp # l585

if (base() != NULL) {

#2\. src/hotspot/share/opto/lcm.cpp # l42

if (Universe::narrow_oop_base() != NULL) { // Implies UseCompressedOops.

#3\. src/hotspot/share/opto/loopPredicate.cpp # l915

assert(rng->Opcode() == Op_LoadRange || iff->is_RangeCheck() || _igvn.type(rng)->is_int()->_lo >= 0, "must be");

JVM crash

自己也忘记截图,所以也盗图了:
jvm crash.png

解决方法:Building OpenJDK 9 on Mac os

上面三个问题全被自己遇到了,运气真好,不过走到这里,终于是把JDK编译好了!

总结

但行好事,莫问前程

参考

  1. mac下编译openjdk1.9及集成clion动态调试
  2. MacOS Mojave(10.14)编译openjdk9