实战:自己编译JDK

参考周志明老师的《深入理解Java虚拟机》第3版的第一章,自己动手实践了一下编译JDK

1.获取源码

选用OpenJDK12来编译,打开jdk版本仓库页面http://hg.openjdk.java.net/jdk/jdk12/,点击左边菜单中的"Browse"将显示源码根目录页面。

手动编译pytorch 手动编译jdk_java

点击左侧的"zip"链接即可下载当前版本打包好的源码。

手动编译pytorch 手动编译jdk_jdk_02

2.系统需求

尽量在Linux或MacOS上构建OpenJDK,这两个系统在准备构建工具链和依赖项上要比在Windows或Solaris平台上要容易许多。本次实践将以Ubuntu 18.04.05 LTS为平台进行构建。

Ubuntu 18.04.05 LTS下载地址

选择64位桌面版

手动编译pytorch 手动编译jdk_java_03

本次编译采用64位操作系统,默认参数下编译出来的也是64位的OpenJDK,如果需要编译32位版本,同样推荐在64位的操作系统上进行,理由是编译过程可以使用更大内存(32位系统受4G内存限制),通过编译参数(–with-target-bits=32)来指定需要生成32位编译结果即可。在官方文档上要求编译OpenJDK至少需要24G的内存空间,而且至少要68GB的空闲磁盘空间。

安装Ubuntu教程

3.构建编译环境

Ubuntu里用户可以自行选择安装GCC或CLang来进行编译,但必须保证最低的版本为GCC 4.8或者CLang 3.2以上,官方推荐使用GCC 7.8或者CLang 9.1来完成编译。在Ubuntu系统上安装GCC的命令为:

sudo apt-get install build-essential

手动编译pytorch 手动编译jdk_jvm_04

在编译过程中需要依赖FreeType、CUPS等若干第三方库,OpenJDK全部的依赖库已在下表列出,可执行相应的安装命令来完成安装。

工具

库名称

安装命令

FreeType

The FreeType Project

sudo apt-get install libfreetype6-dev

CUPS

Common UNIX Printing System

sudo apt-get install libcups2-dev

X11

X Window System

sudo apt-get install libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev

ALSA

Advanced Linux Sound Architecture

sudo apt-get install libasound2-dev

libffi

Portable Foreign Function Interface Library

sudo apt-get install libffi-dev

Autoconf

Extensible Package of M4 Macros

sudo apt-get install autoconf

编译大版本号为N的JDK,我们还要另外准备一个大版本号至少为N-1的、已经编译好的JDK。编译OpenJDK 12时,Bootstrap JDK必须要使用JDK11及之后的版本。在Ubuntu中使用以下命令安装OpenJDK 11:

sudo apt-get install openjdk-11-jdk

手动编译pytorch 手动编译jdk_jvm_05

4.进行编译

需要下载的编译环境和依赖项目都齐备后,我们就可以按照默认配置来开始编译了。但通常我们编译OpenJDK的目的都不仅仅是为了得到在自己机器中诞生的编译成品,而是带着调试、定制化等需求,这样就必须了解OpenJDK提供的编译参数才行,这些参数可以使用“bash configure --help"命令查询到。

手动编译pytorch 手动编译jdk_jdk_06

所有参数均通过以下形式使用:

bash configure [options]

譬如,编译FastDebug版、仅含Serve模式的HotSpot虚拟机,命令应为:

bash configure --enable-debug --with-jvm-variants=server

手动编译pytorch 手动编译jdk_jdk_07

如果编译过程中需要的工具类或者依赖项有缺失,命令执行后将会得到明确的提示,并且给出该依赖的安装命令,如我就缺少了libfontconfig1-dev,感觉是作者故意没说。

手动编译pytorch 手动编译jdk_java_08

一切顺利就会收到配置成功的提示,并且输出调试级别,Java虚拟机的模式、特性,使用的编译器版本等配置摘要信息,如下所示。

手动编译pytorch 手动编译jdk_jvm_09

依赖检测通过后便可以输入“make”执行整个OpenJDK编译了。

手动编译pytorch 手动编译jdk_java_10

如果电脑配置不高的话现在就可以去开始一把游戏或者看两集电视剧了,我只给虚拟机分配了一个核心和4GB内存,编译花了差不多40分钟。

编译完成如下所示

手动编译pytorch 手动编译jdk_手动编译pytorch_11

编译完成后进入OpenJDK源码的“build/配置名称/jdk"就可以看到OpenJDK的完整编译结果了。

编译完成后”build/配置名称“目录下结构如下图所示:

手动编译pytorch 手动编译jdk_java_12

如果多次编译,或者目录结构成功产生后又再次修改了配置,必须先使用“make clean"和”make dist-clean"命令清理目录,才能确保新的配置生效。

“build/配置名称/jdk"下目录结构如下图所示:

手动编译pytorch 手动编译jdk_jdk_13

进入“build/配置名称/jdk/bin"目录,输入以下命令验证jdk版本。

./java -version

输入如下,宣告成功。

手动编译pytorch 手动编译jdk_java_14

5.在IDE工具中进行源码调试

本次实战中,这里建议使用的IDE是JetBrian的CLion 2020.1.3及之前的版本,可以在JetBrian官网下载并免费使用30天,学生可以验证免费使用。我原本下载的是最新的CLion 2021.2,但新版本没有“New CMake Project from Sources”,我搞了半天也没能生成CMakeLists.txt,放弃了,下面是官网的说明,可以参考一下,反正我是行不通。Clion官网的说明是打开CMake项目的根目录,打开一个源文件在编辑器中,如果在顶层目录中没有CMakeLists.txt文件,CLion会建议创建一个。有弄出来的小伙伴可以指导一下。

手动编译pytorch 手动编译jdk_CL_15

CLion安装后,新建一个项目,选择“New CMake Project from Sources”,在源码文件夹中填入OpenJDK源码根目录,此时CLion已经自动选择好了需要导入的源码,如下图所示。点击OK按钮就会自动导入源码并自动创建好CMakeLists.txt文件。

手动编译pytorch 手动编译jdk_jvm_16

这份自动生成的CMakeLists.txt并不能直接使用,OpenJDK本身也没有为任何IDE提供支持,但如果只是为了能够在CLion中追踪、阅读源码,而不需要修改重新编译的话,直接在Run/Debug Configuration中增加一个CMake Application,然后Executable选择我们刚才编译出来的FastDebug的java命令,运行参数加上-version或者某个Class文件的路径,再把Before launch里面的Build去掉,就可以开始运行调试了,如下图所示。

手动编译pytorch 手动编译jdk_java_17

手动编译pytorch 手动编译jdk_CL_18

运行结果如下图所示。

手动编译pytorch 手动编译jdk_jvm_19

HotSpot虚拟机启动器的执行入口是java.c的JavaMain()方法,可以设置断点单步跟踪,如下图所示。

手动编译pytorch 手动编译jdk_CL_20

花了差不多三个下午终于做完了,中间遇到了不少困难,总算还是做完了。