暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

基于Win10新特性WSL+VSCode调试Hotspot虚拟机

万力王 2020-07-17
1056
Microsoft这几年在不断拥抱开源,拥抱开发者社区。除了收购github外,它在Win10中加入了新特性WSL(Windows Sub-System for Linux),这使得开发者真正有机会在享受Windows PC的便利同时,又能有机会有一套真正意义上(在此之前的选择主要是Cygwin)基于Linux内核的开发系统环境。
同时,同时我觉得Visual Studio Code(VSCode)也是最近几年微软颠覆自我的一个IDE工具,它能以轻量级、插件化的形式可以适配到任何语言的开发。做过.NET开发的同学都知道几代Visual Studio工具都是非常重的IDE,安装更新都要几个小时,虽然功能齐全,但也仅仅局限在微软自己的生态中。而Visual Studio Code的出现也体现出微软意识到固步自封的局限性。我个人觉得,目前VSCode在Java、Python等语言的开发上还比不上Jetbrains的IDE,但未来可期。
为此,我花了几个周末时间,尝试基于WSL+VSCode来调试一把hotspot虚拟机,整理出来分享给大家。

一、准备工作

  1. Win10:请将Win10专业版/企业版更新到最新版本,否则安装WSL特性可能会卡住。

  2. WSL: Powershell中直接输入:
    dism.exe online enable-feature featurename:Microsoft-Windows-Subsystem-Linux all norestart 
    具体参考如下地址:
    https://docs.microsoft.com/zh-cn/windows/wsl/install-win10

  3. Ubuntu: 在Microsoft Store里搜索Ubuntu,点击安装。(按照自己习惯的Linux系统下载就行,我这用的Ubuntu)然后就可以把Ubuntu当作一个普通的应用打开了,如下图。

  4.  VSCode:下载Visual Studio Code:
    https://code.visualstudio.com/

  5. openjdk:下载openjdk8源码,jdk8调试起来比较麻烦,因为需要jdk7作为boot-jdk,而jdk7已经archive了,无法直接通过linux的包管理来安装,所以需要自己手动下载。
    jdk8源码:
    http://openjdk.java.net/projects/jdk8/
    https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-src-b04-14_jan_2020.zip
    jdk7:
    https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html



二、WSL内开发环境安装


打开Ubuntu后,我们先建议一个空目录,然后把jdk相关文件复制到这里(/mnt/d就是windows的d盘):
    mkdir openjdk
    cp /mnt/d/Graviton/Downloads/jdk-7u80-linux-x64.tar.gz openjdk/
    cp /mnt/d/Graviton/Downloads/jdk-8u41-src-b04-14_jan_2020.zip openjdk/
    用apt包管理命令直接下载所有相关的必要工具:
      sudo apt install build-essential zip unzip libxext-dev libx11-dev libxrender-dev libxtst-dev libxt-dev libcups2-dev libfreetype6-dev libasound2-dev gdb
      解压刚才复制的两个文件:
        cd openjdk
        tar -zxvf jdk-7u80-linux-x64.tar.gz
        unzip jdk-8u41-src-b04-14_jan_2020.zip
        我们要把环境变量PATH加上刚才jdk7的位置:
          vim ~/.profile

          在末尾加上,然后wq!保存:

            PATH="/home/graviton/openjdk/jdk1.7.0_80/bin:$PATH"
            最后确认下java版本
              java -version
              可以看到:


              到这里,我们大概完成了20%,接下来,为了能够让jdk8正确编译,我们需要把gcc降级到4.4版本,因为刚才默认安装的build-essential中默认安装的是最新版本的gcc,在新版本的gcc中,加强了对语法的检验标准,导致jdk8源码里大量编译报错。


              gcc4.4的版本太老了,需要加点包源:
                vim etc/apt/sources.list
                在最后加上这两行:
                  deb http://dk.archive.ubuntu.com/ubuntu/ trusty main universe
                  deb http://dk.archive.ubuntu.com/ubuntu/ trusty-updates main universe
                  wq!保存后,就可以安装gcc-4.4
                    sudo apt-get install gcc-4.4
                    sudo apt-get install g++-4.4
                    成功安装好后,把4.4调成默认版本,最后的100表示优先级,数字越高优先级越高,默认是60:
                      sudo update-alternatives --install usr/bin/gcc gcc usr/bin/gcc-4.4 100
                      sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.4 100
                      刚才我们有注意到,我们安装的Linux内核版本是4.4的,jdk8的hotspot的编译文件里只有支持到3以下的版本。因此我们需要改动点文件,让系统支持4以上的版本。
                      找到./hotspot/make/linux/Makefile文件,在里面搜索SUPPORTED_OS_VERSION,在最后加上“4%”
                        # We do not want people accidentally building on old systems (e.g. Linux 2.2.x,
                        # Solaris 2.5.1, 2.6).
                        # Disable this check by setting DISABLE_HOTSPOT_OS_VERSION_CHECK=ok.


                        SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% 4%
                        OS_VERSION := $(shell uname -r)
                        EMPTY_IF_NOT_SUPPORTED = $(filter $(SUPPORTED_OS_VERSION),$(OS_VERSION))
                        接下来,我们就可以开始正式编译jdk8了。
                          cd openjdk
                          chmod +x ./configure
                          ./configure --with-debug-level=slowdebug --with-freetype-include=/usr/include/freetype2 --with-freetype-lib=/usr/lib/x86_64-linux-gnu
                          运行成功后可以看到这样的提示:

                          接下来我们可以正式编译了:
                            make all
                            如果严格按照上面的步骤来安装的话,我们最终会看到这么一个report:

                            最后,我们可以验证下debug版的java是否成功:
                              cd build/linux-x86_64-normal-server-slowdebug/jdk/bin
                              ./java -version


                              三、VSCode的安装和配置

                              到此,我们完成了50%,我们下面转到VSCode上。

                              在VSCode的左边最后一个模块,搜索安装"Remote - WSL"插件,然后就能看到如下图的倒数第二个按钮。

                              (除此之外,我们还可以安装上其他需要的插件,比如C/C++ ,再按提示,点击“Install in WSL: Ubuntu"。)

                              点进去后,按照提示,我们可以建立wsl和VSCode的连接,如下图:

                              然后点击左侧第一个按钮,我们就能看到刚才我们解压和编译后的文件夹:


                              四、开始调试

                              至此我们准备工作都已经做完,我们可以开始尝试加断点,调试jdk和hotspot。

                              我们先随便写一段简单的java代码,比如:

                                # MainClass.java
                                public class MainClass {
                                public static void main(String[] args) {
                                String a = System.getenv().get("JAVA_HOME");
                                System.out.println(a);
                                    }
                                }

                                接着我们需要用javac把它编译成class文件,我们也可以直接用构建个maven项目,然后使用mvn clean compile来编译,然后记下target目录,后面需要用到。

                                接下来,我们回到VSCode,在菜单栏里点击Run->Add Configuration,在./.vscode文件夹下会生成一个launch.json文件,我们按下面,稍作修改:

                                  // .vscode/launch.json
                                  {
                                  // Use IntelliSense to learn about possible attributes.
                                  // Hover to view descriptions of existing attributes.
                                  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
                                  "version": "0.2.0",
                                  "configurations": [
                                  {
                                  "name": "(gdb) Launch",
                                  "type": "cppdbg",
                                  "request": "launch",
                                  "program": "${workspaceFolder}/build/linux-x86_64-normal-server-slowdebug/jdk/bin/java",
                                              "args": ["-cp""/mnt/d/codes/test/target/classes/""MainClass"],
                                  "stopAtEntry": true,
                                  "cwd": "${workspaceFolder}",
                                  "environment": [
                                  {"name": "JAVA_HOME", "value":"${workspaceFolder}/build/linux-x86_64-normal-server-slowdebug/jdk/bin"}
                                  ,{"name": "LD_LIBRARY_PATH","value": "${workspaceFolder}/build/linux-x86_64-normal-server-slowdebug/jdk/lib/amd64"}],
                                  "externalConsole": false,
                                  "MIMode": "gdb",
                                  "miDebuggerPath": "/usr/bin/gdb",
                                  "setupCommands": [
                                  {
                                  "description": "Enable pretty-printing for gdb",
                                  "text": "-enable-pretty-printing",
                                  "ignoreFailures": true
                                  }
                                  ]
                                  }
                                  ]
                                  }

                                  说明下这个配置文件里几个关键字段的意义:

                                  • type:使用dbg来做调试工具
                                  • program:执行程序的路径,这里就是我们编译好的java
                                  • args:传给program的参数,结合命令行,就是java的启动命令。结合上面的例子,实际就是在Terminal里输入下面这段:
                                    java -cp /mnt/d/codes/test/target/classes/ MainClass 
                                  • environment: 添加环境变量
                                  • miDebuggerPath: 指定调试工具gdb在wsl里的绝对路径

                                  然后我们就可以点击左侧第四个按钮,然后点击上面绿色的启动按钮""

                                  我们可以看到断点停在Java的main函数入口:

                                  (jdk/src/share/bin/main.c)

                                  我们接下来,找到hotspot/src/share/vm/prims/jni.cpp文件,搜索JNI_CreateJavaVM方法,这个hotspot虚拟机创建的入口方法,在它下面加个断点,继续支持,你会发现并不能命中这个断点,这是因为还缺少一个hotspot的debuginfo。

                                  我们继续回到wsl,执行下面的命令:

                                    unzip ./build/linux-x86_64-normal-server-slowdebug/jdk/lib/amd64/server/libjvm.diz

                                    我们再回来VSCode调试,我们就可以正常命中hotspot的入口方法了。

                                    最后执行完成后,在TERMINAL里可以看到我们Java代码打印出来的环境变量JAVA_HOME。

                                    至此,我们可以欢快地开启在Windows上探索Java核心实现代码的旅程
                                    (PS:我用Cygwin也成功跑完了整个流程,只是需要改了很多源文件,不够纯粹,不太适合当开发环境来用。)


                                    文章转载自万力王,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                    评论