本文内容过于硬核,建议有 Java 相关经验人士阅读。
1 引言
从上周开始一直在看周志明的 「深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)」 ,好多年之前看过第二版的,绝对算的上是国内 JVM 领域的经典之作,值得多读几遍。
全书的开头就介绍了如何自己编译一次 JDK ,之前看书的时候直接跳过了,一直都没自己操作过,上周读到这里的时候突然萌生了实践的念头,说搞就搞。
首先我这次选用的 OpenJDK ,而不是 OracleJDK , OracleJDK 会有一些独立的商业特性,而这些商业特性都不是开源的,所以只能选择 OpenJDK 。
在开始编译之前,我也查看了很多网上的资料,所有的资料都建议我在基于 Unix 的系统上进行编译,也就是 Linux 或者是 MacOS ,但我就是头铁,上周在 Windows10 上从早晨 9 点搞到 12 点也没搞定,所以我投降了。
由于囊中羞涩等原因,手头上也没有 Mac 电脑,只能把目光瞄向了 Linux 。
一般这种时候可供选择的发行版要么是 CentOS 要么是 Ubuntu ,后来偶然看到有人推荐国产的 Linux 桌面版 deepin ,然后在自己电脑上切了 128G 的空间出来做了个双系统,正好在试用这款操作系统的同时尝试下编译 OpenJDK 。
2 OpenJDK 源码
首先我使用的是 deepin20 社区版。
编译目标是 OpenJDK14 ,也是目前最新的 JDK 版本。
OpenJDK 的源码是使用 Mercurial 代码版本管理工具进行管理,可以直接从 Repository 中获取源码:
hg clone https://hg.openjdk.java.net/jdk/jdk14
但是这么干吧,在国内搞实在是太慢了,不做某些网络相关设置的话,等这个全都 clone 下来,基本上要一上午时间,所以不推荐这么干,可以直接访问代码仓库,使用 zip 下载的方式直接下载代码包。
直接访问 https://hg.openjdk.java.net/jdk/jdk14/ ,点击左边的 browse
,然后再点击左边的 zip
按钮进行下载,我这里取到的下载地址是:
https://hg.openjdk.java.net/jdk/jdk14/archive/6c954123ee8d.zip
不知道这个下载地址是否长期可用,先放着吧。
等这个 zip 压缩包下载完成后,我就完成第一步了,得到了 OpenJDK14 的源码包,在这个源码包下有一个 doc 的目录,里面有一个 building.html
,这个文件实际上编译的指导手册,当编译出现问题的时候可以去这个手册里面查找解决方案。
3 环境准备
编译 JDK14 需要一个叫做 BootJDK 的东西,这个其实就是目标 JDK 的上一个 JDK 版本,比如我们要编译 JDK14 ,那么本地就需要有一个 JDK13 的环境,所以第一件事情是在本地安装 JDK13 ,下载地址:
http://jdk.java.net/java-se-ri/13
下载完成后解压,修改环境变量的配置, deepin 系统的环境变量在用户目录的 .bashrc
中,因为我这个是桌面版的系统,直接使用 VSCode 在文件的最后配置上 JDK13 的环境变量:
export JAVA_HOME=/home/用户名/Java/jdk-13
export CLASSPATH=${JAVA_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
然后在命令行 terminal 中刷新一下这个配置文件:
source /home/用户名/.bashrc
这时输入经典的命令 java -version
看下版本信息:
openjdk version "13" 2019-09-17
OpenJDK Runtime Environment (build 13+33)
OpenJDK 64-Bit Server VM (build 13+33, mixed mode, sharing)
接着开始安装各种环境,为编译做准备,因为要装的软件属实有点多,我把命令整理出来都放在下面了:
sudo apt-get install build-essentail -y
sudo apt-get install libfreetype6-dev -y
sudo apt-get install libcups2-dev -y
sudo apt-get install libfontconfig1-dev -y
sudo apt-get install libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev -y
sudo apt-get install libasound2-dev -y
sudo apt-get install libffi-dev -y
sudo apt-get install autoconf -y
安装的时候如果当前用户是 root ,则不需要加最前面的 sudo ,如果不是 root 要记得加 sudo ,我是习惯打开 terminal 先把用户切换成 root 。
然后准备工作就完成了,不过有一点需要注意,执行完上面的命令后请检查 gcc 的版本,因为在我们下载下来的源码包的文档中已经明确的指出了 gcc 的版本限制,如果不在这个版本中十分有可能造成编译失败。
# 输入
gcc --version
# 输出
gcc (Uos 8.3.0.3-3+rebuild) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
OpenJDK14 要求的 gcc 的版本是 8.3.0 ,这个请注意,否则将会出现编译检查可以通过,但是打包镜像会失败的情况(我之前在 Ubuntu 虚拟机上做实验的时候遇到过)。
这一段的含义是要求我们使用 gcc 的版本在 4.8 到 8.3 之间,越接近 8.3 越接近成功,言外之意就是我们最好使用 8.3 ,否则极有可能会失败。
到此为止,我们的编译环境就准备完毕了,接下来可以开始进行编译了。
4 编译进行时
首先我们进入刚才准备好的 OpenJDK14 源码包的根目录,第一步是使用 configure
命令进行编译检查。
configure 命令承担了依赖项检查、参数配置和构建输出目录结构等多项职责,如果编译过程中需要的工具链或者依赖项有缺失,命令执行后将会得到明确的提示,并且给出该依赖的安装命令。
我使用下面这个命令进行编译检查:
bash configure --enable-debug --with-jvm-variants=server
这个命令的含义是编译 FastDebug 版、仅含 Server 模式的 HotSpot 虚拟机。
configure 命令有很多其他的参数,我就不抄书往出列了,有想知道的朋友欢迎看书或者使用命令 bash configure --help
进行查看。
接下来我们输入上面的那个编译检查命令,如果检查通过了会打印以下信息:
这里输出了一些信息,包括调试级别,Java虚拟机的模式、特性,使用的编译器版本等配置摘要信息。
接下来到了激动人心的时刻,最后一个命令实际上非常简单, make images
,执行这个命令后,我们就真正开始了 OpenJDK 编译的过程。
接下来能做的就是喝杯茶。。。
再喝杯茶。。。
再喝杯茶。。。
。。。
直到第 N 杯茶以后,编译成功了。
我使用的是台式机,16G 内存,CPU 酷睿 i7-8700 物理 6 核虚拟 12核,首次全量编译耗时在 8 分钟左右。
如果是全量编译过,只是修改后做增量编译,这个会快很多,在书中是说可以在 10s 内编译完成。这个我没试过,没有话语权。
编译成功后我的 OpenJDK14 在 build/linux-x86_64-server-fastdebug/jdk
这个目录下,然后修改下系统的环境 Java 环境变量,改成我刚编译的这个 OpenJDK ,再使用命令查看下版本:
# 输入
java -version
# 输出
openjdk version "14-internal" 2020-03-17
OpenJDK Runtime Environment (fastdebug build 14-internal+0-adhoc.weishiyao.jdk14-6c954123ee8d)
OpenJDK 64-Bit Server VM (fastdebug build 14-internal+0-adhoc.weishiyao.jdk14-6c954123ee8d, mixed mode)
可以看到,系统的 jdk 已经变成了我刚才自己编译的版本,连名字都变成了我的机器名,接下来我就可以自己使用自己编译的 jdk 了,还是蛮有成就感的。