---
# System prepended metadata

title: JVM 歷史、編譯 JDK
tags: [JVM]

---

---
title: 'JVM 歷史、編譯 JDK'
disqus: kyleAlien
---

JVM 歷史、編譯 JDK
===

## Overview of Content

如有引用參考請詳註出處，感謝 :cat:

Java 不僅僅是開發語言，它也是一系列計算機應用、規範組成的 **體系**，該技術體系提供了完整的軟體開發、跨平台佈署...等等的環境（像是包括嵌入式、移動裝置、服務器）

[TOC]

## Java 技術體系

運行在 JVM 上的語言除了 Java 之外，還有 Kotlin, Clojure, JRuby, Groovy... 等等，這些都算是 Java 技術體系中的一員；一般來講 Java 技術體系包括

* Java 程序設計語言

* Java Library API

* 各平台的 JVM 實現

* Class 文件格式

* 其他開源第三方 Library

### 照組成劃分

* 根據 Java 各個組成部分的功能，**JDK（`Java Development Kit`）是 Java 程序開發的最小環境**

    * Java 程序設計語言
    * Java Library API
    * 各平台的 JVM 實現
        
        :::info
        * **JRE （`Java Runtime Environment`）是指**？
            
            是指 Java Library API 中的 **`Java SE`、`JVM` 這兩部份的組成**，只要有這兩個元素就可以運行 Java 程序
            > ![](https://hackmd.io/_uploads/ByirYk0hn.png)
        :::

### 照服務領域劃分 - JCP/JSR

* 根據 Java 的技術服務領域，又可分為 4 個主要產品；而這些 API 都是業界共同制定的標準，業界代表可參與 **JCP** (`Java Community Process`)、審核、投票，決定平台元件、特性、應用程式介面... 等等
    
    > 而訂製出來的標準會以 **JSR**（`Java Specification Requests`）作為正式標準規範文件，不同的技術解決方案都會給予一個編號
    > 
    > 在 JSR 規範的表準之下，各廠商都可以實現自己的成品！（相當於每個廠商都有不同的實作）

    * **Java Card**
    
        支持 Java 小程序（`Applets`），它運行在 **小內存設備上的平台**
        
        > 智能卡、支付卡、門禁卡...等等

    * **Java ME**（`Micro Edition`）

        支持 Java 程序運行在 **移動端上的平台**，它的特點是它對 Java API 進行精簡，並加入移動端的特性
        
        > 運行在小型嵌入設備上
        
        :::info
        * JDK 6 之前稱為 J2ME
        :::
        
        :::warning
        * 然而 Android 平台上並不使用 Java ME，**Android 平台使用 JSE**
        :::
    
    * **Java SE**（`Standard Edition`）

        支持 **桌面等級應用**，它提供完整的 Java 核心 API
        
        :::info
        * JDK 6 之前稱為 J2SE
        :::

    * **Java EE**（`Enterprise Edition`）

        支持 **多層級架構的企業應用**，其特色是除了標準 API 之外，還有大量的擴充 API
        
        > ERP, MIS, CRM... 等等應用
        
        :::success
        * JDK 6 之前稱為 J2EE
        
        * JavaEE 6 使用的規範是 [**JSR 316**](https://jcp.org/en/jsr/detail?id=316)；而 Servelet 3.0 規範則是 [**JSR 315**](https://jcp.org/en/jsr/detail?id=315)，Servelet 在 Java EE 中，主要是在接收客戶端的請求
        :::


## Java 歷史簡介

這裡做個 Java 歷史的簡介

### Sun 時代

* 最一開始 Java 是 **`Sun` 公司的產品**，它的重點事蹟如下
    
    * 原始名稱為 Oak，後來才改名為 Java
    
    * 開發理念為 **Write Once, Run Anywhere**
    
    * Sun 時代 版本差異

        | JDK 版本 | 說明 | 技術重點補充 |
        | - | - | - |
        | 1.1 | **有 Java 中最基礎的技術支持**：Jar 文件格式、JDBC、JavaBeans、RMI... 等等 | InnerClass, Reflection 的出現 |
        | 1.2 | JDK 重要里程碑，**依照服務將其分為 J2SE, J2EE, J2ME... 等等** | EJB, Java Plugin, Java IDL, Swing, Collection.. (**JVM 中新增 JIT 技術，並出現 `Classic VM`, `HotSpot VM`, `Exact VM`**)|
        | 1.3 | **HotSpot VM 的出現**，並預設為 Java 默認虛擬機 | Java 2D API, Java Sound API |
        | 1.4 | 開始穩定成熟 | 正則表達式、異常鏈、NIO、異常類、XML 解析... 等等 |
        | 5 | 全面 **改由 Java x 發布** | 自動裝箱、泛型、動態註解、枚舉...等等；改進虛擬機中的內存模型（JMM）；併發包 |
        | 6 | **初步的動態語言支持** | JVM 改進了鎖、同步、GC、類加載...等等 |
        |  | **Java 開源**，並建立 OpenJDK 組織對源碼進行管理 | - |
        | 7 | 由於經濟問題，導致發布延期（最終被 Sun 收購） | Lambda（**函數式編成**）, Jigsaw（虛擬機層面的模塊化）, COIN... |
        
        :::info
        * **到 JDK7 為止，Oracle 公司收購了 Sun 公司**
        :::

### Oracle 時代

* Oracle 公司收購後極具商業化風格
    
    * 宣佈 JDK7 維護到 2022 年，在這期間 JDK7 的所有功能都可以在 Mac OS X、Window 上運行

    * Oracle 接手後的版本差異
    
        | JDK 版本 | 說明 | 技術重點補充 |
        | - | - | - |
        | 7 | G1 收集器 | 延後 Lambda, Coin ... 等等項目 |
        | 8 | 完成 Lambda, 新的 時間、日期 API, Nashorn JavaScript 引擎支持 | 移除 JVM 中的永久代 |
        | 9 | Oracle 堅持 **發展 VM 模塊化技術 Jigsaw** | 增強 JS Shell, JLink, JHSDB... 等等，並統整了 HotSpot 各個模塊的日誌系統，支持 Http2 客戶端 API |
        |  | 使用敏捷開發 | 在此之後的版本都以 Java x.y 為準 (y 為月份)，Java 1.x 變成別名 |
        |  | JDK 更新週期改為 6 個月一次，並且只有 LTS 版本才會長期支援 | - |
        | 10 | 主要是 **內部重構** | 統一源倉庫、GC 界面、JIT 界面 |
        |  | Google 被告使用 Java API 侵權（並不關虛擬機，針對使用 Java 語言） | 出現 **==Graal 編譯器==** |
        | 11(LTS) | **ZGC 革命性出現** | 把 JDK 11 之前的特性開放給 OpenJDK 組織 |
        |  | 發布分為兩個版本 JDK：商業收費版本(`OracleJDK`)、免費版(`OpenJDK`) | 免費板只支持半年的更新 |
        | 12 | Switch 表達式、Java 微測套件(`JMH`)... 等等功能 | - |
        
        :::success
        * **Oracle JDK 開始收費了嗎**？
            
            其實不然，這是給使用者自行選擇，在 JDK 11 之後，可以選擇付費（長期支援），或是免費（你要一直更新）
        :::
        
        
### JDK 開分支策略

* 由於 Sun 公司被 Oracle 公司接管 Java 時是在 Java 6 時期（Java 7 未發布），因此他們改變了管理專案的分支策略
    
    1. 剝離原本要發布 JDK 7 的功能，對外公佈穩定 JDK6 分支（並且 6 可不斷更新）
        
        ``` mermaid
        graph TD;

        JDK6_Main-->JDK7_Dev;
        JDK6_Main-->JDK6u1;
        JDK6u1-->JDK6u4;
        JDK6u4-->JDK6u10;
        JDK6u10-->JDK6u26;
        ```
    
    2. JDK7 經過測試、功能穩定後，發布 JDK7，並同時在 JDK7 發布版上建立 JD8 為下一代做準備
        ``` mermaid
        graph TD;

        JDK6-->JDK7_Main;
        JDK7_Main-->JDK8_Dev;
        
        JDK7_Main-->JDK7u1;
        JDK7u1-->JDK7u4;
        JDK7u4-->JDK7u10;
        JDK7u10-->JDK7u26;
        ```

## 編譯 JDK

Java 類中有許多底層方法（Native），了解這些方法的細節實做，可以對於調適 VM 有不小的幫助


### 下載 Java 源碼

* **在 Sun 的後期（`JDK6` 時建立 OpenJDK 組織）將 Java 開源**，而之後使用 OpenJDK 源碼衍生出的多個發行板（`Azul Zulu`、`Oracle JDK`、`Oracle Open JDK`、`AdoptOpenJDK`、`AmazonCorretto`... 等等）

    **OpenJDK 中的源碼倉庫，只包含了標準 Java SE 的代碼**，如果須需要額外模塊則須另外下載
    
    :::warning
    * 也就是說每個發行板的 OpenJDK 有的功能不盡相同，只能保證一定有 `Java SE` 的實現代碼
    :::
    
    :::info
    * **在 Java 11 中，OracleJDK 與 OpenJDK 的實現已經非常接近相同**
    :::

* 藉此我們可以使用 [**OpenJDK**](https://openjdk.org/) 的版本進行研究，下載源碼方式如下
    
    > **以下載 JDK 12 為例**

    1. **透過 Mercurial 代碼管理工具** 下載 JDK 源碼

        ```shell=
        sudo apt install mercurial

        hg clone http://hg.openjdk.java.net/jdk/jdk
        
        cd jdk
        
        # 查看指定 tag 並切換指定版本
        hg log | grep tag
        
        # 切換到 JDK12+1
        hg update -r jdk-12+1
        
        # 確認
        hg summart
        ```
        > ![](https://hackmd.io/_uploads/HJKMRH1pn.png)
    
    2. **透過 [**github**](https://github.com/openjdk/jdk) 下載 JDK 源碼**

        ```shell=
        git clone https://github.com/openjdk/jdk.git
        
        git tag | grep jdk-12
        
        # 切換到 JDK12+33
        git checkout jdk-12+33
        
        # 確認
        git branch
        ```
        
        > ![](https://hackmd.io/_uploads/ByKhOEuT2.png)

        :::info
        * 個人習慣使用 Git、Github，所以採用這個方案
        :::

    3. 手動下載 [**JDK 壓縮包**](https://hg.openjdk.org/jdk/jdk12)：點擊左邊 Browse 再點擊壓縮包（`zip`, `gz`... 等等）
        
        >　![](https://hackmd.io/_uploads/HyJDJ8kT2.png)

### 編譯 JDK - 環境需求

* **環境需求**：

    * **OS 平台**：建議在 Linux or MacOS 上進行編譯，可以少走一些坑
        
        > 目前我使用 Ubuntu 20
        
    * **磁碟空間**：建議準備個 10 G 以上的空間，因為在 **編譯期間會產生不少中間文件** (IR File)
     
    * **路徑**：建議是使用純英文的空間路徑


### 編譯 JDK - 工具需求 Bootstrap JDK

* 編譯 JDK 除了建議環境之外，還需要一些 **系統工具**
    
    * **NativeCode 編譯工具**：也就是 C、C++ 編譯工具，這邊可以使用 `GCC` or `CLang` 編譯工具
        
        :::warning
        * `GCC` 版本最低為 4.8
        
        * `CLang` 版本最低為 3.2
        :::
        
        ```shell=
        sudo apt install -y build-essential
        
        gcc --version
        ```
        > ![](https://hackmd.io/_uploads/B1vSHIkpn.png)
    
    * **第三方工具**：OpenJDK 還依賴一些第三方編譯工具，可依照需求做安裝

        | 工具名 | 庫名 | 安裝包 |
        | - | - | - |
        | FreeType | The FreeType Project | `libfreetype6-dev` |
        | CUPS | Common UNIX Printing System | `libcups2-dev` |
        | X11 | X Window System | `libx11-dev`、`libxext-dev`、`libxrender-dev`、`libxtst-dev`、`libxt-dev`|
        | ALSA | Advanced Linux Sound Architecture | `libasound2-dev` |
        | libffi | Portable Foreign Function Interface Library | `libffi-dev` |
        | autoconf | Exetensible PAckage of M4 Macros | `autoconf` |


        ```shell=
        sudo apt install -y libfreetype6-dev \
                            libcups2-dev \
                            libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev \
                            libasound2-dev \
                            libffi-dev \
                            autoconf \
                            build-essential \
                            zip unzip \
                            git \
                            libfontconfig1-dev
        ```

    * **Bootstrap JDK**：

        編譯版號為為 N 的 JDK 時，需要有 JDK(N - 1) 版的工具，這種 N-1 版本的 JDK 稱為 Bootstrap JDK；

        > 假設現在要編譯 OpenJDK 12，那我們就要先安裝 OpenJDK 11

        ```shell=
        sudo apt install -y openjdk-11-jdk
        ```

### 編譯 JDK & 參數設置

* JDK 編譯會透過一個 `autoconf` 工具來協助，讓使用者免去關注各個硬體平台差異的 Options 設定（所以請記得安裝該工具）

    在編譯 JDK 前我們可以先查看 configure 可以做哪些設定，透過**設定 configure 也會影響到最終 Make 指令編譯出來的結果**

    ```shell=
    # 查看完整可設定的 Options
    
    bash configure --help
    ```
    
    > ![](https://hackmd.io/_uploads/BJqvsUkah.png)

    下表為常用的幾個設定值
    
    | Options | 功能說明 | 補充 |
    | - | - | - |
    | `--with-debug-level=<level>` | 設定調適等級 | `release`(默認)、`fastdebug`、`slowdebug`... |
    | `--enable-debug` | 等於 `fastdebug` 調適等級 | - |
    | `--with-native-debug-symbols=<method>` | 指定要調適的符號信息 | `non`、`internal`、`external`、`zipped` |
    | `--with-version-string=<String>` | 設置編譯 JDK 的版號 | 這會影響最終編譯出 JDK 的版本訊息（`java --version`） |
    | `with-jvm-variants=<variants>` | 編譯特定模式的 HotSpot JVM | `server`、`client`、`core`、`monimal`、`zero`、`custom` |
    | `--with-target-bits=<bits>` | 指名要編譯出 32, 64 位元的 JVM | 64 位元的機台上可以交叉編譯出 32 bit 的 JVM |
    | `--with-<lib>=<path>` | 用於指明依賴包的具體路徑 | - |
    | `--with-extra-<flagtype>=<flags>` | 該設定會作用在 C, C++, Java 代碼編譯時期 | 像是 `cflags`, `cxxflags`, `ldflags`... |
    | `--with-conf-name=<name>` | 指定編譯配置名稱 | - |
    

* **編譯 JDK 12**

    1. **設定參數**：

        ```shell=
        bash configure --enable-debug --with-jvm-variants=server
        ```
        :::warning
        * **configure 設定失敗？**

            當 configure 設定失敗時，它的返回碼就會是非 0（0 才是成功），這時你就需要按照提示去安裝、設置某些必要工具或參數

            > ![](https://hackmd.io/_uploads/H1mM1P1p3.png)

        :::
        
        設置成功後會看到 configure 摘要訊息
        
        > ![](https://hackmd.io/_uploads/ByWYJwJ6n.png)

    
    2. **執行 make 指令開始編譯**

        :::warning
        * 如果你執行多次 make 那會產生多個檔案，這時可以用 `make clean` 清理
        :::
        
        ```shell=
        make jdk
        ```
        
        :::danger
        * **JDK 12 編譯失敗**？ 出現 `BUILD_TOOLS_LANGTOOLS.vardeps`
            
            這是因為 **JDK12 只支援 4.3 版本以下的 make**，所以我們要找到 `./make/common/MakeBase.gmk` 檔案，並找到 `DependOnVariableHelper` 關鍵字，手動修改程如下
            
            ```shell=
            DependOnVariableHelper = \
                $(strip \
                    $(eval $1_filename := $(call DependOnVariableFileName, $1, $2)) \
                    $(if $(wildcard $($1_filename)), $(eval include $($1_filename))) \
                    $(if $(call equals, $(strip $($1)), $(strip $($1_old))),,\
                      $(call MakeDir, $(dir $($1_filename))) \
                      $(if $(findstring $(LOG_LEVEL), trace), \
                          $(info NewVariable $1: >$(strip $($1))<) \
                          $(info OldVariable $1: >$(strip $($1_old))<)) \
                      $(call WriteFile, $1_old:=$(call DoubleDollar,$(call EscapeHash,$($1))), \
                          $($1_filename))) \
                    $($1_filename) \
                )
            ```
        :::
        
### 編譯 JDK 建議 - Docker

* 編譯 JDK 最常碰到的是環境問題，每個版本的 JDK 都有偏好環境、處理工具的版本... 等等需求；而我們可以透過以下方法解決
    
    1. 依照 JDK 編譯需求，去改變當前系統的工具、環境（不太推薦）

        * 修改 JDK 源碼去符合當前環境
        
        * 下載所需的工具並自己編譯程式安裝到當前平台上
        
            :::info
            * 但老實說以上方法確實可以，但卻相當麻煩又不好處理！工具之間的版本相互依賴、過時工具... 等等問題非常不好處理
            :::

    2. **創建符合編譯 JDK 的環境**（推薦，可以使用 Docker）
        
        * 這個最直覺的就是創建虛擬 OS 平台，再透過該平台來編譯 JDK
            
            :::success
            * 這是個很好的辦法，我們 **可以在 Docker 上建立編譯 JDK 所需的環境**

                像是 JDK 12 就可以在 `Ubuntu:18.04` 編譯
            :::

* 接下來 **使用 Docker 創建一個環境來編譯 JDK 12**
    
    > 安裝請參考官方網站，基礎使用可參考另外一篇 [**Docker 安裝、映像檔使用**](https://hackmd.io/tARjfVCSQTy-aG4PtPo2eQ?view#Docker-%E5%AE%89%E8%A3%9D%E3%80%81%E6%98%A0%E5%83%8F%E6%AA%94%E4%BD%BF%E7%94%A8)
    
    1. **下載 OS 檔案**：
        
        使用 `pull` 下載 `Ubuntu 18.04`

        ```shell=
        # 搜尋對應的版本
        sudo docker search ubuntu:18.04

        # 下載 `Ubuntu 18.04`
        sudo docker pull ubuntu:18.04
        
        # 查看所有 images
        sudo docker images
        ```
        
        > ![](https://hackmd.io/_uploads/rkq7OKPah.png)

    2. **建立、運行 OS，並指定本地檔的映射**：

        :::info
        * 下載請參考上面小節（目前已經下載好 JDK12）
        :::
        

        ```shell=
        # 創建 docker 資料夾
        mkdir ~/docker/
        
        # 將原本下載好的 docker 移動到 ~/docker/ 資料夾下
        mv ~/Documents/github/Learning/JDK/downloadJDK ~/docker/
        
        # 運行 ubuntu 並將 `~/docker` 資料夾映射到 ubuntu:18.04 中的 `/opt` 資料夾
        sudo docker run -it -v ~/docker:/opt/ ubuntu:18.04 /bin/bash
        ```
    
    3. **下載基礎工具**

        ```shell=
        sudo apt install -y libfreetype6-dev \
                            libcups2-dev \
                            libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev \
                            libasound2-dev \
                            libffi-dev \
                            autoconf \
                            build-essential \
                            zip unzip \
                            git \
                            libfontconfig1-dev
                            
        sudo apt install -y openjdk-11-jdk
        ```
    
    4. **改變 Docker Container 中 Ubuntu OS 的設置**：
        
        使其可以運行 JDK12 的編譯

        ```shell=
        # 安裝 gcc 4.8 版本
        update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
        
        # 安裝 g++ 4.8 版本
        update-alternatives --install /usr/bin/gcc gcc /usr/bin/g++-4.8 100
        ```
        > ![](https://hackmd.io/_uploads/ByCtRFDTh.png)

    5. **設置 JDK config**

        ```shell=
        bash configure --enable-debug --with-jvm-variants=server --disable-warnings-as-errors
        ```
        > ![](https://hackmd.io/_uploads/SJxNBqPa3.png)

    6. **編譯 JDK 12，並驗證編譯結果**

        ```shell=
        # 譯 JDK 12
        make
        ```
        > ![](https://hackmd.io/_uploads/SykUjV_an.png)

        :::warning
        * 如果還編譯失敗，可以考慮先執行 `make clean`，並再次執行 `make`
        :::
        
        驗證編譯結果確認是 JDK 12
        
        ```shell=
        ./build/linux-x86_64-normal-server-fastdebug/jdk/bin/java --version
        ```
        > ![](https://hackmd.io/_uploads/HkZuoE_an.png)

    7. **編譯 JDK image**：

        ```shell=
        make images
        
        ls -laF ./build/linux-x86_64-normal-server-fastdebug/images/
        ```
        
        > ![](https://hackmd.io/_uploads/SyLcjwOp2.png)


## 其他

### 編譯 JDK 目標

* make 除了上述之外（無指定），還可以指定不同目標產生不同作用

    | make 目標 | 功能 |
    | - | - |
    | `docs-image` | 產生 JDK 的文檔 image |
    | `test-image` | 產生 JDK 的測試 image |
    | `bootcycle-image` | 編譯兩次 JDK，第二次使用第一次的編譯結果作為 Bootstrap JDK |
    | `all-image` | 產生所有 image（相當於 `product`, `docs`, `test`）三個編譯目標 |
    | `hotspot` | 只編譯 Hotspot 虛擬機 |
    | `clean` | 清理 make 指令產生的臨時文件！ |
    | `dist-clean` | 清理 make、configure 指令產生的文件（相當於回歸到最初的檔案） |

### 編譯 JDK - 產生目錄

* 編譯完 JDK 後會產生以下常見目錄，它們功能如下

    | make 結果 | 功能 |
    | - | - |
    | `buildtools/` | 用於生成、存放編譯過程中使用到的工具 |
    | `hotspot/` | HotSpot 虛擬機產生的中間文件 |
    | `images/` | 使用 `make *-image` 相關指令產生的 image 檔案 |
    | `jdk/` | 編譯後產生的 JDK 文件 |
    | `support/` | 存放編譯時期產生的中間文件 |
    | `test-results/` | 存放編譯後的自動化測試結果 |
    | `configure-support/`、`male-support/`、`test-support/` | 存放執行 `configure`、`make`、`test` 的臨時文件 |
    
    > ![](https://hackmd.io/_uploads/H1xCjN_ah.png)


### 重用 Docker 環境

* 在前面範例中，我們有使用 Docker 建立對應符合固有版本 JDK 的 OS 環境，為了將來方便重用，我們可以把這個特定的 OS 儲存

    ```shell=
    sudo docker ps -a
    
    # 提交指定 OS （儲存）
    sudo docker commit -m "Ubuntu 18.04 for JDK" 49acf ubuntu:18.04_JDK
    
    # 查看建立好的 image 檔案
    sudo docker images
    ```

    > ![](https://hackmd.io/_uploads/Bk6wkB_62.png)


### CLion 調適 JDK

* 以下示範使用 CLion 來調適 JDK（當然你也可以傳統一點使用 GDB 命令、VIM 調適）

    1. **開啟指定 JDK 專案**

        > ![](https://hackmd.io/_uploads/HJxh0wuan.png)

    2. 這裡先選擇 **自動產生 `CMakeList.txt`**
    
        > ![](https://hackmd.io/_uploads/r1sWydOah.png)

        但預設的 `CMakeList.txt` 是不能使用的
        
        > ![](https://hackmd.io/_uploads/By7tkd_a3.png)

        :::success
        * 正確的 `CMakeList.txt` 可以參考 [**ojdkbuild 設置**](https://github.com/ojdkbuild/ojdkbuild)，下載專案並複製其中的 `CMakeList.txt` 檔案
        :::


    3. 接著我們要自己 **建立一個 `CMake Application`**
        
        > ![](https://hackmd.io/_uploads/Bk2n1_OTh.png)

    3. **設定啟動的 `Executable`、`target`、`Program argument`... 等等資訊**
        
        * 設定 `Executable` 為上面編譯好的 Java 程式

            > ![](https://hackmd.io/_uploads/S1xPl__p2.png)

        * 設定 `Program argments` 如下

            ```shell=
            --version -XX:+TraceBytecodes -XX:StopInterpreterAt=<n>
            ```
            
            :::info
            * `-XX:+TraceBytecodes -XX:StopInterpreterAt=<n>`
                
                該設置值是因為 Hotspot 在主流的操作系統上是採用 **模板解釋器執行字節碼的**（與即時編譯器相同），最終 **執行的匯編代碼都是運行時產生的**
                
                > 藉此無法透過下定斷點來暫停程式，所以需要設置此值
            :::

    4. 移除 `Before launch` 中的 `Build`

        > ![](https://hackmd.io/_uploads/Hklj-u_pn.png)


### CLion 調適 JDK - compile-commands

* 在 jdk 編譯完成（完成 `make`、`make images`）後，使用 CLion 開啟 JDK 調適還有另一種方法（[**參考**](https://blog.jetbrains.com/clion/2020/03/openjdk-with-clion/)）


    1. 執行以下指令 **產生 `compile_commands.json` 檔案**

        ```shell=
        make compile-commands
        ```

        :::danger
        * **並不是每一版本的 JDK 都有這個指令**，我目前是切換到 **jdk-12+33** TAG 上
        :::
        
    2. **使用 CLion 開啟 `compile_commands.json` 檔案**
    
        > ![](https://hackmd.io/_uploads/rJTJ6tu6h.png)

    3. 執行 `Tools` -> `Compilation Database` -> `Change Project Root` 功能，**切換專案根目錄**
            
        > 切換到原 `jdk` 目錄
            
    4. **建立 `Custom Build Targets`**：**設置 Build、Clean 工具**
        
        > ![](https://hackmd.io/_uploads/By78Rtda2.png)

        * **Build 工具設置**
            
            | 欄位 | 設定 |
            | - | - |
            | name | `linux_x86_64-server-fastdebug_make` |
            | Program | `make` |
            | Arguments | `CONF=linux-x86_64-server-fastdebug make` |
            | Working directory（jdk 位置） | `/home/alien/docker/downloadJDK/jdk_github/jdk` |
            
            > ![](https://hackmd.io/_uploads/rkrNxAWA2.png)

        * **Clean 工具設置**
            
            | 欄位 | 設定 |
            | - | - |
            | name | `linux_x86_64-server-fastdebug_clean` |
            | Program | `make` |
            | Arguments | `CONF=linux-x86_64-server-fastdebug clean` |
            | Working directory（jdk 位置） | `/home/alien/docker/downloadJDK/jdk_github/jdk` |
        
            > ![](https://hackmd.io/_uploads/H1R50FuT2.png)

    5. **建立 `Custom Build Application`**：
        
        同樣設置 `Executable`、`target`、`Program argument`... 等等資訊，並移除預設的 `Build launch` 的 `Build` 選項
        
        > ![](https://hackmd.io/_uploads/rJ-g19_62.png)


* 設置完後運行 JDK，就可以看到程式的運行式
    
    > 下圖是 `java` 指令的入口：`java.c`#`JavaMain`
    > 
    > ![](https://hackmd.io/_uploads/rkHgEq_63.png)

### CLion - Signal: SIGSEGV 錯誤

* 使用 CLion 調適 JDK 時有 **發生 `Signal: SIGSEGV` 錯誤**，這是因為 Ubuntu 預設使用 GNU 幫 C、C++ 進行編譯，所以會產生這個錯誤

    所以須做以下

    1. 在 `home` 目錄下創建 `.gdbinit` 文件
    
        ```shell=
        touch ~/.gdbinit
        ```
        
    2. 編輯 `.gdbinit` 文件，並撰寫內容


        ```shell=
        # 編譯 .gdbinit 檔案
        vim ~/.gdbinit

        # 以下為內容
        handle SIGSEGV pass noprint nostop

        handle SIGBUS pass noprint nostop
        ```

        > ![](https://hackmd.io/_uploads/HJsNuddph.png)


## Appendix & FAQ

:::info
[**JDK 參考**](https://juejin.cn/post/7068473519415230495)
:::

###### tags: `JVM`
