左手的世界
Rise's Blog
2020年,在 Linux 下动手编译 OpenJDK 8
读深入理解 Java 虚拟机 - 经历了一天的折腾,我成功编译了 OpenJDK 8。

前言

这两天开始读深入理解 Java 虚拟机了。在这本书的第一章就提到了动手编译 OpenJDK。 突然想到 2018 年 11 月被 OpenCV 的交叉编译支配的恐惧。

网上的各种攻略琳琅满目,五花八门。

终于,在蹚了前人的那些坑之后,我成功编译了 OpenJDK 8。其实编译一个 JDK 也没那么难。

– 即使是 2020 年,在更新策略激进的 Arch 系 Linux 下,我没有降级任何软件也照样编译成功。

注:本篇文章以 Manjaro Linux 为例进行讲解。其它的 Linux 基本一致,只是软件包名不同。

准备

环境

名称 版本
OS Manjaro 20.0 Lysia
Kernel x86_64 Linux 4.19.118-1-MANJARO
make GNU Make 4.3 x86_64-pc-linux-gnu
GCC gcc (Arch Linux 9.3.0-1) 9.3.0

注:我并没有切换到低版本的 gcc。

OpenJDK 8

你需要一个 OpenJDK 8 来编译 OpenJDK 8 原代码中的 Java 代码。太高或太低都不能编译成功。

注: OpenJDK 7 理论上可以,但编译时会出问题。还是建议用 OpenJDK 8。

在 Arch Linux/Manjaro Linux 下,可以通过archlinux-java status查看是否有 OpenJDK 8。输入以下命令:

$ archlinux-java status | grep 8 
  java-8-openjdk

如果没有的话(即上面命令没有结果),赶紧去搞一个!(sudo pacman -S jdk8-openjdk

Mercurial

作为 OpenJDK 的版本管理系统,类似于 git。

在 Arch Linux 下可以通过 sudo pacman -S mercurial 安装。

(直接连接会很慢,请自行准备工具,具体工具请自行探索,支持 HTTP 代理就可以。下文会讲解如何给 mercurial 套 HTTP 代理。)

注:本篇文章中提到的所有 sudo 操作都已经特别指出,不要在 sudo 模式下进行其它操作。

GCC 和 make

这个貌似不用我多说。这个年头用 Linux 写代码,没个 gccmake 好像还是一件挺尴尬的事情。

(还是说一句:make 不是系统自带的,gcc 大多数自带,缺什么装什么。)

编译

以上的工具准备好了,就可以开始编译了。

clone

正常下载是hg clone 目标网址。如果你的网络环境不好,可以出动 HTTP 代理。下例是让 mercurial 经过 http://127.0.0.1:8000/ 处的代理:

hg --config http_proxy.host=127.0.0.1:8000 clone http://hg.openjdk.java.net/jdk8u/jdk8u/ 

get_source

如果你的网络环境不好,我们要预先定义一下代理:

export HGFOREST_GLOBALOPTS=" --config http_proxy.host=127.0.0.1:8000"

注意:在--config前有一个空格

开始吧:

chmod +x ./get_source.sh
./get_source.sh

如果中间失败,可以重复运行get_source.sh,脚本会从失败的地方继续下载。

注意:有些地方提到可以去 http://jdk.java.net/ 下载。但是我这里下载到的源代码都不能正常编译。

configure

输入以下命令开始配置工作。这里需要手动指定 Bootstrap JDK 的路径。

./configure --with-boot-jdk=/usr/lib/jvm/java-8-openjdk 

如果没有报错,那么说明你的环境配置正常。

dirty hack

我们还需要更改一下编译参数。OpenJDK 默认编译的时候会将所有 warning 视为 error,会导致以下错误:cc1plus: all warnings being treated as errors

因为 OpenJDK 8 的编译不支持 --disable-warnings-as-errors 参数,所以我们需要手动修改一下:

打开./hotspot/make/linux/makefiles/gcc.make,然后找到 WARNINGS_ARE_ERRORS =,前面加#,把这行注释掉

make

最后,可以正式编译了,分情况讨论。

注:不需要指定 CPU 核心数。默认编译就是多核。

仅编译

如果只编译,不想要二进制:输入make命令,开始编译。

当你看到以下信息时,你就成功了:

## Finished jdk (build time 00:01:43)

----- Build times -------
Start 2020-05-05 13:14:42
End   2020-05-05 13:20:26
00:00:13 corba
00:03:23 hotspot
00:00:08 jaxp
00:00:11 jaxws
00:01:43 jdk
00:00:06 langtools
00:05:44 TOTAL
-------------------------

编译二进制

如果你想编译出 JDK JRE 的那套二进制的话,请运行make images

此时结果应该是这样的:

## Finished images (build time 00:01:28)

----- Build times -------
Start 2020-05-05 19:36:50
End   2020-05-05 19:38:49
00:00:00 corba
00:00:16 demos
00:00:00 hotspot
00:01:28 images
00:00:01 jaxp
00:00:00 jaxws
00:00:05 jdk
00:00:01 langtools
00:00:08 nashorn
00:01:59 TOTAL
-------------------------

这种情况下,你可以在./build/linux-x86_64-normal-server-release/images/j2sdk-image/bin/目录下找到javajavac

你可以运行一下:

$ ./java -version
openjdk version "1.8.0-internal"
OpenJDK Runtime Environment (build 1.8.0-internal-amazingrise_2020_05_05_13_13-b00)
OpenJDK 64-Bit Server VM (build 25.71-b00, mixed mode)

没错,它的版本号里写着你的机器名。 很有成就感。

最后

结语

真的就这些了吗?是的,就这些。在 Linux 上,书上那一长串的export统统不需要。

而且可以看出,在我的普普通通的笔记本上,不设置任何参数也可以很快完成编译。网上和书上的各种优化大可不必,configure已经帮我们做好大部分了。

尽信书不如无书。

有人可能会说这篇文章很水,但实际上我花了很多时间:我编译过 OpenJDK 7, 9, 11, 14,试了网上各种各样的方法都不行。

就是希望后人少走点弯路吧(不走是不可能的)。

另外,网上有人说,OpenJDK 8 编译巨坑,其实也没那么复杂。(可能因为他是 macOS?)

网上还有人说,怎么编译都不成功,把 Ubuntu 换成 CentOS 才行。我想说,真的不至于

参考

《深入理解 Java 虚拟机》周志明著,第二版。

问题整理 [已解决] - Debian10 下编译 OpenJDK-8 源码 - cc1plus: all warnings being treated as errors

–disable-warnings-as-errors does not work for HotSpot build

osx环境编译jdk8

JVM-Ubuntu18.04.1下编译OpenJDK8

次回予告

下次可能是 NES 模拟器或者简单 NLP 问答机器人的实现了,看我有没有时间吧。


上次修改於 2020-05-05