學習JVM時看到書裏講到本身編譯OpenJDK。記錄一下過程java
我是從官網下載網站的,openJDK源碼是用mercurial進行管理的,因此首先使用homebrew安裝mercurialc++
brew install mercurial
安裝完成以後,再運行命令克隆jdk源碼,以後經過運行腳本get_source.sh獲取全部的源代碼macos
hg clone http://hg.openjdk.java.net/jdk8u/jdk8u-dev/ cd jdk8u-dev sh ./get_source.sh
在獲取源碼的過程當中可能會遇到一些問題,以下所示。我遇到的問題主要是網絡的問題,後來經過切換網絡,使用手機熱點解決了。ubuntu
abort: stream ended unexpectedly (got 1596 bytes, expected 10164)
在編譯開始以前須要設置一些變量。這裏與書中所講的有一些不同,只由於我用的是Mac平臺,因此編譯器之類的可能會有一些不同。能夠將下面的內容拷貝創建一個腳本運行。xcode
這裏的環境變量設置採用了博客https://www.jianshu.com/p/d9a1e1072f37中的設置瀏覽器
# 語言選項 export LANG=C # Mac平臺,C編譯器再也不是GCC,是clang export CC=clang # 跳過clang的一些嚴格的語法檢查,否則會將N多的警告做爲Error export COMPILER_WARNINGS_FATAL=false # 連接時使用的參數 export LFLAGS='-Xlinker -lstdc++' # 是否使用clang export USE_CLANG=true # 使用64位數據模型 export LP64=1 # 告訴編譯平臺是64位,否則會按32位來編譯 export ARCH_DATA_MODEL=64 # 容許自動下載依賴 export ALLOW_DOWNLOADS=true # 並行編譯的線程數,編譯時間長,爲了避免影響其餘工做,我選擇爲2 export HOTSPOT_BUILD_JOBS=2 # 是否跳過與先前版本的比較 export SKIP_COMPARE_IMAGES=true # 是否使用預編譯頭文件,加快編譯速度 export USE_PRECOMPILED_HEADER=true # 是否使用增量編譯 export INCREMENTAL_BUILD=true # 編譯內容 export BUILD_LANGTOOLS=true export BUILD_JAXP=true export BUILD_JAXWS=true export BUILD_CORBA=true export BUILD_HOTSPOT=true export BUILD_JDK=true # 編譯版本 export SKIP_DEBUG_BUILD=true export SKIP_FASTDEBUG_BUILD=false export DEBUG_NAME=debug # 避開javaws和瀏覽器Java插件之類的部分的build export BUILD_DEPLOY=false export BUILD_INSTALL=false unset JAVA_HOME
設置好環境變量以後,就能夠開始編譯了,首先運行configure,這個腳本會調用不少其餘的腳本進行配置並檢查編譯環境。bash
bash ./configure
運行成功後的顯示以下:網絡
A new configuration has been successfully created in /Users/zhengshuangxi/mercurial/temp/build/macosx-x86_64-normal-server-release using default settings. Configuration summary: * Debug level: release * JDK variant: normal * JVM variants: server * OpenJDK target: OS: macosx, CPU architecture: x86, address length: 64 Tools summary: * Boot JDK: java version "1.8.0_212" Java(TM) SE Runtime Environment (build 1.8.0_212-b10) Java HotSpot(TM) 64-Bit Server VM (build 25.212-b10, mixed mode) (at /Library/Java/JavaVirtualMachines/jdk1.8.0_212.jdk/Contents/Home) * Toolchain: gcc (GNU Compiler Collection) * C Compiler: Version Apple LLVM version 10.0.0 (clang-1000.11.45.5) Target: x86_64-apple-darwin17.7.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin (at /usr/bin/clang) * C++ Compiler: Version Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 10.0.0 (clang-1000.11.45.5) Target: x86_64-apple-darwin17.7.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin (at /usr/bin/g++) Build performance summary: * Cores to use: 2 * Memory limit: 8192 MB
也有可能會遇到一些問題,這裏我遇到的問題有:app
具體解決辦法在本文最後提到。若是沒有遇到問題就能夠進一步編譯了。jvm
直接使用make all命令進行編譯
make all
編譯成功以後顯示以下:
## Finished docs (build time 00:02:31) ----- Build times ------- Start 2019-06-21 16:43:05 End 2019-06-21 16:57:48 00:00:27 corba 00:00:55 demos 00:02:31 docs 00:03:43 hotspot 00:01:34 images 00:00:15 jaxp 00:00:24 jaxws 00:04:10 jdk 00:00:31 langtools 00:00:12 nashorn 00:14:43 TOTAL ------------------------- Finished building OpenJDK for target 'all'
在編譯過程當中還可能出現一些問題,目前我只遇到這一個問題:
編譯完成以後,在build文件夾中會生成一個名爲macosx-x86_64-normal-server-release的文件夾,這裏就是咱們編譯生成的結果。在這個文件夾中jdk就是OpenJDK編譯成功的產物。
咱們能夠經過以下命令運行虛擬機,查看版本號,若是沒什麼問題終端會顯示以下信息:
cd ./build/macosx-x86_64-normal-server-release/jdk/bin ./java -version openjdk version "1.8.0-internal" OpenJDK Runtime Environment (build 1.8.0-internal-zhengshuangxi_2019_06_21_17_25-b00) OpenJDK 64-Bit Server VM (build 25.71-b00, mixed mode)
運行以後我又遇到一個問題,在運行過程當中會報錯,提示 libjvm.dylib 動態連接庫相關的錯誤。具體解決在本文最後。
checking for xcodebuild... /usr/bin/xcodebuild configure: error: Xcode 4 is required to build JDK 8, the version found was 10.1. Use --with-xcode-path to specify the location of Xcode 4 or make Xcode 4 active by using xcode-select. configure exiting with result code 1
咱們只須要將文件 jdk8u-dev/common/autoconf/generated-configure.sh 進行一些修改,找到如下代碼並進行註釋,代碼大約在26780行左右。註釋以後就不會提示版本問題了
# Fail-fast: verify we're building on Xcode 4, we cannot build with Xcode 5 or later XCODE_VERSION=`$XCODEBUILD -version | grep '^Xcode ' | sed 's/Xcode //'` XC_VERSION_PARTS=( ${XCODE_VERSION//./ } ) if test ! "${XC_VERSION_PARTS[0]}" = "4"; then as_fn_error $? "Xcode 4 is required to build JDK 8, the version found was $XCODE_VERSION. Use --with-xcode-path to specify the location of Xcode 4 or make Xcode 4 active by using xcode-select." "$LINENO" 5 fi
configure: Will use user supplied compiler CC=clang checking for clang... /usr/bin/clang checking resolved symbolic links for CC... no symlink configure: The C compiler (located as /usr/bin/clang) does not seem to be the required gcc compiler. configure: The result from running with --version was: "" configure: error: A gcc compiler is required. Try setting --with-tools-dir. configure exiting with result code 1
解決辦法也是在generated-configure.sh文件中註釋掉如下的條件代碼。註釋的地方一共有兩處:
# 第一處代碼,27936行左右
elif test "x$TOOLCHAIN_TYPE" = xgcc; then # gcc --version output typically looks like # gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 # Copyright (C) 2013 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1` # Check that this is likely to be GCC. $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Free Software Foundation" > /dev/null # 條件語句註釋掉 # if test $? -ne 0; then # { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 # $as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} # { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$COMPILER_VERSION\"" >&5 # $as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSION\"" >&6;} # as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 # fi
# 第二處代碼,29677行左右 elif test "x$TOOLCHAIN_TYPE" = xgcc; then # gcc --version output typically looks like # gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 # Copyright (C) 2013 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1` # Check that this is likely to be GCC. $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Free Software Foundation" > /dev/null # 條件語句註釋掉 # if test $? -ne 0; then # { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 # $as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} # { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$COMPILER_VERSION\"" >&5 # $as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSION\"" >&6;} # as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 # fi
註釋完以後,從新運行configure
Making signal interposition lib... error: invalid argument '-std=gnu++98' not allowed with 'C' make[6]: *** [libjsig.dylib] Error 1 make[6]: *** Waiting for unfinished jobs.... make[5]: *** [the_vm] Error 2 make[4]: *** [product] Error 2 make[3]: *** [generic_build2] Error 2 make[2]: *** [product] Error 2 make[1]: *** [/Users/zhengshuangxi/mercurial/temp/build/macosx-x86_64-normal-server-release/hotspot/_hotspot.timestamp] Error 2 make: *** [hotspot-only] Error 2
在generated-configure.sh文件中找到參數「-std=gnu++98」,將代碼註釋以下:
LDFLAGS_JDK="$LDFLAGS_JDK -Wl,-z,relro" LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS -Wl,-z,relro" fi 此處註釋掉 #CXXSTD_CXXFLAG="-std=gnu++98"
以後從新運行configure,再執行make all
ld: library not found for -lstdc++ clang: error: linker command failed with exit code 1 (use -v to see invocation) make[6]: *** [libsaproc.dylib] Error 1 make[6]: *** Waiting for unfinished jobs.... make[5]: *** [the_vm] Error 2 make[4]: *** [product] Error 2 make[3]: *** [generic_build2] Error 2 make[2]: *** [product] Error 2 make[1]: *** [/Users/zhengshuangxi/mercurial/temp/build/macosx-x86_64-normal-server-release/hotspot/_hotspot.timestamp] Error 2 make: *** [hotspot-only] Error 2
這個緣由是Xcode升級到10之後就沒有包含lstdc++庫了,解決辦法是將/usr/lib中的庫文件拷貝到Xcode相應的文件夾中,並設置相關的軟鏈接。
sudo cp /usr/lib/libstdc++.6.0.9.dylib /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/ cd /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/ sudo ln -s libstdc++.6.0.9.dylib libstdc++.6.dylib sudo ln -s libstdc++.6.dylib libstdc++.dylib
而後從新運行make all命令進行編譯。
# # A fatal error has been detected by the Java Runtime Environment: # # SIGILL (0x4) at pc=0x000000010fe801bf, pid=48116, tid=0x0000000000002203 # # JRE version: OpenJDK Runtime Environment (8.0) (build 1.8.0-internal-zhengshuangxi_2019_06_21_16_42-b00) # Java VM: OpenJDK 64-Bit Server VM (25.71-b00 mixed mode bsd-amd64 compressed oops) # Problematic frame: # V [libjvm.dylib+0x4801bf] PerfDataManager::destroy()+0xab # # Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again # # An error report file with more information is saved as: # /Users/zhengshuangxi/mercurial/temp/build/macosx-x86_64-normal-server-release/jdk/bin/hs_err_pid48116.log # # If you would like to submit a bug report, please visit: # http://bugreport.java.com/bugreport/crash.jsp # [error occurred during error reporting , id 0x4] Abort trap: 6
根據這個錯誤提示,咱們能夠知道錯誤發生在動態連接庫 libjvm.dylib中,根據提示,錯誤代碼時PerDataManager::destroy()函數中。所以咱們須要對這個函數進行修改,即文件 hotspot/src/share/vm/runtime/perfData.cpp,在這個文件中將代碼"delete p"註釋掉。
問題的解決辦法是在博客https://www.jianshu.com/p/34c8a8c37169中看到的。
// 大約在287行 void PerfDataManager::destroy() { if (_all == NULL) // destroy already called, or initialization never happened return; for (int index = 0; index < _all->length(); index++) { PerfData* p = _all->at(index); // 將delete p註釋掉 //delete p; } delete(_all); delete(_sampled); delete(_constants); _all = NULL; _sampled = NULL; _constants = NULL; }
而後從新運行configure以及make all進行編譯。以後就不會出現問題了。