本文內容過於硬核,建議有 Java 相關經驗人士閱讀。
1 引言
從上週開始一直在看周志明的 「深入理解Java虛擬機器:JVM高階特性與最佳實踐(第3版)」 ,好多年之前看過第二版的,絕對算的上是國內 JVM 領域的經典之作,值得多讀幾遍。
全書的開頭就介紹瞭如何自己編譯一次 JDK ,之前看書的時候直接跳過了,一直都沒自己操作過,上週讀到這裡的時候突然萌生了實踐的念頭,說搞就搞。
首先我這次選用的 OpenJDK ,而不是 OracleJDK , OracleJDK 會有一些獨立的商業特性,而這些商業特性都不是開源的,所以只能選擇 OpenJDK 。
在開始編譯之前,我也檢視了很多網上的資料,所有的資料都建議我在基於 Unix 的系統上進行編譯,也就是 Linux 或者是 MacOS ,但我就是頭鐵,上週在 Windows10 上從早晨 9 點搞到 12 點也沒搞定,所以我投降了。
由於囊中羞澀等原因,手頭上也沒有 Mac 電腦,只能把目光瞄向了 Linux 。
一般這種時候可供選擇的發行版要麼是 CentOS 要麼是 Ubuntu ,後來偶然看到有人推薦國產的 Linux 桌面版 deepin ,然後在自己電腦上切了 128G 的空間出來做了個雙系統,正好在試用這款作業系統的同時嘗試下編譯 OpenJDK 。
2 OpenJDK 原始碼
首先我使用的是 deepin20 社群版。
編譯目標是 OpenJDK14 ,也是目前最新的 JDK 版本。
OpenJDK 的原始碼是使用 Mercurial 程式碼版本管理工具進行管理,可以直接從 Repository 中獲取原始碼:
hg clone https://hg.openjdk.java.net/jdk/jdk14
但是這麼幹吧,在國內搞實在是太慢了,不做某些網路相關設定的話,等這個全都 clone 下來,基本上要一上午時間,所以不推薦這麼幹,可以直接訪問程式碼倉庫,使用 zip 下載的方式直接下載程式碼包。
直接訪問 https://hg.openjdk.java.net/jdk/jdk14/ ,點選左邊的 browse
,然後再點選左邊的 zip
按鈕進行下載,我這裡取到的下載地址是:
https://hg.openjdk.java.net/jdk/jdk14/archive/6c954123ee8d.zip
不知道這個下載地址是否長期可用,先放著吧。
等這個 zip 壓縮包下載完成後,我就完成第一步了,得到了 OpenJDK14 的原始碼包,在這個原始碼包下有一個 doc 的目錄,裡面有一個 building.html
,這個檔案實際上編譯的指導手冊,當編譯出現問題的時候可以去這個手冊裡面查詢解決方案。
3 環境準備
編譯 JDK14 需要一個叫做 BootJDK 的東西,這個其實就是目標 JDK 的上一個 JDK 版本,比如我們要編譯 JDK14 ,那麼本地就需要有一個 JDK13 的環境,所以第一件事情是在本地安裝 JDK13 ,下載地址:
http://jdk.java.net/java-se-ri/13
下載完成後解壓,修改環境變數的配置, deepin 系統的環境變數在使用者目錄的 .bashrc
中,因為我這個是桌面版的系統,直接使用 VSCode 在檔案的最後配置上 JDK13 的環境變數:
export JAVA_HOME=/home/使用者名稱/Java/jdk-13
export CLASSPATH=${JAVA_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
然後在命令列 terminal 中重新整理一下這個配置檔案:
source /home/使用者名稱/.bashrc
這時輸入經典的命令 java -version
看下版本資訊:
openjdk version "13" 2019-09-17
OpenJDK Runtime Environment (build 13+33)
OpenJDK 64-Bit Server VM (build 13+33, mixed mode, sharing)
接著開始安裝各種環境,為編譯做準備,因為要裝的軟體屬實有點多,我把命令整理出來都放在下面了:
sudo apt-get install build-essentail -y
sudo apt-get install libfreetype6-dev -y
sudo apt-get install libcups2-dev -y
sudo apt-get install libfontconfig1-dev -y
sudo apt-get install libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev -y
sudo apt-get install libasound2-dev -y
sudo apt-get install libffi-dev -y
sudo apt-get install autoconf -y
安裝的時候如果當前使用者是 root ,則不需要加最前面的 sudo ,如果不是 root 要記得加 sudo ,我是習慣開啟 terminal 先把使用者切換成 root 。
然後準備工作就完成了,不過有一點需要注意,執行完上面的命令後請檢查 gcc 的版本,因為在我們下載下來的原始碼包的文件中已經明確的指出了 gcc 的版本限制,如果不在這個版本中十分有可能造成編譯失敗。
# 輸入
gcc --version
# 輸出
gcc (Uos 8.3.0.3-3+rebuild) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
OpenJDK14 要求的 gcc 的版本是 8.3.0 ,這個請注意,否則將會出現編譯檢查可以通過,但是打包映象會失敗的情況(我之前在 Ubuntu 虛擬機器上做實驗的時候遇到過)。
這一段的含義是要求我們使用 gcc 的版本在 4.8 到 8.3 之間,越接近 8.3 越接近成功,言外之意就是我們最好使用 8.3 ,否則極有可能會失敗。
到此為止,我們的編譯環境就準備完畢了,接下來可以開始進行編譯了。
4 編譯進行時
首先我們進入剛才準備好的 OpenJDK14 原始碼包的根目錄,第一步是使用 configure
命令進行編譯檢查。
configure 命令承擔了依賴項檢查、引數配置和構建輸出目錄結構等多項職責,如果編譯過程中需要的工具鏈或者依賴項有缺失,命令執行後將會得到明確的提示,並且給出該依賴的安裝命令。
我使用下面這個命令進行編譯檢查:
bash configure --enable-debug --with-jvm-variants=server
這個命令的含義是編譯 FastDebug 版、僅含 Server 模式的 HotSpot 虛擬機器。
configure 命令有很多其他的引數,我就不抄書往出列了,有想知道的朋友歡迎看書或者使用命令 bash configure --help
進行檢視。
接下來我們輸入上面的那個編譯檢查命令,如果檢查通過了會列印以下資訊:
這裡輸出了一些資訊,包括除錯級別,Java虛擬機器的模式、特性,使用的編譯器版本等配置摘要資訊。
接下來到了激動人心的時刻,最後一個命令實際上非常簡單, make images
,執行這個命令後,我們就真正開始了 OpenJDK 編譯的過程。
接下來能做的就是喝杯茶。。。
再喝杯茶。。。
再喝杯茶。。。
。。。
直到第 N 杯茶以後,編譯成功了。
我使用的是桌上型電腦,16G 記憶體,CPU 酷睿 i7-8700 物理 6 核虛擬 12核,首次全量編譯耗時在 8 分鐘左右。
如果是全量編譯過,只是修改後做增量編譯,這個會快很多,在書中是說可以在 10s 內編譯完成。這個我沒試過,沒有話語權。
編譯成功後我的 OpenJDK14 在 build/linux-x86_64-server-fastdebug/jdk
這個目錄下,然後修改下系統的環境 Java 環境變數,改成我剛編譯的這個 OpenJDK ,再使用命令檢視下版本:
# 輸入
java -version
# 輸出
openjdk version "14-internal" 2020-03-17
OpenJDK Runtime Environment (fastdebug build 14-internal+0-adhoc.weishiyao.jdk14-6c954123ee8d)
OpenJDK 64-Bit Server VM (fastdebug build 14-internal+0-adhoc.weishiyao.jdk14-6c954123ee8d, mixed mode)
可以看到,系統的 jdk 已經變成了我剛才自己編譯的版本,連名字都變成了我的機器名,接下來我就可以自己使用自己編譯的 jdk 了,還是蠻有成就感的。