在MacOS系統(tǒng)上編譯OpenJDK12并使用CLion調(diào)試
“?寫給自己看,說給別人聽。你好,這是think123的第68篇原創(chuàng)文章”
最近在看synchronized 鎖優(yōu)化方面的內(nèi)容,有些地方看起來不是很方便,干脆就編譯個源碼來看看。
在windows上編譯
由于自己常用的電腦操作系統(tǒng)是win10,所以最開始是想要在win10上編譯的,但是一來網(wǎng)上文章太少,二來在windows上編譯確實麻煩太多了(windows可以參考深入理解JVM虛擬機這本書),故放棄了。
MAC環(huán)境

準(zhǔn)備
獲取源碼
OpenJDK源碼使用Mercurial管理,如果通過版本庫下載,則需要安裝Mercurial,我們借助homebrew包管理器來安裝
brew?install?mercurial
如果你的電腦沒有安裝homebrew,那么可以使用下面的命令來安裝
/usr/bin/ruby?-e?"$(curl?-fsSL?https://raw.githubusercontent.com/Homebrew/install/master/install)"
安裝完成后使用以下命令clone源代碼
cd?~/jvm
hg?clone?https://hg.openjdk.java.net/jdk/jdk12
命令運行之后,openjdk的源碼并沒有下載下來
由于我并沒有使用hg的方式,關(guān)于這部分可以參考閃電俠的文章https://www.jianshu.com/p/ee7e9176632c
當(dāng)然我非常不建議你使用Mercurial的方式下載,這種方式不僅要等很久,而且還需要正確上網(wǎng)才穩(wěn)妥。我墻裂推薦你直接通過頁面下載OpenJdk12源碼壓縮包)

比如我下載的是gz格式的文件(選擇什么格式并不重要)。
如果你使用的Chrome,那么可以開啟多線程下載,速度會有一個很明顯的提升。
Bootstrap JDK
因為OpenJDK的各個組成部分有的是使用C++編寫的,有的是使用Java編寫的,因此編譯這些Java代碼需要使用到一個可用的JDK,官方稱這個JDK為“Bootstrap JDK",一般來說只需要比編譯的JDK第一個版本,這里采用OpenJDK11,可以通過這個網(wǎng)址 https://jdk.java.net/archive/ 下載 記住一定要下載一個適合Mac平臺的OpenJDK11。
我使用的Bootstrap JDK版本如下
openjdk?version?"11.0.2"?2019-01-15
OpenJDK?Runtime?Environment?18.9?(build?11.0.2+9)
OpenJDK?64-Bit?Server?VM?18.9?(build?11.0.2+9,?mixed?mode)
安裝依賴
#?用于生成shell腳本的工具,可以使軟件包在不同的系統(tǒng)下都可以編譯
brew?install?autoconf
#?字體引擎
brew?install?freetype
XCode 和 Command Line Tools for Xcode
這兩個SDK提供了OpenJDK所需的編譯器以及Makefile中用到的外部命令。一般電腦上都自帶安裝了。
網(wǎng)上很多編譯出錯都是因為XCode版本問題,導(dǎo)致報錯,我也遇到了這個坑。
configure:?error:?No?xcodebuild?tool?and?no?system?framework?headers?found,?use?--with-sysroot?or?--with-sdk-name?to?provide?a?path?to?a?valid?SDK
/Users/.../.../xxx.sh:?line?82:?5:?Bad?file?descriptor
configure?exiting?with?result?code?1
最終我通過官網(wǎng)下載https://developer.apple.com/download/more/安裝了9.4.1版本的XCode才搞定了。
下載xcode需要登錄,如果沒有賬號可以申請一個
我選擇的是手動下載xcode安裝的方式,你可以先只下載Command Line Tools (macOS 10.13) for Xcode 9.4.1 安裝看能不能解決你的問題,如果不能再下載Xcode(這個很大,大概4個多G)

編譯jdk
源碼下載好之后,我解壓放到了這個/Users/naver/jvm/jdk12-06222165c35f目錄下,下面的命令均是在這個目錄下執(zhí)行的。
bash?configure??--with-boot-jdk='/usr/local/jdk-11.0.2.jdk/Contents/Home'?--with-debug-level=slowdebug?--with-target-bits=64?--disable-warnings-as-errors?--enable-dtrace?--with-jvm-variants=server
--with-boot-jdk:指定Bootstrap JDK路徑
--with-debug-level:編譯級別,可選值為release、fastdebug、slowdebug和optimized,默認(rèn)值為release,如果我們要調(diào)試的話,需要設(shè)定為fastdebug或者slowdebug,建議設(shè)置為slowdebug
--with-target-bits:指定編譯32位還是64位的虛擬機
--disable-warnings-as-errors:避免因為警告而導(dǎo)致編譯過程中斷
--enable-dtrace:開啟一個性能工具
--with-jvm-variants:編譯特定模式下的虛擬機,一般這里編譯server模式
--with-conf-name:指定編譯配置的名稱,如果沒有指定,則會生成默認(rèn)的配置名稱macosx-x86_64-server-slowdebug,我這里采用默認(rèn)生成配置
在很多場景下編譯OpenJDK都會使用--enable-ccache參數(shù),來通過ccache加快編譯速度,但我沒有采用,因為目前編譯速度其實不慢,再有就是如果增加了這個參數(shù),后續(xù)導(dǎo)入到CLion的時候,會出現(xiàn)很多紅字提示,看著好像不影響使用,但總歸看著不太舒服
生成Compilation Database
在配置CLion的時候,直接import編譯好之后的jdk源碼,你會發(fā)現(xiàn)頭文件都是紅色的,無法找到提示,是因為CLion生產(chǎn)的CMakeLists.txt有問題,如果想要解決這個問題就需要修改這個文件,很明顯我不會修。
最后通過JetBrains說的利用Compilation Database (https://blog.jetbrains.com/clion/2020/03/openjdk-with-clion/) 在CLion中構(gòu)建OpenJDK解決了這個問題。
make?CONF=macosx-x86_64-server-slowdebug?compile-commands
執(zhí)行完該命令,就會在${source_root}/build/macosx-x86_64-server-slowdebug下生成compile_commands.json文件。

編譯
在導(dǎo)入CLion之前,要編譯一下,因為某些模塊使用了預(yù)編譯頭,如果不編譯,CLion會在索引過程中提示找不到各種各樣的文件。
make?CONF=macosx-x86_64-server-slowdebug
測試

至此,證明我們已經(jīng)編譯完成了JDK12
CLion調(diào)試
導(dǎo)入project
在導(dǎo)入project之前先配置好Toolchains(Preferences進入)

配置好Toolchains后,通過File -> Open功能,選中${source_root}/build/macosx-x86_64-server-slowdebug/compile_commands.json,As a project打開,這樣就導(dǎo)入了Compilation Database文件,接下來CLion開始進行索引。
這時候,你會發(fā)現(xiàn)你是看不到源碼的,所以下面需要修改項目的根目錄,通過Tools -> Compilation Database -> Change Project Root功能,選中你的源碼目錄,也就是${source_root},這樣設(shè)置就可以在CLion中看到源代碼啦。
${source_root}指的是 /Users/naver/jvm/jdk12-06222165c35f
debug之前配置
需要在Preferences --> Build, Exceution, Deployment --> Custom Build Targets配置構(gòu)建目標(biāo)


由于我這里已經(jīng)配置好了,所以這里顯示的是編輯頁面,第一次配置要點擊+,進行新增即可。
通過這兩個配置每次構(gòu)建之前都會重新編譯我們的jdk,修改jvm代碼之后可以直接進行重新調(diào)試。
debug 配置

Executable:選擇${source_root}/build/macosx-x86_64-server-slowdebug/jdk/bin/java,或者其它你想調(diào)試的文件,比如javac;
Before luanch:這個下面新增的時候有一個bug,去掉就不會每次執(zhí)行都去Build,節(jié)省時間,但其實OpenJDK增量編譯的方式,每次Build都很快,所以就看個人選擇了。
debug
在${source_root}/src/java.base/share/native/libjli/java.c的401行打斷點,點擊Debug,然后F9放掉,不出意外你會遇到下面這個問題

由于我們使用的LLDB進行debug的,所以在進入第一個斷點的時候在LLDB下執(zhí)行以下命令可以避免此類問題
pro?hand?-p?true?-s?false?SIGSEGV?SIGBUS

最終就可以看到j(luò)ava -version的輸出效果如下

不過每次debug的時候都要輸入這么一句就很麻煩,所以我們可以在~/.lldbinit文件中,使用如下命令,實現(xiàn)每次Debug時自動打個斷點,然后輸入
pro hand -p true -s false SIGSEGV SIGBUS
最后繼續(xù)執(zhí)行后續(xù)流程,文件內(nèi)容如下(其中main.c文件的路徑自行替換)
breakpoint?set?--file?/Users/naver/jvm/jdk12-06222165c35f/src/java.base/share/native/launcher/main.c?--line?98?-C?"pro?hand?-p?true?-s?false?SIGSEGV?SIGBUS"?--auto-continue?true
與Java程序聯(lián)合debug
上面演示的實際是java -version如何debug,那么如何做到通過自己編寫的java代碼作為程序入口來調(diào)試呢?
首先java代碼如下(我用idea編寫的):

CLion中配置如下

運行結(jié)果如下:

參考文檔
<<深入理解Java虛擬機:JVM高級特性與最佳實踐>>
mac下編譯openjdk1.9及集成clion動態(tài)調(diào)試在MacOS系統(tǒng)上使用
CLion編譯并調(diào)試OpenJDK
關(guān)注我不迷路
你的關(guān)注是對我最大的鼓勵,是兄弟就關(guān)注我(狗頭保命)
作者:think123, 一個試圖把問題想簡單的程序員。
"三思而后行 , think23"
