阅读JDK源码最好的方式,就是编译JDK源码!然后在开发工具中用源码的方式运行,网上有很多教程,但是只有自己亲身操作过,才会知道具体是怎么样的——>纸上得来终觉浅,绝知此事要躬行👍
环境准备
ubuntu 16.04
lich@lich-virtual-machine:~/workspace$ uname -a Linux lich-virtual-machine 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
lich@lich-virtual-machine:~/workspace/openjdk8$ cat /proc/version Linux version 4.15.0-45-generic (buildd@lcy01-amd64-027) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)) #48~16.04.1-Ubuntu SMP Tue Jan 29 18:03:48 UTC 2019
最开始我是用 ubuntu 20.4 版本,但是编译过程中出现了许多奇怪的错误,所以选用的低版本的ubuntu
因为主要的目的是编译源码阅读源码,不是研究版本的兼容性问题。高版本的openJDK应该是可以的,没有测试,用openjdk8比较多,所以还是想编辑openjdk8。所以最终还是选用了低版本的ubuntu。
下载openJDK8源码
两种方式:==①利用Mercurial(hg)== ==②手动下载==
利用Mercurial(hg)
openJDK使用的代码管理工具为Mercurial(hg),下载并安装Mercurial后就可以通过hg clone命令获取openJDK8的源码了,相关的命令如下:
hg clone http://hg.openjdk.java.net/jdk8u/jdk8u openjdk8u
cd openjdk
./get_source.sh
没有hg命令需要先安装:如果失败的话可能是网络的问题,在执行一次
sudo apt-get install mercurial
实际上,执行了hg clone http://hg.openjdk.java.net/jdk8u/jdk8u openjdk8u 命令以后,执行到如下所示就卡死了,不动了~ 所以还是使用下面手动下载的方式
lich@lich-virtual-machine:~/workspace$ hg clone http://hg.openjdk.java.net/jdk8u/jdk8u openjdk8u
正在请求全部修改
正在增加修改集
正在增加清单
正在增加文件改变
files [================> ] 32/142 2m50s
手动下载
下载地址:http://jdk.java.net/ 选择需要的版本,下载即可
RI Source Code
The source code of the RI binaries is available under the [GPLv2](javascript:void(0)) in a single zip file (md5) 123 MB.
下载后得到文件:openjdk-8u41-src-b04-14_jan_2020.zip
解压文件,得到文件夹openjdk ,重命名为openjdk8
unzip openjdk-8u41-src-b04-14_jan_2020.zip
编译源代码
安装BootJDK
要编译JDK你的有个基础的JDK,所以先安装个JDK,版本小于等于我们要编译的JDK,作为引导JDK
方式一:
$ sudo add-apt-repository ppa:openjdk-r/ppa
$ sudo apt update
$ sudo apt install openjdk-7-jdk
方式二:
可以自己下载jdk然后自己配置环境变量就行了。
同样在 http://jdk.java.net/ 下载JDK7注意这次不是下载源码,是编译好的JDK7
openjdk-7u75-b13-linux-x64-18_dec_2014.tar.gz 解压后重命名为openjdk7
给JDK7配置系统环境变量,切换为root
vim /etc/profile
文件末尾追加如下:注意修改为自己JDK的路径
export JAVA_HOME=/home/lich/workspace/openjdk7
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
切换成自己的用户,配置生效
source /etc/profile
测试
lich@lich-virtual-machine:~/workspace$ java -version
java version "1.7.0_95"
OpenJDK Runtime Environment (IcedTea 2.6.4) (7u95-2.6.4-3)
OpenJDK 64-Bit Server VM (build 24.95-b01, mixed mode)
安装编译相关的依赖
看其他教程都已经把需要的依赖给列出来了,所以我们就直接安装就好了
sudo apt install \
libx11-dev \
libxext-dev \
libxrender-dev \
libxtst-dev \
libxt-dev \
libcups2-dev \
libfreetype6-dev \
libasound2-dev \
libfontconfig1-dev
依赖检查
在源码根路径下执行如下命令,检查是否还缺少其他的依赖
bash ./configure
比如我执行完毕后,后面会有提示,按照提示安装相关依赖即可
......
Build performance summary:
* Cores to use: 4
* Memory limit: 7934 MB
* ccache status: not installed (consider installing)
Build performance tip: ccache gives a tremendous speedup for C++ recompilations.
You do not have ccache installed. Try installing it.
You might be able to fix this by running 'sudo apt-get install ccache'.
安装了ccache 后出现问题: ccache status: installed, but disabled (version older than 3.1.4) 。没事不影响
Build performance summary:
* Cores to use: 4
* Memory limit: 7934 MB
* ccache status: installed, but disabled (version older than 3.1.4)
WARNING: The result of this configuration has overridden an older
configuration. You *should* run 'make clean' to make sure you get a
proper build. Failure to do so might result in strange build problems.
编译
编译前检查下
(1)设定语言选项,如果不是C那么就修改下
lich@lich-virtual-machine:~/workspace/openjdk8$ echo $LANG
zh_CN.UTF-8
修改命令:
export LANG=C
(2)执行echo $PATH
看下输出,如果没有boot JDK,则执行(注意修改为自己的路径,如果用上面打命令安装后,路径大概和我打一样)
export PATH="/usr/lib/jvm/java-7-openjdk-amd64/bin:${PATH}"
(3)检查JAVA_HOME ,可先执行echo $JAVA_HOME,看下输出,如果有值则需要unset JAVA_HOME
检查完毕后,编译使用的命令如下:
make all
相关报错:
1》编译内核问题
*** This OS is not supported: Linux lich-virtual-machine 4.15.0-45-generic #48~16.04.1-Ubuntu SMP Tue Jan 29 18:03:48 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
/home/lich/workspace/openjdk8/hotspot/make/linux/Makefile:238: recipe for target 'check_os_version' failed
make[5]: *** [check_os_version] Error 1
/home/lich/workspace/openjdk8/hotspot/make/linux/Makefile:259: recipe for target 'linux_amd64_compiler2/debug' failed
查看内核版本
lich@lich-virtual-machine:~/workspace/openjdk8$ uname -a
Linux lich-virtual-machine 4.15.0-45-generic #48~16.04.1-Ubuntu SMP Tue Jan 29 18:03:48 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
查看ubuntu版本
lich@lich-virtual-machine:~/workspace/openjdk8$ cat /proc/version
Linux version 4.15.0-45-generic (buildd@lcy01-amd64-027) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)) #48~16.04.1-Ubuntu SMP Tue Jan 29 18:03:48 UTC 2019
解决办法:
修改....../openjdk8/hotspot/make/linux/Makefile
,找到SUPPORTED_OS_VERSION
变量定义的地方,在后面追加4%
,如下所示
SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% 4%
解决完报错后,再次执行make all ,听电脑风扇一顿爆转就行了,最终如下所示:
----- Build times -------
Start 2020-07-25 10:57:00
End 2020-07-25 11:04:10
00:00:16 corba
00:00:12 demos
00:01:25 docs
00:02:48 hotspot
00:00:14 images
00:00:10 jaxp
00:00:15 jaxws
00:01:40 jdk
00:00:00 langtools
00:00:10 nashorn
00:07:10 TOTAL
-------------------------
Finished building OpenJDK for target 'all'
验证下,进入编译好的路径下 执行熟悉的 java -version
....../openjdk8/build/linux-x86_64-normal-server-release/jdk/bin
lich@lich-virtual-machine:~/workspace/openjdk8/build/linux-x86_64-normal-server-release/jdk/bin$ ./java -version
openjdk version "1.8.0-internal"
OpenJDK Runtime Environment (build 1.8.0-internal-lich_2020_07_25_10_27-b00)
OpenJDK 64-Bit Server VM (build 25.40-b25, mixed mode)
验证编译代码:
创建一个Test.java源文件,内容如下:
public class Test{ public static void main(String[] args){ System.out.println("Hello World!");}}
通过Javac编译器编译如上的源代码,得到Test.class文件,注意自己JDK的路径
/home/lich/workspace/openjdk8/build/linux-x86_64-normal-server-release/jdk/bin/javac Test.java
运行如上的Class文件,命令如下:
/home/lich/workspace/openjdk8/build/linux-x86_64-normal-server-release/jdk/bin/java Test
输出如下的信息:表示成功了
lich@lich-virtual-machine:~$ /home/lich/workspace/openjdk8/build/linux-x86_64-normal-server-release/jdk/bin/java Test
Hello World!
IDEA中使用JDK源码调试
安装IntelliJ IDEA
首先在ubuntu系统下,安装个idea
下载 https://www.jetbrains.com/idea/download/#section=linux idea
解压到opt目录
sudo tar -zxvf ideaIU-2020.1.4.tar.gz -C /opt
然后进入bin下执行idea.sh 就行了,但是每次这么用比较麻烦,所以我们需要把idea添加到启动器
先进入到applications文件夹下
cd /usr/share/applications
添加
sudo vim idea.desktop
内容如下所示,修改为自己的idea路径
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Name=IntelliJ IDEA
GenericName=Java IDE
Comment=IntelliJ IDEA is a code-centric IDE focused on developer
Exec=/opt/idea-IU-201.8743.12/bin/idea.sh
Icon=/opt/idea-IU-201.8743.12/bin/idea.png
Terminal=false
Type=Application
Categories=Development;IDE
赋予执行权限
sudo chmod +x idea.desktop
然后去软件列表找到启动器即可
使用JDK
然后在SDK中导入编译的JDK,debug配置中去掉 Before launch 中打build 然后执行测试代码
public class Main {
public static void main(String[] args) {
System.out.println("hello world");
}
}
执行结果:显示用打我们编译好的JDK
/home/lich/ideaworkspace/openjdk8-normal-server-release/jdk/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:47693,suspend=y,server=n -javaagent:/opt/idea-IU-201.8743.12/plugins/java/lib/rt/debugger-agent.jar -Dfile.encoding=UTF-8 -classpath /home/lich/ideaworkspace/openjdk8-normal-server-release/jdk/classes:/home/lich/ideaworkspace/test/out/production/test:/opt/idea-IU-201.8743.12/lib/idea_rt.jar com.org.Main
Connected to the target VM, address: '127.0.0.1:47693', transport: 'socket'
hello world
修改JDK源码
平时我们在查看源码打过程中,虽然可以通过DEBUG打断点来查看,但是有打时候不如加个打印输出更方便,所以我们可以修改源码,打造自己的JDK。
举个例子,比如我们要修改System.out.println
增加个打印前缀
我们知道println在java.io包下,我们去修改下源码,进入我们下载打源码中,然后重新make就可以了。
我们在打印字符串打时候增加一个前缀:
/**
* Prints a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>String</code> to be printed.
*/
public void println(String x) {
synchronized (this) {
print("lich:");
print(x);
newLine();
}
}
然后从新make下即可,有报错会提示,因为是增量编译,所以很快,然后再执行测试代码
public class Main {
public static void main(String[] args) {
System.out.println("hello world");
}
}
结果:
lich:hello world
至此,入门的源码编译就结束了,纸上得来终觉浅,绝知此事要躬行👍
详细见:故事的程序员-ubuntu下面编译openJDK8,修改源码IDEA中调试