好奇害死羊
很多小伙伴们做 Java
开发,天天写 Java
代码,必定离不开 Java
根底环境:JDK
,毕竟咱们写好的 Java
代码也是跑在 JVM
虚拟机上。
一般来说,咱们学 Java
之前,第一步就是装置 JDK
环境。这个简略啊,咱们个别间接把 JDK
从官网下载下来,装置实现,配个环境变量就能够欢快地应用了。
不过话说回来,对于这个天天应用的货色,咱们难道不好奇这玩意儿它到底是怎么由源码编译进去的吗?
带着这个原始的疑难,明天筹备大干一场,本人动动呆萌的小手,来编译一个属于本人的 JDK
吧!
对了,本文在开源我的项目:https://github.com/hansonwang99/JavaCollection 中已收录,蕴含自学编程路线、面试题汇合 / 面经、及系列技术文章等,资源继续更新中 …
还有个待填的坑
记得之前不是出过一期对于《JDK 源码浏览环境搭建》相干的视频以及文章嘛,仔细的小伙伴,可能会发现一个 很理论的问题:
咱们将
src.zip
包里的JDK
源码解压进去,关联到这份源码之后,调试时是能够进,然而咱们在加正文的时候却只能在 行尾增加 ,并不能扭转原代码的行构造。换句话说,如果在源码中加了跨行的多行正文,则debug
调试的时候就会呈现以后行的 运行错位 问题,这个有点难堪了。
当然那个视频的评论区,确实也有几个小伙伴提了这个问题:
起因也很简略,因为理论撑持调试运行的代码,并不是咱们解压进去的那份 JDK
源码,那个仅仅是做关联用,理论运行用到的 JDK
,还是之前零碎装置好的那个JDK
环境。
要想解决这个问题,那就只能应用本人批改过的代码来 自行编译生成 本人的JDK
,而后用到我的项目中去!
所以什么都憋说了,肝就完了!
环境筹备
首选说在后面的是,编译前的软件版本关系极其重要,本人在踩坑时,所呈现的各种奇奇怪怪的问题简直都和这个无关,起初版本匹配之后,就十分顺利了。
咱们来 盘点和梳理 一下编译一个 JDK 须要哪些环境和工具:
1、boot JDK
咱们要想编译JDK
,首先本人本机必须提前曾经装置有一个JDK
,官网称之为bootstrap JDK
(或者称为boot JDK
)。
比方想编译 JDK 8
,那本机必须最起码得有一个JDK 7
或者更新一点的版本;你想编译 JDK 11
,那就要求本机必须装有JDK 10
或者11
。
所以鸡生蛋、蛋生鸡又来了 …
2、Unix 环境
编译 JDK
须要 Unix
环境的反对!
这一点在 Linux
操作系统和 macOS
操作系统上曾经人造的保障了,而对于 Windows
兄弟来说略微麻烦一点,须要通过应用 Cygwin
或者 MinGW/MSYS
这种软件来模仿。
就像官网所说:在 Linux
平台编译 JDK
个别问题起码,容易胜利;macOS
次之;Windows
上则须要略微多花点精力,问题可能也多一些。
究其实质起因,还是因为 Windows
毕竟不是一个 Unix-Like
内核的零碎,毕竟很多软件的原始编译都离不开Unix Toolkit
,所以绝对必定要麻烦一些。
3、编译器 / 编译工具链
JDK
底层源码(尤其 JVM
虚拟机局部)很多都是 C++/C
写的,所以相干编译器也跑不掉。
一图胜千言,各平台上的编译器反对如下表所示,按平台抉择即可:
4、其余工具
典型的比方:
-
Autoconf
:软件源码包的主动配置工具 -
Make
:编译构建工具 -
freetype
:一个收费的渲染库,JDK
图形化局部的代码可能会用它
好,环境盘点就到这里,接下来具体列一下我在编译 JDK 8
和JDK 11
时别离用到的软件具体版本信息:
编译 JDK 8 时:
-
操作系统
:macOS 10.11.6 -
boot JDK
:JDK 1.8.0 (build 1.8.0_201-b09) -
Xcode 版本
:8.2 -
编译器
:Version 8.0.0 (at /usr/bin/clang)
编译 JDK 11 时:
-
操作系统
:macOS 10.15.4 -
boot JDK
:JDK 11.0.7 (build 11.0.7+8-LTS) -
Xcode 版本
:11.5 -
编译器
:Version 11.0.3 (at /usr/bin/clang)
大家在编译时如果过程中有很多问题,大概率少软件没装,或者软件版本不匹配,不要轻易放弃,须要急躁自查一下。
下载 JDK 源码
下载 JDK
源码其实有两种形式。
形式一:通过 Mercurial 工具下载
Mercurial
能够了解为和 Git
一样,是另外一种代码管理工具,装置好之后就有一个 hg
命令可用。
而 OpenJDK
的源码曾经提前托管到http://hg.openjdk.java.net/
。
因而,比方下载 JDK 8
,可间接hg clone
一下就行,和 git clone
一样:
`hg clone http://hg.openjdk.java.net/jd…
`
同理,下载JDK 11
:
`hg clone http://hg.openjdk.java.net/jd…
`
然而这种形式下载速度不是很快。
形式二:间接下载打包好的源码包
下载地址:https://jdk.java.net/
抉择你想要的版本下载即可。
编译前的主动配置
源码包下载好,放到本地某个目录(倡议门路纯英文,防止不必要的麻烦),解压之,而后进入源码根目录,执行:
`sh configure
`
当然这里运行的是默认配置项。
这一步会进行一系列的主动配置工作,工夫个别很快,最终如果能呈现一下提醒,那么很侥幸,编译前的配置工作就实现了!
这里我给出我本人别离在配置 JDK 11
和JDK 8
时候实现时的样子:
配置 JDK 8 实现:
配置 JDK 11 实现:
注: 如果这一步出错,大概率是某个软件环境未装,或者即便装了,但版本不匹配,控制台打印日志里个别是会揭示的。
比方我在配置 JDK 8
的时候,就遇到了一个 errof:GCC compiler is required
的问题:
明明零碎里曾经有编译器,但还是报这个谬误。通过起初批改 jdk 源码根目录 /common/autoconf/generated-configure.sh
文件,将相干的两行代码正文后就配置通过了
配置实现,接下来开始执行真正的编译动作了!
真正的编译动作
咱们这里进行的是全量编译,间接在咱们下载的 JDK
源码根目录下执行如下命令即可:
`make all
`
这一步编译须要一点工夫,急躁期待一下即可。编译过程如果有谬误,会终止编译,如果能看到如下两个画面,那么则祝贺你,本人编译 JDK
源码就曾经通过了,能够搞一杯咖啡庆贺一下了。
JDK 8 编译实现:
JDK 11 编译实现:
从两张图的比照能够看出,编译 JDK 8
和JDK 11
实现时在输入上还是有区别的。工夫上的区别很大水平上来源于 JDK 11
的编译机配置要高不少。
验证成绩
JDK
源码编译实现之后必定会产生和输入很多产物,这也是咱们所急不可待想看到的。
因为 JDK 8
和JDK 11
的源码包组织构造并不一样,所以输入货色的内容和地位也有区别。咱们一一来盘点一下。
1、JDK 8 的编译输入
编译实现,build
目录下会生成一个 macosx-x86_64-normal-server-release
目录,所有的编译成绩均位于其中。
首先,编译进去的 Java
可执行程序能够在如下目录里找到:
jdk 源码根目录 /build/macosx-x86_64-normal-server-release/jdk/bin
进入该目录后,能够输出 ./java -version
命令验证:
其次,编译生成的成品 JDK
套装,能够在目录
`jdk 源码根目录 /build/macosx-x86_64-normal-server-release/images
`
下找到,如图所示:
其中:
-
j2sdk-image
:编译生成的 JDK -
j2re-image
:编译生成的 JRE
进入 j2sdk-image
目录会发现,外面的内容和咱们平时从网络上下载的成品 JDK
内容统一。
2、JDK 11 的编译输入
JDK 11 的源码目录组织形式和 JDK 8 自身就有区别,编译生成的产物和下面编译 JDK 8 的输入有肯定区别,但也不大。
JDK 11
编译实现,同样在 build
目录下会生成一个 macosx-x86_64-normal-server-release
目录,所有的编译成绩均位于其中。
同样编译进去的 Java 可执行程序能够在目录
JDK 源码根目录 /build/macosx-x86_64-normal-server-release/jdk/bin
下看到,进入该目录后,也能够输出 ./java -version
命令验证:
其次,编译生成的成品 JDK 11
套装,能够在目录
`JDK 源码根目录 /build/macosx-x86_64-normal-server-release/images
`
下找到,如图所示:
其中 jdk
目录就是编译生成的成品 JDK 11
套装。
应用本人编译的 JDK
既然咱们曾经入手编译出了 JDK
成品,接下来咱们得用上哇。
新建一个最最根本的 Java
工程,比方命名为 JdkTest
,目标是把咱们本人编译出的JDK
给用上。
咱们点开 Project Structure
,选到SDKs
选项,新增加上本人刚刚编译生成的 JDK,并选为我的项目的 JDK,看看是否能失常工作
点击确定之后,咱们运行之:
能够看到咱们本人编译出的 JDK 曾经用上了。
关联 JDK 源码并批改
咱们持续在上一步 JdkTest
我的项目的 Project Structure
→ SDKs
里将 JDK
源码关联到自行下载的 JDK 源码门路上:
这样不便咱们对本人下载的 JDK 源码
进行 浏览 、 调试 、 批改 、以及在源码里随便 做笔记 和加正文。
举个最简略的例子,比方咱们关上 System.out.println()
这个函数的底层源码:
咱们轻易给它批改一下,加两行简略的标记,像这样:
为了使咱们新加的代码行失效,咱们必须要从新去 JDK 源码的根目录中再次执行 make images
从新编译生成 JDK 方可失效:
因为之前曾经全量编译过了,所以再次 make
的时候增量编译个别很快。
从新编译之后,咱们再次运行 JdkTest
我的项目,就能够看到改变的成果了:
多行正文的问题
记得之前搭建《JDK 源码浏览环境》时,大家可能发现了一个问题:浏览源码嘛,给源代码做点正文或笔记很常见!但那时候有个问题就是做正文时 不可扭转代码的行构造 (只能行尾正文,不能跨行正文),否则 debug 调试时会呈现 行号错位 的问题。
起因很简略,因为咱们尽管做了源代码目录的映射,然而理论撑持运行的 JDK
还是事后装置好的那个 JDK 环境,并不是依据咱们批改后的源码来从新编译构建的,所以看到这里,解决这个问题就很简略,就像下面一样自行编译一下 JDK
即可。
理论在试验时,还有一个很典型的问题是,当增加了多行的中文正文后,再编译竟然会报错!
比方,还是以下面例子中最简略的 System.out.println()
源码为例,咱们增加几行中文正文:
这时候咱们去 JDK 源码目录下编译会发现满屏相似这样的报错:
谬误: 编码 ascii 的不可映射字符
登时有点懵,毕竟仅仅是加了几行正文。对于咱们来说,源码里写点多行的中文正文根本是 刚需,然而编译竟会报错,这还能不能让人欢快的游玩了 … 过后后背有点发凉。
实不相瞒,就这个问题排查了一段时间,熬到了很晚。最终折腾了一番,通过如下这种形式解决了,顺便分享给小伙伴们,大家如果遇到了这个问题,能够参考着解决一下。
因为从控制台的报错能够很显著的看出,必定是字符编码相干的问题导致的,而且都指向了 ascii
这种编码方式。
于是将 JDK 的源码从根目录导入了 Vs Code,而后全目录查找 encoding ascii
相干的内容,看看有没有什么端倪,后果发现
jdk 源码根目录 /make/common/SetupJavaCompilers.gmk
文件中有两处指定了 ascii
相干的编码方式:
于是尝试将这两处 -encoding ascii
的均替换成-encoding utf-8
:
而后再次执行 make images
编译,编译顺利通过!
至此功败垂成!
这样前面不论是 浏览 、 调试 还是 定制 JDK
源码都十分不便了。
后记:这篇文章在开源我的项目:https://github.com/hansonwang99/JavaCollection 中也曾经收录了,蕴含自学编程路线、面试题汇合 / 面经、及系列技术文章等,资源继续更新中 …
每天提高一点点
慢一点能力更快