Java虚拟机原理分析之Win10下VS2017编译OpenJDK8与单步调试HotSpot VM过程详细记录

来源:互联网 发布:梦三国2网络原因失败 编辑:程序博客网 时间:2024/06/05 07:02

在上一篇文章《Java虚拟机原理分析之Win7下VS2010编译OpenJDK8与单步调试HotSpot VM过程详细记录》中,我们在Win7+VS2010环境下成功编译出了x86版本的OpenJDK。然而VS2010毕竟有些年头了,我也只是在开发机上才装了这个经典的VS版本,而在自己的电脑上使用的是VS2017。而通过远程桌面连到开发机是一件很不爽的事,并且VS2010的IDE自然是不如VS2017的好用。因此萌发了使用VS2017编译OpenJDK的想法,然而经过搜索并没能在网上找到类似的文章和教程,于是只得靠自己摸索了。

首先放上我的环境信息:

  1. Microsoft Windows 10 LTSB 2016版本(补丁更新到最新)

  2. Visual Studio 2017(补丁更新到最新,装有VisualAssistX插件)

  3. JDK Win64 8u152版本

  4. Cygwin x64版本,已装好了需要的组件

  5. freetype 2.81版本,已用VS2017编译好x86的Dll版本,放在I:\jvm\freetype目录下

  6. OpenJDK v8源码最新版本,放在I:\jvm\jdk8u-dev目录下

  7. msvcr100.dll的x86版本(只是用来骗配置过程的),放在I:\jvm\目录下

由于之前已经详细记录过Win7下使用VS2010编译x86版本OpenJDK的过程了,因此这里对于重复部分就不再详细讲解了,直接一句话带过,如有需要可以参考上一篇文章中的详细记叙。

配置

解决找不到VS的问题

下载好源码、安装好Cygwin及工具并编译生成dll版本的typefree(这部分操作与VS2010编译时一致,在此不再赘述),然后使用如下命令:

bash ./configure --with-freetype=/cygdrive/i/jvm/freetype -with-target-bits=32 --with-debug-level=slowdebug --with-jvm-variants=client

接着在寻找VS时会报错:

2017-12-19_132105

打开/common/autoconf/generated-configure.sh文件,搜索“Cannot locate a valid Visual Studio”进行定位,发现可以通过传入–with-tools-dir参数指定vcvars32.bat的路径,从而定位到头文件、库文件等的路径。针对VS2017,该批处理位于以下路径:

C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build

修改代码,主要匹配其vcvars32.bat和VS100BASE路径。值得注意的是,VS2017默认的vcvars32xp.bat没有包含WinSDK 7.1,并且生成的可执行文件也无法在XP上运行。因此拷贝vcvars32.bat为vcvars32xp.bat,修改其内容如下:

@call "%~dp0vcvarsall.bat" x86 %*set INCLUDE=%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.1A\Include;%INCLUDE%set PATH=%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.1A\Bin;%PATH%set LIB=%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.1A\Lib;%LIB%set CL=/D_USING_V110_SDK71_;%CL%set LINK=/SUBSYSTEM:CONSOLE,5.01 %LINK%

然后对generated-configure.sh文件中的代码进行修改:

# First-hand choice is to locate and run the vsvars bat file.  if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then    VCVARSFILE="VC/Auxiliary/Build/vcvars32xp.bat"  # 这里改为VS2017的路径  else    VCVARSFILE="VC/Auxiliary/Build/vcvars64.bat"    # 这里改为VS2017的路径  fi  VS_ENV_CMD=""  VS_ENV_ARGS=""  if test "x$with_toolsdir" != x; then  if test "x$VS_ENV_CMD" = x; then    VS100BASE="$with_toolsdir/../../.."               # 这里改为VS2017的路径    METHOD="--with-tools-dir"

修改后,重新输入配置命令如下:

bash ./configure --with-freetype=/cygdrive/i/JVM/freetype -with-target-bits=32 --with-debug-level=slowdebug --with-jvm-variants=client with_toolsdir="/cygdrive/c/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/VC/Auxiliary/Build"

执行后继续报错:

2017-12-19_142448

看来程序考虑的比较周到,如果是在VS2010环境下编译,还会检查msvcr100.dll的版本,估计最后生成阶段会有一步CRT库Dll拷贝的动作。反正这里我们是使用VS2017编译,生成的可执行文件肯定不会依赖msvcr100.dll。所以这里我们就做做样子,给它传一个x86版本的msvcr100.dll路径吧。用下列命令进行配置

bash ./configure --with-freetype=/cygdrive/i/JVM/freetype -with-target-bits=32 --with-debug-level=slowdebug --with-jvm-variants=client with_toolsdir="/cygdrive/c/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/VC/Auxiliary/Build" --with-msvcr-dll="/cygdrive/i/jvm/msvcr100.dll"

执行后报了一个我们很熟悉的错误:

2017-12-19_145423

这个错误在之前用VS2010编译时也出现过,因此这里直接修改,在jdk8u-dev\common\autoconf下的generated-configure.sh中做如下修改:

 # First line typically looks something like:    # Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86    COMPILER_VERSION_TEST="19.12.15831"     # 直接指定    COMPILER_VERSION="19"   # 直接指定    COMPILER_VENDOR="Microsoft CL.EXE"      COMPILER_CPU_TEST="x86" # 直接指定    # 下面的一堆if全部删掉

再进行配置,万里长征第一步终于顺利走完了。

2017-12-19_150444

下面到了激动人心的编译时刻了。

make images

很快,一堆错误出现了。首先是MSC_VER没能被正确识别,然后是一堆编译错误——首先出现的就是JVM源码部分的一堆编译错误。于是决定先编译HotSpot VM项目,生成VS工程文件再说,即先将HostSpot项目导入VS2017中,利用VS2017快速修改其源码,使其通过编译。然而执行create.bat时马上就报错了:

2017-12-19_184809

打开jdk8u-dev\hotspot\make\windows下的create.bat,将以下代码删除掉。

cl 2>NUL >NULif %errorlevel% == 0 goto nexttestecho Make sure cl.exe is in your PATH before running this script.goto end:nexttestgrep -V 2>NUL >NULif %errorlevel% == 0 goto testitecho Make sure grep.exe is in your PATH before running this script. Either cygwin or MKS should work.goto end:testi# 然后在其中设置MSC_VER=1700即可

由于下面有一堆判断Visual Studio版本的逻辑,因此这里将版本设置到其支持的最高版本——VS2012的1700即可。然后在I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug中创建images和jdk两个目录,其中images下创建j2sdk-image,其中再创建bin文件。

2017-12-19_185504

完成工程文件的生成后,将其导入VS2017中。下面的操作在VS2017的IDE中完成。

首先解决C2220错误。

error C2220: warning treated as error - no object file generated”

到工程属性中关闭“将警告视为错误”选项即可,如下图所示:

2017-12-20_005856

然后是函数体重定义的编译错误:

jdk8u-dev\hotspot\src\share\vm\utilities/globalDefinitions_visCPP.hpp(190): error C2084: function 'int vsnprintf(char *const ,const ::size_t,const char *const ,va_list)' already has a body

这个问题是JVM中定义了自己的vsnprintf函数,和C库的vsnprintf函数撞衫了。于是直接使用VisualAssistx的重构功能,将JVM自定义的vsnprintf函数重命名为jvmvsnprintf即可:

2017-12-19_192522

然后是一大堆宏定义的报错。

2017-12-19_192730

这个问题比较在HotSpot VM中很常见,到处都有。其产生原因https://stackoverflow.com/questions/31738796/using-macro-with-string-fails-on-vc-2015

值得注意的是,使用旧版本的编译器不会有问题,因为这是启用C++11特性所带来的坑。其实就是这些宏本身就是字符串,其与两侧的分号应该有空格间隔。解决方案就是补加空格。如上图中由上角所示。在整个解决方案中搜索替换报错的语句,将其替换为两侧带空格的即可。以”ABCD”为例,需要进行下述两次替换:

"ABCD->" ABCDABCD"->ABCD "

全部完成后,编译错误瞬间降到了一个:

error C2065: 'timezone': undeclared identifier

经过搜索,在https://bugs.chromium.org/p/webrtc/issues/detail?id=4521找到了解决方案。在VS2017中要换一种获取方式,如下所示:

#if defined(_ALLBSD_SOURCE)  const time_t zone = (time_t) time_struct.tm_gmtoff;#else#if _MSC_VER < 1900  const time_t zone = timezone;#else  const time_t zone = 0;  _get_timezone((long *)&zone);#endif#endif

把上面这些坑都填平后,HotSpot VM的编译终于告一段落了。

2017-12-19_200703

make过程

继续脚本编译,果不其然又报错了:

2017-12-19_200848

先找出负责link版本的那个make文件:jdk8u-dev\hotspot\make\windows\makefiles\sanity.make,将对cl和link版本进行判断的脚本注释掉。

然后打开jdk8u-dev\hotspot\make\windows\makefiles下的compile.make,做如下修改:

# 第56行 去掉/WXCXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3# 第123行,去掉判定逻辑,强制指定COMPILER_NAME=VS2012

保存后继续编译,眼看快成功时,又报错了:

2017-12-19_205326

这个问题貌似是动态CRT库和静态CRT库打架了,但JVM貌似全部都依赖的是动态库啊,不然也不会让传入msvcr100.dll路径了。上网查了半天,终于发现问题了:

We resolved the issue. Seems we had the following in one of our header files to work around in issue with one of the earlier versions of VS 2012.

说白了这是历史遗留问题,VS2012时代的历史遗留产物到了VS2017时代不好用了,也就是下面这两个家伙需要被干掉:

#define _STATIC_CPPLIB#define _DISABLE_DEPRECATE_STATIC_CPPLIB

没招了,在文件夹中全局搜索“_STATIC_CPPLIB”字样,只要不是出现在PDB文件里,咱们统统将其干掉。

----------------------------------------“在 'I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\config.status' 中查找 '_STATIC_CPPLIB' (2017/12/19 星期二 15:04:22; 2017/12/19 星期二 15:04:24):”I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\config.status(662): S["CXXFLAGS_JDKEXE"]=" -nologo  -Zi -MD -Zc:wchar_t- -W3 -wd4800       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN       -D_CRT_SECURE_NO_DE"\I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\config.status(667): S["CXXFLAGS_JDKLIB"]=" -nologo  -Zi -MD -Zc:wchar_t- -W3 -wd4800       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN       -D_CRT_SECURE_NO_DE"\I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\config.status(673): S["CFLAGS_JDKEXE"]=" -nologo  -Zi -MD -Zc:wchar_t- -W3 -wd4800       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN       -D_CRT_SECURE_NO_DE"\I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\config.status(678): S["CFLAGS_JDKLIB"]=" -nologo  -Zi -MD -Zc:wchar_t- -W3 -wd4800       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN       -D_CRT_SECURE_NO_DE"\找到 '_STATIC_CPPLIB' 8 次。----------------------------------------“在 'I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\spec.gmk' 中查找 '_STATIC_CPPLIB' (2017/12/19 星期二 15:04:25; 2017/12/19 星期二 15:04:25):”I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\spec.gmk(327): CFLAGS_JDKLIB:= -nologo  -Zi -MD -Zc:wchar_t- -W3 -wd4800       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN       -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE       -DWIN32 -DIAL -D_X86_ -Dx86  -D_LITTLE_ENDIAN -DWINDOWS -DDEBUG -DARCH='"i586"' -Di586 -DRELEASE='"$(RELEASE)"'       -I/cygdrive/i/jvm/jdk8u-dev/build/windows-x86-normal-client-slowdebug/jdk/include       -I/cygdrive/i/jvm/jdk8u-dev/build/windows-x86-normal-client-slowdebug/jdk/include/windows       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/share/javavm/export       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/windows/javavm/export       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/share/native/common       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/windows/native/common     I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\spec.gmk(328): CXXFLAGS_JDKLIB:= -nologo  -Zi -MD -Zc:wchar_t- -W3 -wd4800       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN       -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE       -DWIN32 -DIAL -D_X86_ -Dx86  -D_LITTLE_ENDIAN -DWINDOWS -DDEBUG -DARCH='"i586"' -Di586 -DRELEASE='"$(RELEASE)"'       -I/cygdrive/i/jvm/jdk8u-dev/build/windows-x86-normal-client-slowdebug/jdk/include       -I/cygdrive/i/jvm/jdk8u-dev/build/windows-x86-normal-client-slowdebug/jdk/include/windows       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/share/javavm/export       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/windows/javavm/export       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/share/native/common       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/windows/native/common      I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\spec.gmk(331): CFLAGS_JDKEXE:= -nologo  -Zi -MD -Zc:wchar_t- -W3 -wd4800       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN       -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE       -DWIN32 -DIAL -D_X86_ -Dx86  -D_LITTLE_ENDIAN -DWINDOWS -DDEBUG -DARCH='"i586"' -Di586 -DRELEASE='"$(RELEASE)"'       -I/cygdrive/i/jvm/jdk8u-dev/build/windows-x86-normal-client-slowdebug/jdk/include       -I/cygdrive/i/jvm/jdk8u-dev/build/windows-x86-normal-client-slowdebug/jdk/include/windows       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/share/javavm/export       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/windows/javavm/export       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/share/native/common       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/windows/native/common   I:\jvm\jdk8u-dev\build\windows-x86-normal-client-slowdebug\spec.gmk(332): CXXFLAGS_JDKEXE:= -nologo  -Zi -MD -Zc:wchar_t- -W3 -wd4800       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN       -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE       -DWIN32 -DIAL -D_X86_ -Dx86  -D_LITTLE_ENDIAN -DWINDOWS -DDEBUG -DARCH='"i586"' -Di586 -DRELEASE='"$(RELEASE)"'       -I/cygdrive/i/jvm/jdk8u-dev/build/windows-x86-normal-client-slowdebug/jdk/include       -I/cygdrive/i/jvm/jdk8u-dev/build/windows-x86-normal-client-slowdebug/jdk/include/windows       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/share/javavm/export       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/windows/javavm/export       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/share/native/common       -I/cygdrive/i/jvm/jdk8u-dev/jdk/src/windows/native/common   找到 '_STATIC_CPPLIB' 8 次。----------------------------------------“在 'I:\jvm\jdk8u-dev\common\autoconf\generated-configure.sh' 中查找 '_STATIC_CPPLIB' (2017/12/19 星期二 13:06:27; 2017/12/19 星期二 15:03:25):”I:\jvm\jdk8u-dev\common\autoconf\generated-configure.sh(30017):       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN \找到 '_STATIC_CPPLIB' 2 次。----------------------------------------“在 'I:\jvm\jdk8u-dev\common\autoconf\toolchain.m4' 中查找 '_STATIC_CPPLIB' (2017/12/19 星期二 13:06:27; 2017/12/17 星期日 11:07:41):”I:\jvm\jdk8u-dev\common\autoconf\toolchain.m4(1068):       -D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB -DWIN32_LEAN_AND_MEAN \找到 '_STATIC_CPPLIB' 2 次。----------------------------------------“在 'I:\jvm\jdk8u-dev\hotspot\make\windows\makefiles\adlc.make' 中查找 '_STATIC_CPPLIB' (2017/12/19 星期二 13:07:40; 2017/12/17 星期日 11:08:56):”I:\jvm\jdk8u-dev\hotspot\make\windows\makefiles\adlc.make(29): # $(MS_RUNTIME_OPTION) ( with /D_STATIC_CPPLIB)找到 '_STATIC_CPPLIB' 1 次。----------------------------------------“在 'I:\jvm\jdk8u-dev\hotspot\make\windows\makefiles\compile.make' 中查找 '_STATIC_CPPLIB' (2017/12/19 星期二 13:07:40; 2017/12/19 星期二 20:34:01):”I:\jvm\jdk8u-dev\hotspot\make\windows\makefiles\compile.make(160): #     /D _STATIC_CPPLIB /D _DISABLE_DEPRECATE_STATIC_CPPLIBI:\jvm\jdk8u-dev\hotspot\make\windows\makefiles\compile.make(162): # Always add the _STATIC_CPPLIB flagI:\jvm\jdk8u-dev\hotspot\make\windows\makefiles\compile.make(163): STATIC_CPPLIB_OPTION = /D _STATIC_CPPLIB /D _DISABLE_DEPRECATE_STATIC_CPPLIB找到 '_STATIC_CPPLIB' 5 次。

这么多文件里,一个个修改。好在这两个宏基本定义都在一起,所以删起来倒也挺方便。都改好以后,执行一次清理操作:

make clean

继续构建,然后出现了上一篇文章中提到过的换行符问题,解决完成后,编译通过。

这里写图片描述

此时强制使用VS2017重新生成jvm.dll后,解压其符号与java.exe的符号即可开始调试。
20171221注:在VS的调试命令参数中,加入-XXaltjvm=$(TargetDir)参数,则默认使用VS2010编译得到的jvm.dll,由于jvm.pdb也在该目录下,所以可以直接调试,无需对jvm相应的压缩包进行任何解压操作了(java.exe的还是需要的)。另外加入的类路径最好放在最后。

第一个断点

阅读全文
0 0
原创粉丝点击