來,手把手教你編譯OpenJDK源代碼

從哪搞到OpenJDK的源代碼?

OpenJDK的官網在這裏:https://hg.openjdk.java.net/,裏面可以看到不同版本的jdk分支。OpenJDK使用Mercurial來做SCM,安裝好Mercurial之後可以使用如下命令克隆OpenJDK的源代碼:

apt-get install -y mercurial
hg clone http://hg.openjdk.java.net/jdk8u/jdk8u/

做好心理準備,克隆的時間會很久。。。
也有人把OpenJDK的源代碼放到GitHub上,譬如這個:

git clone --depth 1 -b master [email protected]:AdoptOpenJDK/openjdk-jdk8u.git

官方也有提供一些打包好的源代碼zip:

wget https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-src-b04-14_jan_2020.zip

OpenJDK源代碼結構

openjdk 
—— corba:多語言、分佈式通訊接口 
—— hotspot:Java 虛擬機 
—— jaxp:XML 處理 
—— jaxws:一組 XML web services 的 Java API 
—— jdk:java 開發工具包 
—— —— 針對操作系統的部分 
—— —— share:與平臺無關的實現 
—— langtools:Java 語言工具 
—— nashorn:JVM 上的 JavaScript 運行時

其中,hotspot 目錄包含了 JVM 的實現, HotSpot VM 的實現源碼位於 hotspot/src 目錄,其目錄結構如下所示:

├─agent                            Serviceability Agent的客戶端實現
├─make                             用來build出HotSpot的各種配置文件
├─src                              HotSpot VM的源代碼
│  ├─cpu                            CPU相關代碼(彙編器、模板解釋器、ad文件、部分runtime函數在這裏實現)
│  ├─os                             操作系相關代碼
│  ├─os_cpu                         操作系統+CPU的組合相關的代碼
│  └─share                          平臺無關的共通代碼
│      ├─tools                        工具
│      │  ├─hsdis                      反彙編插件
│      │  ├─IdealGraphVisualizer       將server編譯器的中間代碼可視化的工具
│      │  ├─launcher                   啓動程序“java”
│      │  ├─LogCompilation             將-XX:+LogCompilation輸出的日誌(hotspot.log)整理成更容易閱讀的格式的工具
│      │  └─ProjectCreator             生成Visual Studio的project文件的工具
│      └─vm                           HotSpot VM的核心代碼
│          ├─adlc                       平臺描述文件(上面的cpu或os_cpu裏的*.ad文件)的編譯器
│          ├─asm                        彙編器接口
│          ├─c1                         client編譯器(又稱“C1”)
│          ├─ci                         動態編譯器的公共服務/從動態編譯器到VM的接口
│          ├─classfile                  類文件的處理(包括類加載和系統符號表等)
│          ├─code                       動態生成的代碼的管理
│          ├─compiler                   從VM調用動態編譯器的接口
│          ├─gc_implementation          GC的實現
│          │  ├─concurrentMarkSweep      Concurrent Mark Sweep GC的實現
│          │  ├─g1                       Garbage-First GC的實現(不使用老的分代式GC框架)
│          │  ├─parallelScavenge         ParallelScavenge GC的實現(server VM默認,不使用老的分代式GC框架)
│          │  ├─parNew                   ParNew GC的實現
│          │  └─shared                   GC的共通實現
│          ├─gc_interface               GC的接口
│          ├─interpreter                解釋器,包括“模板解釋器”(官方版在用)和“C++解釋器”(官方版不在用)
│          ├─libadt                     一些抽象數據結構
│          ├─memory                     內存管理相關(老的分代式GC框架也在這裏)
│          ├─oops                       HotSpot VM的對象系統的實現
│          ├─opto                       server編譯器(又稱“C2”或“Opto”)
│          ├─prims                      HotSpot VM的對外接口,包括部分標準庫的native部分和JVMTI實現
│          ├─runtime                    運行時支持庫(包括線程管理、編譯器調度、鎖、反射等)
│          ├─services                   主要是用來支持JMX之類的管理功能的接口
│          ├─shark                      基於LLVM的JIT編譯器(官方版裏沒有使用)
│          └─utilities                  一些基本的工具類
└─test                             單元測試

等下,我爲什麼要編譯OpenJDK?

如果你改了JDK的源代碼,譬如加了些printf打印點東西、加了sleep模擬長gc之類的,那是不是需要重新編譯一下呢?如果你想要一探JDK內部的實現機制,最便捷的路徑之一就是自己編譯一套JDK,通過閱讀和跟蹤調試JDK源碼去了解Java技術體系的原理,肯定會比閱讀各種技術書籍、文章更加貼近本質。而且,Linux環境下從源代碼開始編譯構建可執行文件,解決各種環境依賴的坑,也是一個後臺開發人員最基本的工程能力的體現,不是麼?

需要什麼環境?

操作系統

要編譯OpenJDK,首先要準備好相關的環境,參看官方的建議,這裏我們以編譯OpenJDK 8爲例,可以選擇Ubuntu 14.04來作爲構建的操作系統。
在這裏插入圖片描述

所需的依賴

採用Docker、VirtualBox等裝好Ubuntu 14.04之後,先換下你喜歡的國內源,然後使用如下命令更新和安裝所需的依賴:

apt-get update && apt-get install -y curl ssh zip unzip vim ant git mercurial build-essential ccache cpio g++ gcc gdb libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libcups2-dev libfreetype6-dev libasound2-dev libelf-dev openjdk-7-jdk 

如何構建?

準備好操作系統安裝好所需的依賴後,就可以把下載好的源代碼拷貝到目標系統中(也可以在目標系統中拉代碼)。cd進去對應的目錄,執行如下命令進行構建:

chmod a+x configure && ./configure --with-debug-level=slowdebug --with-target-bits=64 && make images

如無意外,你應該會遇到這個錯誤:
* This OS is not supported: Linux d71054f4b5ef 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
怎麼肥事!!說好的works flawlessly呢???
沒關係,這個問題其實也很好辦,改改Makefile告訴他Ubuntu 14.04的內核4.x也變成supported的就好:

sed -i 's/3%/3% 4%/g' hotspot/make/linux/Makefile

繼續執行,然後還會碰到這個錯誤:
configure: error: Could not find freetype! You might be able to fix this by running 'sudo apt-get install libfreetype6-dev'. configure exiting with result code 1
libfreetype6-dev這個依賴我們已經安裝過了,參考這裏的建議,使用命令行指定下位置就好:

./configure --with-debug-level=slowdebug --with-target-bits=64 --with-freetype-include=/usr/include/freetype2 --with-freetype-lib=/usr/lib/x86_64-linux-gnu && make clean && make images

將debug level設置爲slowdebug是爲了方便debug,否則你用gdb調試的時候可能無法打斷點。可選的debug level是releasefastdebugslowdebugoptimized,默認是release
構建的過程也會很久,你可以像這個哥們一樣去打幾盤王者,或者做做Keep運動啥的。
構建成功後,build目錄下的目錄結構如下:

buildtools/
configure-support/
hotspot/
images/
jdk/
make-support/
support/
test-results/
test-support/

編譯後的jdk就在jdk目錄中,我們進去驗證下:

# build/linux-x86_64-normal-server-slowdebug/jdk/bin/java -version
openjdk version "1.8.0-internal-debug"
OpenJDK Runtime Environment (build 1.8.0-internal-debug-_2020_02_24_08_50-b00)
OpenJDK 64-Bit Server VM (build 25.40-b25-debug, mixed mode)

OK!大功告成!
爲了節約大家的時間和減少重複勞動,我已經將構建的過程寫成Dockerfile放到了GitHub,大家可以直接拉下來執行構建:

git clone https://github.com/lixuanbin/compile-openjdk-in-docker.git
cd compile-openjdk-in-docker/ubuntu1404_openjdk8
docker build -t ubuntu1404_openjdk8:version3 .

構建成功後進入鏡像驗證:

docker run -ti --entrypoint /bin/sh ubuntu1404_openjdk8:version3

也可以嘗試直接使用我構建導出的鏡像文件:https://pan.baidu.com/s/1sj5-cPfzoGRawXBA0ld6aQ,提取碼:u9ht。
然後導入到Docker本地鏡像庫:

tar -zxvf ubuntu1404_openjdk8_v3.img.tar.gz
docker load < ubuntu1404_openjdk8_v3.img

參考資料

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章