# 为什么编译可调式的OpenJdk源码
学习一段时间JAVA之后,关于Java方面的知识总还能找到解决办法,但是一旦涉及到虚拟机,有的时候就茫然无头绪,不知道如何去解决,此时就需要一个可调试的虚拟机代码。同时想要更好的了解虚拟机原理,自己编译一个可debug的JVM则必不可少,本文就是介绍在mac上自己编译一个JVM。
## 为什么要用mac去编译?
因为jvm源码比较复杂,有一系列的运行环境依赖,所以在mac上更容易去获取这些依赖。
# 前人蹚过的坑
不要编译JDK 8: 因为编译JDK 8需要Xcode 4现在Xcode版本已远高于4了(这个坑是前人蹚出来的,当然我不信邪,然后自己蹚了一遍,然后发现确实是个坑)
尽量不要使用Mercurial来下Open JDK的源码,而用浏览器直接下载打包好的源码: 因为你要用Mercurial下载了Open JDK的顶层工程后,还需要执行其中的get_source.sh来下载其子工程的源码,这个过程漫长而且失败率高(关键还没有执行百分比提示,干等),用浏览器自己下载所有子工程的压缩包要快很多,而且成功率100%(我自己蹚出来的,前人的几篇文章中全告诉我用Mercurial,结果坑了)
编译JDK 9u而不是JDK 9因为我当时编译9的时候出了一堆error,所以我想带个u的是不是会好些,当然这个有很大程度是我臆测的,我后期就都拿9u搞了,没试9,如果各位有兴趣可以自己蹚蹚这个
configure的时候一定要带上–disable-warnings-as-errors这个参数,否则编译过程中的warning也会中断编译的进程,实际上这些warning并不影响编译后的目标JDK的运行
# 环境描述
官方安装环境,强烈建议尽量贴近官方提供的环境,否则可能编译失败
https://wiki.openjdk.java.net/display/Build/Supported+Build+Platforms
系统:MacOS High Sierra 10.13.6
Boot JDK:1.8.0_221
Freetype:2.10
XCode CommandLineTools
# 源码位置
openjdk是托管在 Mercurial hg(类似于git的代码管理软件) 上的,因此打开openjdk官网,找到Source Code的Mercurial Bundles即可,具体位置:http://hg.openjdk.java.net/jdk9
# 开始前准备
下载完源码后,开始编译之前,请仔细阅读README,文档在下载的源码中 common/doc/building.html
# 环境准备
## 1.Boot JDK安装
编译jdk需要预先安装版本至少为N-1的JDK,这个jdk官方成为Boot JDK,比如安装openjdk9,则需要安装的jdk版本至少为jdk8。因为jdk源码里面有不少工具是java编写的,所以需要jdk进行编译。
## 2.ToolChain:
Command Line Tools 就是一个小型独立包,为mac终端用户提供了许多常用的工具,实用程序和编译器。包括svn,git,make,GCC,clang,perl,size,strip,strings,libtool,cpp,what以及其他很多能够在Linux默认安装中找到的有用的命令。
因为jdk底层用cpp编写的,所以需要安装cpp的环境,推荐安装!
- 安装xcode command line tools
- xcode-select --install
实际安装目录:/Library/Developer/CommandLineTools/,可用命令都在目录下的 usr/bin 中
各个系统需要的toolchain不一样,官方说明如下:
Linux:gcc,
macOS:Apple Xcode (using clang)
Solaris:Oracle Solaris Studio
AIX:IBM XL C/C++
Windows:Microsoft Visual Studio
## 3.安装brew:
mac(或linux)上常用的软件下载安装工具,类似Linux的apt-get,如果没有安装,[点这里参考官网](https://brew.sh/index_zh-cn.html)。
## 4.安装Mercurial hg:
hg是openjdk提供的仓库管理工具,类似git
## 5.安装ccache:
ccache:compiler cache,就是把已编译内容进行缓存,不用每次都需要对openjdk进行。支持gcc、Clang和其他相似编译器
## 6.安装freetype:
openjdk依赖于freetype
```shell
# 安装brew
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
# 安装hg
$ brew install mercurial
# 安装ccache
$ brew install ccache
# 安装freetype
$ brew install freetype
```
# 具体编译流程
```shell
$ hg clone http://hg.openjdk.java.net/jdk9/jdk9 jdk9 # 1.下载初始包
$ cd jdk9 # 进入目录
$ bash get_source.sh # 2.下载全部源代码【如果慢的话,挂代理,或者多试几次】
$ bash configure # 3.configure 以默认参数配置编译环境,若编译报错,需要添加 `--disable-warnings-as-errors`
$ make images # 4.编译 OpenJDK
```
接下来按照流程进行尝试
## 1.下载初始包和全部源代码
如果运行 bash get_source.sh 时出现类似以下错误,是网络问题造成,多运行几次 bash get_source.sh,直到不出现错误为止。
若不想使用 hg clone 加 get_source.sh 下载全部源代码,可以从 OpenJDK 的 github 镜像(非官方)下载:
```shell
$ git clone -b jdk9/jdk9 https://github.com/dmlloyd/openjdk.git
```
## 2.配置编译环境
```shell
$ bash configure --with-target-bits=64 --with-freetype=/usr/local/Cellar/freetype/2.10.1 --enable-ccache --with-jvm-variants=server,client --with-boot-jdk-jvmargs="-Xlint:deprecation -Xlint:unchecked" --disable-warnings-as-errors --with-debug-level=slowdebug 2>&1 | tee configure_mac_x64.log
```
注意:需要按照你本机按照的freetype目录和版本进行指定参数
编译参数简介:
```shell
--with-target-bits:设置32位/64位编译
--with-freetype:设置freetype路径
--enable-ccache:设置启用ccache
--with-jvm-variants=client,server:为了保证兼容性,编译时JVM的Client和Server都会被编译
--with-boot-jdk-jvmargs:提供运行Bootstrap JDK所需要的JVM参数
--disable-zip-debug-info:禁用zip调试信息
--disable-warnings-as-errors:禁用将警告当做错误,避免因为警告而中断编译
--with-debug-level:设置调试等级
2>&1 | tee configure_mac_x64.log:将错误信息重定向至标准输出,并输出到configure_mac_x64.log
```
## 关于debug调试等级
```shell
# Set the debug level
# release: no debug information, all optimizations, no asserts.
# optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
# fastdebug: debug information (-g), all optimizations, all asserts
# slowdebug: debug information (-g), no optimizations, all asserts
```
fastdebug可以而且将比release运行得慢,因为它在运行过程中会断言很多东西。启用断言是用户在怀疑jvm错误时寻求fastdebug构建的原因:在发布构建中神秘失败的内容,通常在fastdebug中有意义地断言。另外,fastdebug允许更好的调试,因为它通常带有调试符号,并且它可以访问在发布版本中不可设置的“开发”jvm标志
执行configure如果一切正常,则会输出:
```
A new configuration has been successfully created in
/Users/yanghao/openjdk/jdk9-download/jdk9/build/macosx-x86_64-normal-serverANDclient-slowdebug
using configure arguments '--with-target-bits=64 --with-freetype=/usr/local/Cellar/freetype/2.10.1 --enable-ccache --with-jvm-variants=server,client --with-boot-jdk-jvmargs='-Xlint:deprecation -Xlint:unchecked' --disable-zip-debug-info --disable-warnings-as-errors --with-debug-level=slowdebug'.
Configuration summary:
* Debug level: slowdebug
* HS debug level: debug
* JDK variant: normal
* JVM variants: server client
* OpenJDK target: OS: macosx, CPU architecture: x86, address length: 64
* Version string: 9-internal+0-adhoc.yanghao.jdk9 (9-internal)
Tools summary:
* Boot JDK: java version "1.8.0_221" Java(TM) SE Runtime Environment (build 1.8.0_221-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode) (at /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home)
* Toolchain: clang (clang/LLVM)
* C Compiler: Version 10.0.0 (at /usr/bin/clang)
* C++ Compiler: Version 10.0.0 (at /usr/bin/clang++)
Build performance summary:
* Cores to use: 4
* Memory limit: 8192 MB
* ccache status: Active (3.7.9)
NOTE: You have requested to build more than one version of the JVM, which
will result in longer build times.
The following warnings were produced. Repeated here for convenience:
WARNING: Option --enable-zip-debug-info is deprecated and will be ignored.
WARNING: Please use --with-native-debug-symbols=zipped .
```
同时会产生 build目录,下面有个macosx-x86_64-normal-serverANDclient-slowdebug 目录,后期编译的文件都存放在这里面。如果想要更换configure参数,执行以下命令进行清理configure参数:
```shell
$ make clean
$ make dist-clean
```
## 4.开始正式编译openjdk
### 关于编译错误
正式编译的时候,可能会复现几个编译错误,我完美复现了以下3个编译错误:https://iyichen.xyz/2019/10/mac-compile-openjdk/,请看【编译错误】
官方也有bug列表和解决方案:https://bugs.openjdk.java.net/browse/JDK-8187787。这是因为 XCode 带的 g++ 编译器版本在某些方面与 Hotspot 开发用的 c++ 编译器不兼容,导致有些代码用 XCode 的 g++ 编译会报错,官方使用的版本如下:
At the time of writing, OpenJDK has been successfully compiled on macOS versions up to 10.12.5 (Sierra), using XCode 8.3.2 and –disable-warnings-as-errors
按照说明修改源码,一切编译正常,所有的编译内容都存放在build/macosx-x86_64-normal-serverANDclient-slowdebug目录下。
### 编译成功
成功后测试下JDK版本
```
$ ./build/macosx-x86_64-normal-serverANDclient-slowdebug/jdk/bin/java -version
openjdk version "9-internal"
OpenJDK Runtime Environment (slowdebug build 9-internal+0-adhoc.yanghao.jdk9)
OpenJDK 64-Bit Server VM (slowdebug build 9-internal+0-adhoc.yanghao.jdk9, mixed mode)
```
阅读和调试hospot源码
我们使用 slowdebug 编译了 jdk 源代码,build 目录下会生成 java.dSYM、javac.dSYM、libjava.dylib.dSYM、libjvm.dylib.dSYM 等调试信息文件。有这些调试信息文件,就可以直接使用 gdb 或者 lldb 调试 HotSpot 了。
```
lldb java
(lldb) b main
Breakpoint 1: 19 locations.
(lldb) run
Process 6276 launched: '/Users/yulewei/jdk9/build/macosx-x86_64-normal-server-slowdebug/jdk/bin/java' (x86_64)
Process 6276 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100001813 java`main(argc=1, argv=0x00007fff5fbfef98) at main.c:98
95 {
96 int margc;
97 char** margv;
-> 98 const jboolean const_javaw = JNI_FALSE;
99 #endif /* JAVAW */
100
101 JLI_InitArgProcessing(!HAS_JAVA_ARGS, const_disable_argfile);
Target 0: (java) stopped.
(lldb) source info
Lines found in module `java
[0x0000000100001813-0x0000000100001817): /Users/yulewei/CODING/jdk9/jdk/src/java.base/share/native/launcher/main.c:98:20
```
### 使用CLion
之前Clion只支持 CMake,从2018.2版本开始对Makefile项目提供支持,具体支不支持还需要研究。这里未进行尝试
Mac上编译OpenJDK9源码