手把手编译自己的JDK

344 阅读5分钟

手把手编译自己的JDK

Hello,大家好,这里是KenjiTalk,共同学习,共同成长,可关注本公众号 ~~

—— 专注后台开发工作学习总结分享

前言

《重学JVM》系列是本公众号连载的第一个系列,本篇文章也是这系列的第一篇文章。《重学JVM》不是简单入门的系列,是笔者学习《深入理解Java虚拟机》和其他有关JVM的资料后学习总结的系列,是入门后再重新怀着空杯心态学习的总结。Stay hungry, Stay foolish ~

背景

想要了解Java虚拟机内部的实现原理,最直接的方式是编译一套自己的JDK,通过阅读和跟踪调试JDK源码来了解Java技术体系的运行。在学习周志明的《深入理解Java虚拟机》的时候,发现作者用的是Ubuntu系统进行构建和作了较为简要的说明,而读者再进行自己的实操时,难免遇到一个又一个的坑点,因此笔者本次文章就生产环境出场率更高的CentOS 7平台进行构建JDK12,并作出详尽的步骤说明。

配置编译环境

获取JDK源码

有两种方式:

(1)通过Mercurial代码版本管理工具从Repository(hg.openjdk.java.net/jdk/jdk12) 中直接取得源码。

hg clone https://hg.openjdk.java.net/jdk/jdk12

(2)访问仓库(hg.openjdk.java.net/jdk/jdk12) 页面下载打包好的源码。

本次编译的OpenJDK12选择后者的方式进行获取打包好的zip。

准备编译环境

本地编译器需求

JDK的相当部分由本地代码(Native Code)组成,这些代码需要编译才能运行。

下表是官方给出的操作系统和对应支持的本地编译器:

JDK12在Linux系统接受使用GCC编译最低的版本是4.8,官方推荐使用GCC7.3.0。 在CentOS系统上安装gcc、c++编译器以及内核文件的命令是:

sudo yum -y install gcc gcc-c++ kernel-devel

其他依赖库需求

OpenJDK编译依赖库及对应的安装命令:

工具库名称安装命令
FreeTypeThe Free Type Projectsudo yum install freetype-devel
CUPSCommon UNIX Printing Systemsudo yum install cups-devel
X11X Window Systemsudo yum install libXtst-devel libXt-devel libXrender-devel libXrandr-devel libXi-devel
ALSAAdvanced Linux Sound Architecturesudo yum install alsa-lib-devel
libffiPortable Foreign Function Interface Librarysudo yum install libffi-devel
AutoconfExtensible Package of M4 Macrossudo yum install autoconf

以上是用yum安装的方式进行安装,相当方便快捷,但我们也可以用源码的方式进行安装。下面仅以安装FreeType作为示例:

(1)先从FreeType官网(download.savannah.gnu.org/releases/fr… 下载获取源码包。

image.png (2)上传到Linux系统,进行解压。 tar -xvf freetype-2.11.0.tar.gz

源码的安装一般由3个步骤组成:配置(configure)、编译(make)、安装(make install)

配置资源路径(--prefix):/usr/local/freetype

其中--prefix选项是配置安装的路径,

如果不配置该选项,安装后

  • 可执行文件默认放在/usr/local/bin
  • 库文件默认放在/usr/local/lib
  • 配置文件默认放在/usr/local/etc
  • 其它的资源文件放在/usr/local/share

因此会比较凌乱,所以本次指定安装资源文件到/usr/local/freetype路径下

配置编译及安装命令如下:

./configure --prefix=/usr/local/freetype && make && make install

完成编译安装后,在/usr/local/freetype路径下会出现FreeType的资源文件。

image.png


引导JDK(boot JDK)需求

构建JDK需求一个预存的JDK,这个JDK官方称为“boot JDK”,boot JDK必须至少是N-1的版本。因为OpenJDK由多个部分(HotSpot、JDK类库、JAXWS、JAXP......)构成,其他一部分(HotSpot)代码是使用C,C++编写,而更多的代码是使用Java语言实现,因此编译这些Java代码需要用到另一个编译期可用的引导JDK(boot JDK)。

  1. 查看本机的JDK

rpm -qa |grep java rpm -qa |grep jdk rpm -qa |grep gcj

  1. 批量卸载所有带有Java的文件

rpm -qa | grep java | xargs rpm -e --nodeps

3)JDK12需要的boot JDK只能是JDK11或者JDK12。因为要用到JDK11的javac做编译,所以我们下载java-11-openjdk-devel

yum install java-11-openjdk-devel

进行编译

运行配置

完成编译环境的准备后,来到构建JDK的最核心的阶段,运行配置(Running Configure)。在这阶段可以带着自己的需求(如可调试,定制化等)进行编译自己的JDK。 可以用“bash configure”加参数命令进行配置。

bash configure [options]

其中部分参数说明如下:

  • --enable-debug:设置调试等级为fastdebug,相当于--with-debug-level=fastdebug
  • --with-debug-level= :设置调试等级,默认release,可以设为release, fastdebug, slowdebug or optimized
  • -with-jvm-variants=[,...]:设置构建Hotspot的特定模式(可多个),可设为server, client, minimal, core, zero, custom

查看configure的所有参数可运行:

bash configure --help

在运行“bash configure”命令后有几个需要注意的地方:

  • 如果之前配置必需的依赖库在配置过程中没有检测到时,那么需要提供路径进行指定。 有两种方式进行指定:
//第一种方式
--with-<LIB>=<path>
//第二种方式
--with-<LIB>-include=<path to include> --with-<LIB>-lib=<path to lib>
  • 如果之前配置的引导JDK(boot JDK)在配置过程中没有检测到时,那么需要提供路径进行指定。 使用如下参数进行指定boot JDK

--with-boot-jdk

运行配置

bash configure --enable-debug --with-jvm-variants=server --with-boot-jdk=/usr/lib/jvm/java-11-openjdk-11.0.13.0.8-1.el7_9.x86_64

在运行配置时,可能还会要求安装其他依赖库(如下图),按照信息安装即可。

image.png

配置成功

运行Make

make

不带参数只运行make,相当于运行“make default”或者“make jdk”,将构建一系列的编译镜像,这些镜像将放在$BUILD/jdk。

“make”命令的部分参数:

  • hotspot:只编译HotSpot虚拟机
  • images or product-images:构建JDK镜像
  • dist-clean:移除所有文件,包含之前的configuration

测试编译后的JDK

刚刚提过编译后的镜像会存放在$BUILD/jdk,进入该目录

cd /usr/local/jdk12/build/linux-x86_64-server-fastdebug/images/jdk/bin 

查看Java version

./java -version

一个属于自己编译,可调试的JDK已经出来了~