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的想法,然而经过搜索并没能在网上找到类似的文章和教程,于是只得靠自己摸索了。
首先放上我的环境信息:
Microsoft Windows 10 LTSB 2016版本(补丁更新到最新)
Visual Studio 2017(补丁更新到最新,装有VisualAssistX插件)
JDK Win64 8u152版本
Cygwin x64版本,已装好了需要的组件
freetype 2.81版本,已用VS2017编译好x86的Dll版本,放在I:\jvm\freetype目录下
OpenJDK v8源码最新版本,放在I:\jvm\jdk8u-dev目录下
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时会报错:
打开/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"
执行后继续报错:
看来程序考虑的比较周到,如果是在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"
执行后报了一个我们很熟悉的错误:
这个错误在之前用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全部删掉
再进行配置,万里长征第一步终于顺利走完了。
下面到了激动人心的编译时刻了。
make images
很快,一堆错误出现了。首先是MSC_VER没能被正确识别,然后是一堆编译错误——首先出现的就是JVM源码部分的一堆编译错误。于是决定先编译HotSpot VM项目,生成VS工程文件再说,即先将HostSpot项目导入VS2017中,利用VS2017快速修改其源码,使其通过编译。然而执行create.bat时马上就报错了:
打开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文件。
完成工程文件的生成后,将其导入VS2017中。下面的操作在VS2017的IDE中完成。
首先解决C2220错误。
error C2220: warning treated as error - no object file generated”
到工程属性中关闭“将警告视为错误”选项即可,如下图所示:
然后是函数体重定义的编译错误:
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即可:
然后是一大堆宏定义的报错。
这个问题比较在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的编译终于告一段落了。
make过程
继续脚本编译,果不其然又报错了:
先找出负责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
保存后继续编译,眼看快成功时,又报错了:
这个问题貌似是动态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的还是需要的)。另外加入的类路径最好放在最后。
- Java虚拟机原理分析之Win10下VS2017编译OpenJDK8与单步调试HotSpot VM过程详细记录
- Java虚拟机原理分析之Win7下VS2010编译OpenJDK8与单步调试HotSpot VM过程详细记录
- Java虚拟机学习笔记-记录一次编译OpenJDK8与调试的过程
- CentOS上编译OpenJDK8源码 以及 在eclipse上调试HotSpot虚拟机源码
- Java虚拟机学习笔记(1)Windows下编译OpenJDK8
- java虚拟机之HotSpot
- Java虚拟机hotspot源码分析之找门
- Win10 64位 VS2017下GDAL2.21编译之添加HDF5库编译C#版
- win10+vc6+单步调试报错
- 修改,编译,GDB调试openjdk8源码(docker环境下)
- ubuntu下编译ffmpeg 并单步调试
- linux在eclipse下编译并单步调试libevent
- windows下构建 HotSpot 虚拟机编译环境
- vs2010中进行ffmpeg编译与单步调试
- Java虚拟机学习记录,HotSpot对象创建
- matlab之断点调试与单步调试
- Linux下编译OpenJDK源码以及在Eclipse中调试Hotspot虚拟机
- Java虚拟机(HOTSPOT)源代码编译步骤
- 常用JS插件
- 数据分析/数据挖掘/机器学习---- 必读书目
- nexus3.3.1上传第三方jar包
- 线程的基本概念,基本状态、状态之间的关系
- Error: Failed to fetch platform ios Probably this is either a connection problem, or platform speci
- Java虚拟机原理分析之Win10下VS2017编译OpenJDK8与单步调试HotSpot VM过程详细记录
- Day014
- JavaWeb自主学习--JavaScript(一),day3
- 《Python网络数据采集》第一章、第二章(阅读代码笔记)
- cs231课程---作业1总结
- C#读写xml总结
- Service Unavailable HTTP Error 503. The service is unavailable.应用程序池就会自动关闭。
- BZOJ3669 [Noi2014]魔法森林
- 基于mvc模式的应用框架之Hibernate(五)