前言
才開始看《深入理解Java虛擬機》?這本書,里面第一章就讓我們編譯jdk,記錄一下踩坑的過程。
環境如下
Mac OS 11.1
xcode-select version 2384.
Apple clang version 12.0.0 (clang-1200.0.32.28)
CLion 20202.4
照著書上編譯完后,說需要修改CMakeList.txt,否則用Clion進行調試的時候一些頭文件會標紅。
發現還是JetBrain官方推薦了另一種方法,Tips & Tricks: Develop OpenJDK in CLion with Pleasure
可以先看我的錯誤記錄,修改了源碼之后再直接看官方的然后跳到調試部分。
但是只看源碼的話vscode 或許也是個很不錯的選擇,它最起碼不會顯示include的文件not found
編譯jdk12
從http://hg.openjdk.java.net/jdk/jdk12/file/06222165c35f下載jdk12
安裝如下依賴
brew install mercurial
brew install autoconf
brew install freetype
brew install ccache
下載jdk11,我原來就下載好了jdk,可以用brew安裝jdk11
修改vim ~/.bash_profile
,這一步不是必須
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/
export JAVA_8_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/
export JAVA_11_HOME=/Library/Java/JavaVirtualMachines/jdk-11.0.8.jdk/Contents/Home/
#alias命令動態切換jdk版本
alias jdk8="export JAVA_HOME=$JAVA_8_HOME"
alias jdk11="export JAVA_HOME=$JAVA_11_HOME"
之后在終端輸入jdk8或jdk11可以自動切換。
執行configure命令
bash configure --enable-debug --with-jvm-variants=server
之后可以看到一些配置信息,其中boot jdk是jdk11,而我系統中當前jdk是jdk8,所以它會??自動找到N-1版本的JDK,
之后可在build目錄下生成一個配置目錄,之后如果進行多次編譯,或者目錄產生后又修改了配置,記得先使用make clean
和make dist-clean
進入這個配置目錄,查看生成文件,發現和書上的不太一樣
$ tree
.
├── Makefile
├── bootcycle-spec.gmk
├── buildjdk-spec.gmk
├── compare.sh
├── configure-support
│ ├── classes.jsa
│ ├── config.log
│ └── config.status
├── configure.log
└── spec.gmk
編譯
輸入命令,加入compile-commands參數生成的是compilation database,如果不加這個參數,導入clion頭文件一直都是紅的,找不到路徑。
$ sudo make compile-commands
錯誤記錄
錯誤一:
make images時候出現
錯誤二:
打開該文件將這一行注釋了,重新執行sudo make clean&&sudo make dist-clean,再執行出現以下錯誤
參考https://codingnote.cc/p/234919/進行修改,其中在sharedRuntime.cpp上有兩處
image錯誤三:
src/java.desktop/macosx/native/libawt_lwawt/awt/CSystemColors.m:134:9: error: converting the result of '?:' with integer constants to a boolean always evaluates to 'true' [-Werror,-Wtautological-constant-compare] if (colorIndex < (useAppleColor) ? sun_lwawt_macosx_LWCToolkit_NUM_APPLE_COLORS : java_awt_SystemColor_NUM_COLORS) { ^ 1 error generated.
參考https://github.com/openjdk/jdk/commit/4622a18a
最后出現下面的信息,就相當于編譯成功了
Creating jdk image
Creating CDS archive for jdk image
Stopping sjavac server
Finished building target 'images' in configuration 'macosx-x86_64-server-fastdebug'
執行
make CONF=macosx-x86_64-server-fastdebug
進入jdk12/build/macosx-x86_64-server-fastdebug/jdk/bin
目錄查看編譯的java版本
$ ./java -version
openjdk version "12-internal" 2019-03-19
OpenJDK Runtime Environment (fastdebug build 12-internal+0-adhoc.root.jdk12)
OpenJDK 64-Bit Server VM (fastdebug build 12-internal+0-adhoc.root.jdk12, mixed mode)
至此,證明我們已經編譯完成了 JDK12
compile-commands配置方式解釋
在構建一個slowdebug
bash configure --with-debug-level=slowdebug --with-jvm-variants=server
make CONF=macosx-x86_64-server-slowdebug compile-commands
make CONF=macosx-x86_64-server-slowdebug
我debug級別為slowdebug,JetBrain推薦是fastdebug,我為了將兩個編譯的jdk項目區分
第一個make時候使用了CONF
參數,指定了要編譯某個具體的配置,如果只有一個配置,可以省略,但我是編譯了fastdebug
和slowdebug
兩個級別的JDK
,所以使用了這個參數,執行完該命令,就會在${source_root}/build/macosx-x86_64-server-slowdebug
下生成compile_commands.json
文件。
第二個make是在導入CLion
之前,要編譯一下,因為某些模塊使用了預編譯頭,如果不編譯,CLion
會在索引過程中提示找不到各種各樣的文件。執行以下命令進行編譯:
CLion 調試
因為正常情況下直接導入項目文件,會生成CmakeList.txt,書上說我們需要修改這個CmakeList.txt,而我不知道怎么修改,JetBrain官方給我們回答了這個問題。Tips & Tricks: Develop OpenJDK in CLion with Pleasure
生成Compilation Database,然后導入的時候選擇compile_commands.json這個文件就好了
所以我用JetBrain官方的方法和通過 compile-commands參數編譯之后的jdk和不通過compile-commands參數編譯的jdk?也是和下面一樣的配置。所以可以一起使用。
配置Toolchains
點擊configurations,通過preference進入設置
選擇Open or Import
選擇compile-commands.json最后一定選上Open as Project
,然后會等待一段時間的索引
再點最上方的Tools->CMake->Change Project Root
,將根目錄修改為jdk12所在的目錄,就是包含build的目錄
配置 Build Targets
配置make,Arguments
要加CONF=
配置clean,注意Arguments
除了要在前面加CONF=
最后還要加上clean
配置Run/Debug configurations
這里的java是編譯之后的那個路徑下的java二進制文件,即jdk12/macosx-x86_64-server-fastdebug/jdk/bin/java
${source_root}/src/java.base/share/native/libjli/java.c
的JavaMain函數打斷點,點擊Debug
,效果如下:
以下內容復制自參考博客
SIGSEGV
代表指針所對應的地址是無效地址,沒有物理內存對應該地址。其實還有一個,是SIGBUS
,代表指針所對應的地址是有效地址,但總線不能正常使用該指針,通常是未對齊的數據訪問所致。
MacOS
的CLion
默認使用LLDB
進行Debug
,所以要避免這種情況,可以通過在進入第一個斷點時,執行以下命令避免后面出現此類問題:# LLDB使用如下命令,GDB暫不討論,原理基本一致,可以自行搜索 pro hand -p true -s false SIGSEGV SIGBUS
這樣雖然可以解決問題,但如果每次
Debug
都手動修改,會很繁瑣。在JetBrains
的文章Develop OpenJDK in CLion with Pleasure中,文末也提到了解決這種問題,但我試了一下,卻總是不生效,也沒找到是什么原因。不過最后在這個博客中找到了一個解決方案,博主提到,
LLDB
只支持Session
級別的忽略設置(GDB
貌似支持全局,感興趣的同學可以嘗試),就是需要先啟動Debug
,打斷點,然后執行忽略命令,才可以生效。然后博主提出了一種解決方案,在~/.lldbinit
文件中,使用如下命令,實現每次Debug
時自動打個斷點,然后輸入pro hand -p true -s false SIGSEGV SIGBUS
,最后繼續執行后續流程,文件內容如下(其中main.c
文件的路徑自行替換):breakpoint set --file /Users/XXX/XXX/XXX/jdk12/src/java.base/share/native/launcher/main.c --line 98 -C "pro hand -p true -s false SIGSEGV SIGBUS" --auto-continue true
最后,在控制臺查看輸出。
修改CMakeList.txt的一點思路
思路一
因為slowdebug和fastdebug是在jdk12下的build目錄下,導入的時候都將jdk12設置為project的根目錄了,前者是compile-commands命令生成的,使用diffmerge查看兩者有什么不一樣的地方
逐漸往下翻,發現它們的不同在于除了一些命名,fastdebug多了些slowdebug沒有的一點點東西,其余的slowdebug有的fastdebug的都有,那是不是可以合理猜測我根本就不用修這個CMakeList.txt了?
為了驗證,我又將fastdebug重新編譯了一遍作為對比,如下圖,左邊是新的參數為compile-commands,右邊是舊的
他們的區別和前面的圖其實是一樣的。只不過之前是使用了make images命令,多了點東西。
建議還是用創建compilation database的方法。
思路二
打開https://github.com/ojdkbuild/ojdkbuild/tree/master/src,看到只有jdk8,11,13,15,沒有12怎么辦,我去歷史記錄里找到了12的CMakeList.txt,就是如下鏈接,下一步就是復制粘貼大法了
但是這條路還是走不通