自己動手編譯OpenJDK

zanwensicheng發表於2019-02-19

個人技術部落格:www.zhenganwen.top

筆者環境

  • 64bit / Windows10 / i5-7200U / 4核心CPU,在虛擬機器上的Centos7(能連外網)上編譯OpenJDK7u75

建議使用Ubuntu或者Centos,安裝依賴的地方使用apt-get/yum替換即可(Rhelyum源使用收商業限制,因此依賴下載不方便,建議使用centos或者debain,或者更換yumcentos也行,筆者起初在rhel上編譯,踩了不少坑,最後換到centos上才編譯成功。沒辦法,linux是真的菜,不過通過這次採坑也學了不少linux上編譯原始碼的套路,本文會穿插著提到)。

環境準備

OpenJDK原始碼

openjdk7u75,主角,下載好用來編譯。

Bootstrap JDK

在編譯JDK時不全是使用C/C++,也有用到JAVA的,因此需要一個已編譯好的JDK,官方稱其為BOOTSTRAP JDK,要求必須是JDK6 Update14以上版本。建議到Oracle官網上下載,筆者下載的是jdk-7u4-linux-x64

編譯環境

編譯需要依賴GCCC++等環境,一鍵下載:

yum -y install build-essential gawk m4 openjdk6-jdk libasound2-print-dev binutils libmotif3 libmotif-dev ant
複製程式碼

Xcode相關的庫:

yum install libX*
複製程式碼

檢查編譯環境

將下載好的openjdk原始碼和作為bootstrap jdkjdk7u4上傳到centos/usr/local/java下並解壓:

[root@pinyoyougou-docker java]# ls
jdk1.7.0_04  jdk-7u4-linux-x64.tar.gz  openjdk  openjdk-7u75-src-b13-18_dec_2014.zip
複製程式碼

上面的openjdk就是openjdk原始碼包解壓之後的目錄,記下這個名字,後續操作都是圍繞這個目錄展開的。

進入openjdk並檢查編譯環境:

[root@pinyoyougou-docker java]# cd openjdk
[root@pinyoyougou-docker java]# make sanity
WARNING: LANG has been set to zh_CN.UTF-8, this can cause build failures.
         Try setting LANG to 'C'.

WARNING: The version of zip being used is older than
       the required version of '2.2'.
       The version of zip found was ''.

ERROR: The Compiler version is undefined.

ERROR: Your CLASSPATH environment variable is set.  This will
       most likely cause the build to fail.  Please unset it
       and start your build again.

ERROR: Your JAVA_HOME environment variable is set.  This will
       most likely cause the build to fail.  Please unset it
       and start your build again.

ERROR: You seem to not have installed ALSA 0.9.1 or higher.
       Please install ALSA (drivers and lib). You can download the
       source distribution from http://www.alsa-project.org or go to
       http://www.freshrpms.net/docs/alsa/ for precompiled RPM packages.

ERROR: FreeType version  2.3.0  or higher is required.
 make[2]: 進入目錄“/usr/local/java/openjdk/jdk/make/tools/freetypecheck”
/bin/mkdir -p /usr/local/java/openjdk/build/linux-amd64/btbins
rm -f /usr/local/java/openjdk/build/linux-amd64/btbins/freetype_versioncheck
make[2]: 離開目錄“/usr/local/java/openjdk/jdk/make/tools/freetypecheck”
Failed to build freetypecheck.

ERROR: You do not have access to valid Cups header files.
       Please check your access to
           /usr/include/cups/cups.h
       and/or check your value of ALT_CUPS_HEADERS_PATH,
       CUPS is frequently pre-installed on many systems,
       or may be downloaded from http://www.cups.org
複製程式碼

上面出現了兩個警告和五個異常,我們需要逐個解決。(如果你make sanity輸出的是check pass則可跳過此步驟)

  1. 設定環境變數LANG=C

    WARNING: LANG has been set to zh_CN.UTF-8, this can cause build failures.
             Try setting LANG to 'C'.
    複製程式碼

    解決方法:

    [root@pinyoyougou-docker java]# export LANG=C
    複製程式碼
  2. zip版本較低,需要更新

    WARNING: The version of zip being used is older than
           the required version of '2.2'.
           The version of zip found was ''.
    複製程式碼

    解決方法:

    yum install zip
    複製程式碼
  3. 缺少編譯依賴

    ERROR: The Compiler version is undefined.
    複製程式碼

    解決:

    [root@pinyoyougou-docker openjdk]# yum install gcc gcc-c++
    複製程式碼
  4. 取消已有的JDK環境變數

    ERROR: Your CLASSPATH environment variable is set.  This will
           most likely cause the build to fail.  Please unset it
           and start your build again.
    複製程式碼

    由於我之前在這個centos上裝過jdk並在/etc/profile中配置過JAVA_HOME,CLASS_PATH,因此這裡提示建議我暫時取消這兩項設定,否則可能出現未知錯誤。解決:

    [root@pinyoyougou-docker openjdk]# unset JAVA_HOME
    [root@pinyoyougou-docker openjdk]# unset CLASS_PATH
    複製程式碼
  5. 缺少音效卡依賴alsa,這個是linux上常用的聲音裝置的依賴,java.awt需要依賴這個。

    ERROR: You seem to not have installed ALSA 0.9.1 or higher.
           Please install ALSA (drivers and lib). You can download the
           source distribution from http://www.alsa-project.org or go to
           http://www.freshrpms.net/docs/alsa/ for precompiled RPM packages.
    複製程式碼

    解決

    [root@pinyoyougou-docker openjdk]# yum search alsa
    已載入外掛:fastestmirror
    Loading mirror speeds from cached hostfile
     * base: mirrors.aliyun.com
     * extras: mirrors.shu.edu.cn
     * updates: mirrors.aliyun.com
    ======================================== N/S matched: alsa ========================================
    alsa-firmware.noarch : Firmware for several ALSA-supported sound cards
    alsa-lib.x86_64 : The Advanced Linux Sound Architecture (ALSA) library
    alsa-lib.i686 : The Advanced Linux Sound Architecture (ALSA) library
    alsa-lib-devel.i686 : Development files from the ALSA library
    alsa-lib-devel.x86_64 : Development files from the ALSA library
    alsa-plugins-arcamav.i686 : Arcam AV amplifier plugin for ALSA
    alsa-plugins-arcamav.x86_64 : Arcam AV amplifier plugin for ALSA
    alsa-plugins-maemo.i686 : Maemo plugin for ALSA
    alsa-plugins-maemo.x86_64 : Maemo plugin for ALSA
    alsa-plugins-oss.i686 : Oss PCM output plugin for ALSA
    alsa-plugins-oss.x86_64 : Oss PCM output plugin for ALSA
    alsa-plugins-pulseaudio.i686 : Alsa to PulseAudio backend
    alsa-plugins-pulseaudio.x86_64 : Alsa to PulseAudio backend
    alsa-plugins-samplerate.i686 : External rate converter plugin for ALSA
    alsa-plugins-samplerate.x86_64 : External rate converter plugin for ALSA
    alsa-plugins-upmix.i686 : Upmixer channel expander plugin for ALSA
    alsa-plugins-upmix.x86_64 : Upmixer channel expander plugin for ALSA
    alsa-plugins-usbstream.i686 : USB stream plugin for ALSA
    alsa-plugins-usbstream.x86_64 : USB stream plugin for ALSA
    alsa-plugins-vdownmix.i686 : Downmixer to stereo plugin for ALSA
    alsa-plugins-vdownmix.x86_64 : Downmixer to stereo plugin for ALSA
    alsa-tools.x86_64 : Specialist tools for ALSA
    alsa-tools-firmware.x86_64 : ALSA tools for uploading firmware to some soundcards
    alsa-utils.x86_64 : Advanced Linux Sound Architecture (ALSA) utilities
    alsa-plugins-speex.i686 : Rate Converter Plugin Using Speex Resampler
    alsa-plugins-speex.x86_64 : Rate Converter Plugin Using Speex Resampler
    [root@pinyoyougou-docker openjdk]# yum -y install alsa-lib* alsa-util*
    複製程式碼

    套路一:當提示缺少依賴,而你不知道要yum install什麼時,你可以根據提示關鍵字搜一下yum search,然後在搜出的結果列表中,對有著相同字首的依賴使用字尾萬用字元一鍵下載。

  6. 缺少freetype依賴

    ERROR: FreeType version  2.3.0  or higher is required.
    複製程式碼

    解決:

    root@pinyoyougou-docker openjdk]# yum search freetype
    已載入外掛:fastestmirror
    Loading mirror speeds from cached hostfile
     * base: mirrors.aliyun.com
     * extras: mirrors.shu.edu.cn
     * updates: mirrors.aliyun.com
    ====================================== N/S matched: freetype ======================================
    freetype-demos.x86_64 : A collection of FreeType demos
    freetype-devel.i686 : FreeType development libraries and header files
    freetype-devel.x86_64 : FreeType development libraries and header files
    freetype.x86_64 : A free and portable font rendering engine
    freetype.i686 : A free and portable font rendering engine
    
      名稱和簡介匹配 only,使用“search all”試試。
    [root@pinyoyougou-docker openjdk]# yum install freetype-devel.x86_64
    複製程式碼

    套路二:使用yum install時習慣性帶上一個-y,免得總是詢問是否確定安裝。

  7. 於是我再make sanity,發現還有一個問題

    ERROR: You do not have access to valid Cups header files.
           Please check your access to
               /usr/include/cups/cups.h
           and/or check your value of ALT_CUPS_HEADERS_PATH,
           CUPS is frequently pre-installed on many systems,
           or may be downloaded from http://www.cups.org
    複製程式碼

    缺少cups列印框架,解決:

    [root@pinyoyougou-docker openjdk]# yum search cups
    已載入外掛:fastestmirror
    Loading mirror speeds from cached hostfile
     * base: mirrors.aliyun.com
     * extras: mirrors.shu.edu.cn
     * updates: mirrors.aliyun.com
    ======================================== N/S matched: cups ========================================
    bluez-cups.x86_64 : CUPS printer backend for Bluetooth printers
    cups.x86_64 : CUPS printing system
    cups-client.x86_64 : CUPS printing system - client programs
    cups-devel.i686 : CUPS printing system - development environment
    cups-devel.x86_64 : CUPS printing system - development environment
    cups-filesystem.noarch : CUPS printing system - directory layout
    cups-filters.x86_64 : OpenPrinting CUPS filters and backends
    cups-filters-devel.i686 : OpenPrinting CUPS filters and backends - development environment
    cups-filters-devel.x86_64 : OpenPrinting CUPS filters and backends - development environment
    cups-filters-libs.i686 : OpenPrinting CUPS filters and backends - cupsfilters and fontembed
                           : libraries
    cups-filters-libs.x86_64 : OpenPrinting CUPS filters and backends - cupsfilters and fontembed
                             : libraries
    cups-ipptool.x86_64 : CUPS printing system - tool for performing IPP requests
    cups-libs.x86_64 : CUPS printing system - libraries
    cups-libs.i686 : CUPS printing system - libraries
    cups-lpd.x86_64 : CUPS printing system - lpd emulation
    ghostscript-cups.x86_64 : CUPS filter for interpreting PostScript and PDF
    gutenprint-cups.x86_64 : CUPS drivers for Canon, Epson, HP and compatible printers
    python-cups.x86_64 : Python bindings for CUPS
    python-cups-doc.x86_64 : Documentation for python-cups
    cups-pk-helper.x86_64 : A helper that makes system-config-printer use PolicyKit
    foomatic-filters.x86_64 : CUPS print filters for the foomatic package
    samba-krb5-printing.x86_64 : Samba CUPS backend for printing with Kerberos
    
      名稱和簡介匹配 only,使用“search all”試試。
    [root@pinyoyougou-docker openjdk]# yum install cups-devel.x86_64
    複製程式碼
  8. make sanity檢查通過:

    Sanity check passed.
    複製程式碼

編寫編譯啟動指令碼

經過前面一番周折,編譯環境基本上準備好了,接下來就可以make進行編譯了,但是編譯前需要設定一下一些環境變數,諸如boostrap jdk的根目錄在哪,哪些需要編譯,並行編譯執行緒數等。

openjdk/下建立compile.sh並鍵入下列內容(參考《深入理解Java虛擬機器》):

#語言選項,這個必須設定,否則編譯好後會出現一個HashTable的NPE錯
export LANG=C

#Bootstrap JDK的安裝路徑。必須設定。 
export ALT_BOOTDIR=/usr/local/java/jdk1.7.0_04

#允許自動下載依賴
export ALLOW_DOWNLOADS=true

#並行編譯的執行緒數,設定為和CPU核心數量一致即可
export HOTSPOT_BUILD_JOBS=4
export ALT_PARALLEL_COMPILE_JOBS=4

#比較本次build出來的映像與先前版本的差異。這個對我們來說沒有意義,必須設定為false,否則sanity檢查會報缺少先前版本JDK的映像。如果有設定dev或者DEV_ONLY=true的話這個不顯式設定也行。 
export SKIP_COMPARE_IMAGES=true

#使用預編譯標頭檔案,不加這個編譯會更慢一些
export USE_PRECOMPILED_HEADER=true

#要編譯的內容
export BUILD_LANGTOOLS=true 
#export BUILD_JAXP=false
#export BUILD_JAXWS=false 
#export BUILD_CORBA=false
export BUILD_HOTSPOT=true 
export BUILD_JDK=true

#要編譯的版本
#export SKIP_DEBUG_BUILD=false
#export SKIP_FASTDEBUG_BUILD=true
#export DEBUG_NAME=debug

#把它設定為false可以避開javaws和瀏覽器Java外掛之類的部分的build。 
BUILD_DEPLOY=false

#把它設定為false就不會build出安裝包。因為安裝包裡有些奇怪的依賴,但即便不build出它也已經能得到完整的JDK映像,所以還是別build它好了。
BUILD_INSTALL=false

#這兩個環境變數必須去掉,不然會有很詭異的事情發生(我沒有具體查過這些“”詭異的事情”,Makefile指令碼檢查到有這2個變數就會提示警告“)
unset JAVA_HOME
unset CLASSPATH

make 2>&1 | tee $ALT_OUTPUTDIR/build.log
複製程式碼

其中需要注意的地方:

  1. 必須設定LANG=C、將ALT_BOOTDIR設定成boostrap jdk的根目錄
  2. 如果你的系統先前配置過jdk環境變數,一定要在這裡unset一下(上述的第40,41行)
  3. 上述並型執行緒數跟你的cpu核心個數相同即可

其它的地方可以照搬。

開始編譯

使用上面寫好的編譯啟動指令碼開始編譯:

[root@pinyoyougou-docker openjdk]# chmod +x compile.sh
[root@pinyoyougou-docker openjdk]# ./compile.sh
複製程式碼

這個過程通常需要幾十分鐘,如果一切順利,最後會顯示編譯開始時間以及終止時間。(當然,大部分情況下,受挫之路相當曲折~)。

########################################################################
##### Leaving jdk for target(s) sanity all docs images             #####
########################################################################
##### Build time 00:10:12 jdk for target(s) sanity all docs images #####
########################################################################

#-- Build times ----------
Target all_product_build
Start 2019-01-23 16:37:02
End   2019-01-23 16:48:00
00:00:23 corba
00:00:09 hotspot
00:00:03 jaxp
00:00:06 jaxws
00:10:12 jdk
00:00:03 langtools
00:10:58 TOTAL
-------------------------
make[1]: Leaving directory `/usr/local/java/openjdk'
[root@pinyoyougou-docker openjdk]#
複製程式碼

所以下面將羅列筆者的受挫之路……如果make過程中發生error異常終止,一般解決異常之後繼續make。筆者開始傻到每次解決異常,然後make clean,再make

解決編譯錯誤

  1. cannot find -lstdc++

    -l表示庫,cannot find -lXXX,通常表示缺少libXXX庫。看網上說是缺少libstdc++-static,但筆者建議最好將yum search libstdc*的搜尋結果一股腦全yum install下來,反正又不多。

  2. libjvm.so軟連線死迴圈

    /usr/bin/ld: cannot open output file libjvm.so: Too many levels of symbolic links
    collect2: error: ld returned 1 exit status
    ln: failed to access 'libjvm.so': Too many levels of symbolic links
    ln: failed to access 'libjvm.so.1': Too many levels of symbolic links
    /usr/bin/objcopy --only-keep-debug libjvm.so libjvm.debuginfo
    /usr/bin/objcopy: Warning: could not locate 'libjvm.so'.  reason: Too many levels of symbolic links
    複製程式碼

    這時不能需要先make clean,然後再make sanitymake

  3. 超過十年問題

    Error: time is more than 10 years from present: 1136059200000
    java.lang.RuntimeException: time is more than 10 years from present: 1136059200000
            at build.tools.generatecurrencydata.GenerateCurrencyData.makeSpecialCaseEntry(GenerateCurrencyData.java:285)
            at build.tools.generatecurrencydata.GenerateCurrencyData.buildMainAndSpecialCaseTables(GenerateCurrencyData.java:225)
            at build.tools.generatecurrencydata.GenerateCurrencyData.main(GenerateCurrencyData.java:154)
    複製程式碼

    修改openjdk//jdk/src/share/classes/java/util/CurrencyData.properties,將其中表示年份的地方都改為距離今年不超過10年的年份:

    • 修改108行 AZ=AZM;2015-12-31-20-00-00;AZN
    • 修改381行 MZ=MZM;2015-06-30-22-00-00;MZN
    • 修改443行 RO=ROL;2015-06-30-21-00-00;RON
    • 修改535行 TR=TRL;2015-12-31-22-00-00;TRY
    • 修改561行 VE=VEB;2015-01-01-04-00-00;VEF
  4. 缺少C標頭檔案

     fatal error: X11/Intrinsic.h: No such file or directory
     # include <X11/Intrinsic.h>
    複製程式碼
    /usr/include/gnu/stubs.h:7:27: fatal error: gnu/stubs-32.h: No such file or directory compilation terminated. make: *** [bitmap.o] Error 1
    複製程式碼

    套路三:如果提示你缺少xxx/xxx.h,可以使用yum provides */xxx.h檢視該標頭檔案包含於哪個庫中,再將該庫的全名稱作為yum install的引數下載

本想將筆者踩過的坑都貼出來,奈何編譯輸出資訊太多難以找到採坑痕跡。總而言之,不是缺少依賴,就是已有依賴不相容(這時你需要32/64位版本都下載)

使用編譯好的jdk

編譯成功之後,openjdk/build/linux-amd64/j2sdk-image就是編譯好的jdk的根目錄:

[root@pinyoyougou-docker j2sdk-image]# bin/java -version
openjdk version "1.7.0-internal"
OpenJDK Runtime Environment (build 1.7.0-internal-root_2019_01_23_14_04-b00)
OpenJDK 64-Bit Server VM (build 24.75-b04, mixed mode)
複製程式碼

參考連結

相關文章