JVM学习(四) 手动编译Windows版及Linux版OpenJDK14

Posted by Lain on 03-31,2020

前言

前段时间发现《深入理解Java虚拟机》于去年12月出第三版了,这次由第二版的jdk6升级到了jdk11,于是兴致勃勃的找了电子版来拜读了一下(本来是想买的,但是小出租屋,实体书太多实在放不下了...之后一定补票),受益匪浅。感觉比第二版讲的清晰了太多,而且补充了很多JVM未来可能推出的新特性,比如Loom,Graal VM等,给人一种视野一下子被打开了的感觉。

这几天照着电子书第一章以及OpenJDK的官方文档,成功的编译了OpenJDK14,Linux和Windows都编译了一份,其中Windows版的编译还是挺坑的,花了两天的时间去踩坑,特此记录一下。

为什么要自己编译JDK?因为要了解JDK,就要对其进行定制和调试,这些在官方发布的版本中往往都是屏蔽掉了的,也就是通过编译时提供的编译级别 --with-debug-level。可选值为release、fastdebug、slowde-bug,越往后进行的优化措施就越少,带的调试信息就越多。还有一些虚拟机调试参数必须在特定模式下才可以使用。默认值为release

编译环境

Linux

系统:Ubuntu 18.04.3 LTS
Bootstrap JDK :openJDK13
处理器:AMD® Ryzen 7 2700x eight-core processor × 16
内存:16G(8G*2)
硬盘:三星 860 EVO 512G固态硬盘
C编译环境:gcc 7.5.0

Windows

系统:Windows10 1903
Bootstrap JDK :openJDK13
UNIX环境:Windows Subsystem for Linux(Ubuntu 18)
处理器:Intel i5 7200U
内存:12G(4+8)
硬盘:建兴T11plus
C编译环境:Microsoft Visual Studio 2017 (文档要求至少update 15.9.16版本)

名词解释:
Bootstrap JDK ,是指比被编译的JDK版本号低一个版本的JDK,作为JDK源码中Java代码的编译环境,比如我要编译的是JDK14,那么就必须要使用JDK13作为Bootstrap JDK

首先下载源代码,OpenJDK官网下载地址:点击此处
先点左边的browse,然后点左边的zip、gz等打包下载。
这里网不好的话经常抽风,只能下载到1.4M左右的残缺包,有条件的建议使用梯子,或者去github上的镜像库里拉取相应版本的Release。

Linux没什么好说的,详情可以参照书里的步骤,或者源码里doc目录下的官方文档(Building the JDK),写得特别详细,按照步骤安装好工具和依赖就行了,由于官方文档里写的相当详细,这里就不赘述了,在之后的configure步骤中,如果缺失了工具,也会给予相应的提示,会直接把安装命令提示给你,可以说相当的友好了。

Windows有几点需要注意:

  • 首先是VS版本,建议按照官方的推荐版本来安装,不要看见有最新版本就装最新版,去官网下载历史版本,我曾经试过社区版2019,在准备阶段的时候,虽然显示成功,但是会提示我toolchain不是支持的版本,后果自负。

  • 安装VS的时候,在语言包那一栏,记得把中文语言包取消掉,勾选英文语言包,并把操作系统的区域改成英语,这点很重要!大部分Windows下编译失败的原因都是因为字符集的问题,在一些单元测试和log输出里输出了乱码,导致编译失败的。
    操作系统中的区域设置

  • JDK源码的存放路径,以及BootStrapJDK的路径,都最好不要包含空格。

  • 推荐使用WSL作为UNIX环境,可以很方便的同时编译Linux和Windows版本,香得不行。
    image.png

  • 有些还一直在专研JDK8的小伙伴们可能还不清楚,从JDK10开始,JDK和JRE就合并到一起了,所以不要费尽心思的去配ClassPath和JRE_HOME给自己添麻烦了,path里面配个%JAVA_HOME%\bin就行,当然个人是比较建议在后面的configure参数里面手动指定Bootstrap JDK比较好一些。

做好上述准备后,在WSL中安装工具链,和Linux步骤相同。

编译

进入jdk源码文件夹,运行

bash configure --enable-debug --with-jvm-variants=server  --with-boot-jdk=/mnt/c/jdk-13.0.2

这里是为了校验并配置编译环境,这一步没有成功的话,编译是无法正常进行的。
部分参数解释:

--enable-debug:等效于--with-debug-level=fastdebug,编译fastbug级别的JDK

--with-jvm-variants:编译特定模式(Variants)的HotSpot虚拟机,可以多个模式并存,可选值为server、client、minimal、core、zero、custom。

--with-boot-jdk:指定Bootstrap JDK路径,如果在WSL中,本机的硬盘是挂载在/mnt下的,路径中不允许出现空格!

如果是想在WSL中编译Linux版本的JDK,需要指定一个Linux版的Bootstrap JDK,运行如下指令:

bash configure --enable-debug --with-jvm-variants=server --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu --with-boot-jdk=/mnt/c/jdk-13.0.2

执行后会有个这样的提示:

Warning: You are using legacy autoconf cross-compilation flags.
It is recommended that you use --openjdk-target instead.

上面那两个用于指定交叉编译的参数已经过时了,官方现在推荐用 --openjdk-target 替代。不过我看了文档后发现这个参数也是自动设置了另外两个参数,区别不大,感兴趣的同学可以自己尝试一下。

其余的参数,可以运行 bash configure --help 进行了解

执行成功后,你应该看见如下提示:

image.png
在WSL中编译Linux版本的JDK时,会有如下提示,说你源码不在本地磁盘,可能会影响编译效率,这个可以无视它,毕竟只要编译通过了就万事大吉了,不缺这点时间。
image.png

最后再提醒一次,确保自己的系统语言为英文!建议进入powershell中运行bash,此时你应该能看见,powershell的提示变为了英文,如果还是中文,说明语言没有设置正确。

运行 make images开始编译。
注意,如果编译途中,因为出现异常而编译中断,在下次编译前,需要运行make cleanmake dist-clean清理上次编译的临时文件,并重新configure

如果一切正常的话,按照我Linux环境中电脑的配置,16核心全速运转,大概三分钟左右就编译完了。在WSL环境中,速度会慢一些,由于这个环境电脑配置本身就低,编译了半个小时。

编译成功后,以linux环境为例,在源码的build/linux-x86_64-server-fastdebug/images/jdk目录中,可以看到编译后的jdk。此时可以运行version命令,简单检验编译结果

./bin/java -version

openjdk version "14-internal" 2020-03-17
OpenJDK Runtime Environment (fastdebug build 14-internal+0-adhoc.lain.jdk14-6c954123ee8d)
OpenJDK 64-Bit Server VM (fastdebug build 14-internal+0-adhoc.lain.jdk14-6c954123ee8d, mixed mode)

至此,编译成功,在之后的学习中,就可以通过调整configure编译参数,编译自己想要的JDK功能,开启JVM之旅了!