来,手把手教你编译OpenJDK源代码

从哪搞到OpenJDK的源代码?

OpenJDK的官网在这里:https://hg.openjdk.java.net/,里面可以看到不同版本的jdk分支。OpenJDK使用Mercurial来做SCM,安装好Mercurial之后可以使用如下命令克隆OpenJDK的源代码:

apt-get install -y mercurial
hg clone http://hg.openjdk.java.net/jdk8u/jdk8u/

做好心理准备,克隆的时间会很久。。。
也有人把OpenJDK的源代码放到GitHub上,譬如这个:

git clone --depth 1 -b master [email protected]:AdoptOpenJDK/openjdk-jdk8u.git

官方也有提供一些打包好的源代码zip:

wget https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-src-b04-14_jan_2020.zip

OpenJDK源代码结构

openjdk 
—— corba:多语言、分布式通讯接口 
—— hotspot:Java 虚拟机 
—— jaxp:XML 处理 
—— jaxws:一组 XML web services 的 Java API 
—— jdk:java 开发工具包 
—— —— 针对操作系统的部分 
—— —— share:与平台无关的实现 
—— langtools:Java 语言工具 
—— nashorn:JVM 上的 JavaScript 运行时

其中,hotspot 目录包含了 JVM 的实现, HotSpot VM 的实现源码位于 hotspot/src 目录,其目录结构如下所示:

├─agent                            Serviceability Agent的客户端实现
├─make                             用来build出HotSpot的各种配置文件
├─src                              HotSpot VM的源代码
│  ├─cpu                            CPU相关代码(汇编器、模板解释器、ad文件、部分runtime函数在这里实现)
│  ├─os                             操作系相关代码
│  ├─os_cpu                         操作系统+CPU的组合相关的代码
│  └─share                          平台无关的共通代码
│      ├─tools                        工具
│      │  ├─hsdis                      反汇编插件
│      │  ├─IdealGraphVisualizer       将server编译器的中间代码可视化的工具
│      │  ├─launcher                   启动程序“java”
│      │  ├─LogCompilation             将-XX:+LogCompilation输出的日志(hotspot.log)整理成更容易阅读的格式的工具
│      │  └─ProjectCreator             生成Visual Studio的project文件的工具
│      └─vm                           HotSpot VM的核心代码
│          ├─adlc                       平台描述文件(上面的cpu或os_cpu里的*.ad文件)的编译器
│          ├─asm                        汇编器接口
│          ├─c1                         client编译器(又称“C1”)
│          ├─ci                         动态编译器的公共服务/从动态编译器到VM的接口
│          ├─classfile                  类文件的处理(包括类加载和系统符号表等)
│          ├─code                       动态生成的代码的管理
│          ├─compiler                   从VM调用动态编译器的接口
│          ├─gc_implementation          GC的实现
│          │  ├─concurrentMarkSweep      Concurrent Mark Sweep GC的实现
│          │  ├─g1                       Garbage-First GC的实现(不使用老的分代式GC框架)
│          │  ├─parallelScavenge         ParallelScavenge GC的实现(server VM默认,不使用老的分代式GC框架)
│          │  ├─parNew                   ParNew GC的实现
│          │  └─shared                   GC的共通实现
│          ├─gc_interface               GC的接口
│          ├─interpreter                解释器,包括“模板解释器”(官方版在用)和“C++解释器”(官方版不在用)
│          ├─libadt                     一些抽象数据结构
│          ├─memory                     内存管理相关(老的分代式GC框架也在这里)
│          ├─oops                       HotSpot VM的对象系统的实现
│          ├─opto                       server编译器(又称“C2”或“Opto”)
│          ├─prims                      HotSpot VM的对外接口,包括部分标准库的native部分和JVMTI实现
│          ├─runtime                    运行时支持库(包括线程管理、编译器调度、锁、反射等)
│          ├─services                   主要是用来支持JMX之类的管理功能的接口
│          ├─shark                      基于LLVM的JIT编译器(官方版里没有使用)
│          └─utilities                  一些基本的工具类
└─test                             单元测试

等下,我为什么要编译OpenJDK?

如果你改了JDK的源代码,譬如加了些printf打印点东西、加了sleep模拟长gc之类的,那是不是需要重新编译一下呢?如果你想要一探JDK内部的实现机制,最便捷的路径之一就是自己编译一套JDK,通过阅读和跟踪调试JDK源码去了解Java技术体系的原理,肯定会比阅读各种技术书籍、文章更加贴近本质。而且,Linux环境下从源代码开始编译构建可执行文件,解决各种环境依赖的坑,也是一个后台开发人员最基本的工程能力的体现,不是么?

需要什么环境?

操作系统

要编译OpenJDK,首先要准备好相关的环境,参看官方的建议,这里我们以编译OpenJDK 8为例,可以选择Ubuntu 14.04来作为构建的操作系统。
在这里插入图片描述

所需的依赖

采用Docker、VirtualBox等装好Ubuntu 14.04之后,先换下你喜欢的国内源,然后使用如下命令更新和安装所需的依赖:

apt-get update && apt-get install -y curl ssh zip unzip vim ant git mercurial build-essential ccache cpio g++ gcc gdb libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libcups2-dev libfreetype6-dev libasound2-dev libelf-dev openjdk-7-jdk 

如何构建?

准备好操作系统安装好所需的依赖后,就可以把下载好的源代码拷贝到目标系统中(也可以在目标系统中拉代码)。cd进去对应的目录,执行如下命令进行构建:

chmod a+x configure && ./configure --with-debug-level=slowdebug --with-target-bits=64 && make images

如无意外,你应该会遇到这个错误:
* This OS is not supported: Linux d71054f4b5ef 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
怎么肥事!!说好的works flawlessly呢???
没关系,这个问题其实也很好办,改改Makefile告诉他Ubuntu 14.04的内核4.x也变成supported的就好:

sed -i 's/3%/3% 4%/g' hotspot/make/linux/Makefile

继续执行,然后还会碰到这个错误:
configure: error: Could not find freetype! You might be able to fix this by running 'sudo apt-get install libfreetype6-dev'. configure exiting with result code 1
libfreetype6-dev这个依赖我们已经安装过了,参考这里的建议,使用命令行指定下位置就好:

./configure --with-debug-level=slowdebug --with-target-bits=64 --with-freetype-include=/usr/include/freetype2 --with-freetype-lib=/usr/lib/x86_64-linux-gnu && make clean && make images

将debug level设置为slowdebug是为了方便debug,否则你用gdb调试的时候可能无法打断点。可选的debug level是releasefastdebugslowdebugoptimized,默认是release
构建的过程也会很久,你可以像这个哥们一样去打几盘王者,或者做做Keep运动啥的。
构建成功后,build目录下的目录结构如下:

buildtools/
configure-support/
hotspot/
images/
jdk/
make-support/
support/
test-results/
test-support/

编译后的jdk就在jdk目录中,我们进去验证下:

# build/linux-x86_64-normal-server-slowdebug/jdk/bin/java -version
openjdk version "1.8.0-internal-debug"
OpenJDK Runtime Environment (build 1.8.0-internal-debug-_2020_02_24_08_50-b00)
OpenJDK 64-Bit Server VM (build 25.40-b25-debug, mixed mode)

OK!大功告成!
为了节约大家的时间和减少重复劳动,我已经将构建的过程写成Dockerfile放到了GitHub,大家可以直接拉下来执行构建:

git clone https://github.com/lixuanbin/compile-openjdk-in-docker.git
cd compile-openjdk-in-docker/ubuntu1404_openjdk8
docker build -t ubuntu1404_openjdk8:version3 .

构建成功后进入镜像验证:

docker run -ti --entrypoint /bin/sh ubuntu1404_openjdk8:version3

也可以尝试直接使用我构建导出的镜像文件:https://pan.baidu.com/s/1sj5-cPfzoGRawXBA0ld6aQ,提取码:u9ht。
然后导入到Docker本地镜像库:

tar -zxvf ubuntu1404_openjdk8_v3.img.tar.gz
docker load < ubuntu1404_openjdk8_v3.img

参考资料

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章