手把手编译自己的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编译依赖库及对应的安装命令:
工具 | 库名称 | 安装命令 |
---|---|---|
FreeType | The Free Type Project | sudo yum install freetype-devel |
CUPS | Common UNIX Printing System | sudo yum install cups-devel |
X11 | X Window System | sudo yum install libXtst-devel libXt-devel libXrender-devel libXrandr-devel libXi-devel |
ALSA | Advanced Linux Sound Architecture | sudo yum install alsa-lib-devel |
libffi | Portable Foreign Function Interface Library | sudo yum install libffi-devel |
Autoconf | Extensible Package of M4 Macros | sudo yum install autoconf |
以上是用yum安装的方式进行安装,相当方便快捷,但我们也可以用源码的方式进行安装。下面仅以安装FreeType作为示例:
(1)先从FreeType官网(download.savannah.gnu.org/releases/fr… 下载获取源码包。
(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的资源文件。
引导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)。
- 查看本机的JDK
rpm -qa |grep java rpm -qa |grep jdk rpm -qa |grep gcj
- 批量卸载所有带有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
在运行配置时,可能还会要求安装其他依赖库(如下图),按照信息安装即可。
配置成功
运行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已经出来了~