win10上构建并调试openjdk 11

2021/06/13 Java 共 14339 字,约 41 分钟

前言

很早就想在windows上编译一遍java的源码,最近一直在尝试,中途试了很多方法,遇到了很多坑。

最后我把编译过程中遇到的困难和解决方法记录下来,希望对后来者有所帮助。

下载源码

Openjdk 11的源码存放在网址https://hg.openjdk.java.net/jdk-updates/jdk11u/上,下载方法有是点击左边的zip按钮,下载源码压缩包,具体地址如下:https://hg.openjdk.java.net/jdk-updates/jdk11u/archive/tip.zip

下载后大小189M,解压后大小600M。

编译与运行

openJdk的源码编译,有2种可选的工具,一种是使用Cygwin,另一种则是使用WSL

我推荐使用WSL,但使用Cygwin也写了,如果有人需要的话。

注意:WSL与Cygwin只需安装一个即可

使用WSL进行编译

安装WSL

首先安装WSL,具体的安装教程,见微软官方文档:在 Windows 10 上安装 WSL | Microsoft Docs

推荐安装Ubuntu 20.04 LTS这个版本的系统。

安装需要的软件

sudo su
apt update && apt upgrade
sudo apt install mercurial zip unzip make gcc g++ build-essential ccache libx11-dev libxext-dev libxrender-dev  libxrandr-dev libxtst-dev libxt-dev libcups2-dev libfreetype6-dev libasound2-dev libfontconfig1-dev ccache cmake gdb autoconf

安装Java

编译Java时,需要N-1版本的Java。如:编译Java 11需要电脑上,安装至少Java 10及以后的版本。

sudo apt install openjdk-11-jdk

编译OpenJdk

chmod +x configure
./configure --with-debug-level=slowdebug --with-native-debug-symbols=internal --disable-warnings-as-errors --enable-ccache

配置完成后进行编译:

make all

测试Java

测试一下编译完成的结果能否正常运行:

ubuntu@zhang:~/jdk11u-113c646a33d2$ ./build/linux-x86_64-normal-server-slowdebug/jdk/bin/java -version
openjdk version "11.0.12-internal" 2021-07-20
OpenJDK Runtime Environment (slowdebug build 11.0.12-internal+0-adhoc.ubuntu.jdk11u-113c646a33d2)
OpenJDK 64-Bit Server VM (slowdebug build 11.0.12-internal+0-adhoc.ubuntu.jdk11u-113c646a33d2, mixed mode)

新建Java文件,命名为hello.java

import java.util.concurrent.ThreadLocalRandom;

public class hello {

    private static final int REPETITIONS = 100_000_000;

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Hello World");
        for (var i = 0; i < REPETITIONS; i++) {
            Thread.sleep(1000);
            System.out.println("i is:" + i + ", current time is:" + System.currentTimeMillis() + ", random is:" + ThreadLocalRandom.current().nextLong());
        }
    }
}

运行Java文件:

ubuntu@zhang:~/jdk11u-113c646a33d2$ ./build/linux-x86_64-normal-server-slowdebug/jdk/bin/java hello.java
Hello World

调试Java在下一章节。

使用 Cygwin与Visual Studio进行编译

安装 Cygwin

openJdk的编译需要安装Cygwin作为GNU的环境,不推荐使用MSYS2

下载:setup-x86_64.exe

运行命令,安装需要的组件:

.\setup-x86_64.exe  -q -P autoconf -P make -P unzip -P zip -P gdb

安装Visual Studio

windows上的gcc版本需要选择vs中的c++编译器。

安装Visual Studio 2019 Community这个版本,工具组件选择使用C++的桌面开发这个组件。

注意:

1.安装目录,不要带有空格,否则要使用fsutil进行短路径转换,具体操作见报错解决。

2.对于老版本的openJdk源码,语言包要选择英文,不要选择中文,否则编译会失败。现在新版本的OpenJdk源码已经解决了这个问题。

3.安装时,在右边的使用C++的桌面开发这一栏中,勾选安装MSVC v141-VS 2017 C++。OpenJdk 11只支持VS 2017版本的c++,OpenJdk 15的源码编译支持了VS 2019

安装Java

编译Java时,需要N-1版本的Java。如:编译Java 11需要电脑上,安装至少Java 10及以后的版本。

下载链接:AdoptOpenJDK - Open source, prebuilt OpenJDK binaries

选择OpenJdk 11版本,JVM选择HotSpot

下载后安装,确定安装成功。

$ java.exe -version
openjdk version "11.0.9.1" 2020-11-04
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.9.1+1)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.9.1+1, mixed mode)

编译OpenJdk

使用Cygwin64 Terminal切换到源码目录,执行configure脚本,如果顺利的话不会报错。

需要指定VS的安装目录。

cd /cygdrive/d/jdk11u-113c646a33d2
./configure --with-debug-level=slowdebug --with-native-debug-symbols=external --disable-warnings-as-errors --with-tools-dir=/cygdrive/c/VS/VC/Auxiliary

警告:如果VS/Windows Kits目录带有空格,那么需要使用fsutil进行短路径转换,具体操作见报错解决

进行编译:

make all

编译时,如果遇到报错,可以看一下文章底下的报错解决中的问题。

顺利的话,一小时左右编译完成。完成后文件夹大小4G。

测试Java

测试一下编译完成的结果能否正常运行:

$ ./build/windows-x86_64-normal-server-slowdebug/images/jdk/bin/java -version
openjdk version "11.0.12-internal" 2021-07-20
OpenJDK Runtime Environment (slowdebug build 11.0.12-internal+0-adhoc.zhang.jdk11u-113c646a33d2)
OpenJDK 64-Bit Server VM (slowdebug build 11.0.12-internal+0-adhoc.zhang.jdk11u-113c646a33d2, mixed mode)

新建Java文件,命名为hello.java

import java.util.concurrent.ThreadLocalRandom;

public class hello {

    private static final int REPETITIONS = 100_000_000;

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Hello World");
        for (var i = 0; i < REPETITIONS; i++) {
            Thread.sleep(1000);
            System.out.println("i is:" + i + ", current time is:" + System.currentTimeMillis() + ", random is:" + ThreadLocalRandom.current().nextLong());
        }
    }
}

运行Java文件:

$ ./build/windows-x86_64-normal-server-slowdebug/images/jdk/bin/java hello.java
Hello World

调试Java

下面以调试WSL版本的Java为例。

1.运行Java程序:

ubuntu@zhang:~/jdk11u-113c646a33d2$ ./build/linux-x86_64-normal-server-slowdebug/jdk/bin/java hello.java
Hello World

2.找到Java程序的PID:

ubuntu@zhang:~$ jps
12257 Main
12302 Jps

3.使用gdb连上程序:

ubuntu@zhang:~$ gdb -p 12257
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
Attaching to process 12339
[New LWP 12340]
[New LWP 12341]
[New LWP 12342]
[New LWP 12343]
[New LWP 12344]
[New LWP 12345]
[New LWP 12346]
[New LWP 12347]
[New LWP 12348]
[New LWP 12349]
[New LWP 12350]
[New LWP 12351]
[New LWP 12352]
[New LWP 12353]
[New LWP 12354]
[New LWP 12357]
[New LWP 12360]
[New LWP 12361]
[New LWP 12362]
[New LWP 12363]
[New LWP 12364]
[New LWP 12365]
[New LWP 12366]
[New LWP 12367]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
__pthread_clockjoin_ex (threadid=140260516488960, thread_return=0x7ffcefea4328, clockid=<optimized out>,
    abstime=<optimized out>, block=<optimized out>) at pthread_join_common.c:145
145     pthread_join_common.c: No such file or directory.

添加断点,这里我选择main的源码实现

(gdb) list JavaMain
388         } while (JNI_FALSE)
389
390
391     int
392     JavaMain(void* _args)
393     {
394         JavaMainArgs *args = (JavaMainArgs *)_args;
395         int argc = args->argc;
396         char **argv = args->argv;
397         int mode = args->mode;
(gdb) break JavaMain
Breakpoint 1 at 0x7f845ebe341d: file ../src/java.base/share/native/libjli/java.c, line 393.

运行程序:

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/ubuntu/jdk11u-113c646a33d2/build/linux-x86_64-normal-server-slowdebug/jdk/bin/java
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff5c27700 (LWP 249)]
[Switching to Thread 0x7ffff5c27700 (LWP 249)]

Thread 2 "java" hit Breakpoint 1, JavaMain (_args=0x0) at ../src/java.base/share/native/libjli/java.c:393
393     {
(gdb) n
394         JavaMainArgs *args = (JavaMainArgs *)_args;
(gdb) n
395         int argc = args->argc;
(gdb) n
396         char **argv = args->argv;
(gdb) print *args
$1 = {argc = 0, argv = 0x5555555595a8, mode = 0, what = 0x0, ifn = {CreateJavaVM = 0x7ffff6a5a36b <JNI_CreateJavaVM(JavaVM**, void**, void*)>,
    GetDefaultJavaVMInitArgs = 0x7ffff6a59e91 <JNI_GetDefaultJavaVMInitArgs(void*)>, GetCreatedJavaVMs = 0x7ffff6a5a3a9 <JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*)>}}

可以看出,成功把断点打在了Java初始化的代码上。

后续可以调试想要的方法。

后记

写这篇花了挺多时间,主要是在探索各种报错如何解决,以及最终用哪个方法调试比较方便。

最终编译调试完成,虽然没有直接学到多少知识,解决问题的过程中,也算是学了挺多的。

报错解决

ls: cannot access ‘/cygdrive/d/VS2/VC/Redist/MSVC/*/x64/Microsoft.VC141.CRT/msvcp140.dll’: No such file or directory

遇到报错如下:

configure: Rewriting CYGWIN_VC_INSTALL_DIR to "/cygdrive/d/VS2/VC"
ls: cannot access '/cygdrive/d/VS2/VC/Redist/MSVC/*/x64/Microsoft.VC141.CRT/vcruntime140.dll': No such file or directory
configure: Found vcruntime140.dll at /cygdrive/c/progra~1/adopto~1/jdk-11~1.101/bin/vcruntime140.dll using well-known location in Boot JDK
checking found vcruntime140.dll architecture... ok
checking for vcruntime140.dll... /cygdrive/c/progra~1/adopto~1/jdk-11~1.101/bin/vcruntime140.dll
configure: Rewriting CYGWIN_VC_INSTALL_DIR to "/cygdrive/d/VS2/VC"
ls: cannot access '/cygdrive/d/VS2/VC/Redist/MSVC/*/x64/Microsoft.VC141.CRT/msvcp140.dll': No such file or directory
configure: Found msvcp140.dll at /cygdrive/c/progra~1/adopto~1/jdk-11~1.101/bin/msvcp140.dll using well-known location in Boot JDK
checking found msvcp140.dll architecture... ok
checking for msvcp140.dll... /cygdrive/c/progra~1/adopto~1/jdk-11~1.101/bin/msvcp140.dll
checking for UCRT DLL dir... configure: Rewriting CYGWIN_WINDOWSSDKDIR to "/cygdrive/d/windows kits/10"
no
configure: error: Could not find any dlls in
configure exiting with result code 1

解决方法:

出现这个问题的原因是,Java 11 的编译不支持VS 2019,这个问题官方在Java 15的编译中修复了:[JDK-8242468] VS2019 build missing vcruntime140_1.dll - Java Bug System

解决方案是使用visual studio installer,在右边的使用C++的桌面开发这一栏中,勾选安装MSVC v141-VS 2017 C++

安装完成后,这个报错就没了

configure: error: Could not find any dlls in

遇到如下报错

configure: Rewriting CYGWIN_VC_INSTALL_DIR to "/cygdrive/c/VS/VC"
POSSIBLE_MSVC_DLL /cygdrive/c/VS/VC/Redist/MSVC/14.16.27012/x64/Microsoft.VC141.CRT/vcruntime140.dll
configure: Found vcruntime140.dll at /cygdrive/c/VS/VC/Redist/MSVC/14.16.27012/x64/Microsoft.VC141.CRT/vcruntime140.dll using well-known location in VCINSTALLDIR
checking found vcruntime140.dll architecture... ok
checking for vcruntime140.dll... /cygdrive/c/VS/VC/Redist/MSVC/14.16.27012/x64/Microsoft.VC141.CRT/vcruntime140.dll
configure: Rewriting CYGWIN_VC_INSTALL_DIR to "/cygdrive/c/VS/VC"
POSSIBLE_MSVC_DLL /cygdrive/c/VS/VC/Redist/MSVC/14.16.27012/x64/Microsoft.VC141.CRT/msvcp140.dll
configure: Found msvcp140.dll at /cygdrive/c/VS/VC/Redist/MSVC/14.16.27012/x64/Microsoft.VC141.CRT/msvcp140.dll using well-known location in VCINSTALLDIR
checking found msvcp140.dll architecture... ok
checking for msvcp140.dll... /cygdrive/c/VS/VC/Redist/MSVC/14.16.27012/x64/Microsoft.VC141.CRT/msvcp140.dll
checking for UCRT DLL dir... configure: Rewriting CYGWIN_WINDOWSSDKDIR to "/cygdrive/d/windows kits/10"
no
configure: error: Could not find any dlls in
configure exiting with result code 1

这个报错的原因是,win10 sdk的目录带有空格,解决方法是修改文件make/autoconf/toolchain_windows.m4

        UCRT_DLL_DIR="`ls -d $CYGWIN_WINDOWSSDKDIR/Redist/*/ucrt/DLLs/$dll_subdir \

修改为

        UCRT_DLL_DIR="`ls -d "$CYGWIN_WINDOWSSDKDIR"/Redist/*/ucrt/DLLs/$dll_subdir \

修改后报错解决。

使用fsutil进行短路径转换

Cygwin不支持带有空格的路径,因此要把带空格的路径转化成不带空格的路径。

比如Windows Kits的安装路径为D:\Windows Kits,别名叫Kits2

使用管理员身份打开cmd,或者powershell

fsutil file setshortname "D:\Windows Kits" Kits2

转化后D:\Kits2等价于D:\Windows Kits

fatal error C1083: Cannot open include file: ‘crtdbg.h’: No such file or directory

遇到如下报错:

formssel.cpp
c:\VS\VC\Tools\MSVC\14.29.30037\include\yvals.h(12): fatal error C1083: Cannot open include file: 'crtdbg.h': No such file or directory
   ... (rest of output omitted)
* For target hotspot_variant-server_tools_adlc_objs_main.obj:
cl : Command line warning D9024 : unrecognized source file type 'kits/10/include/10.0.19041.0/ucrt', object file assumed
cl : Command line warning D9027 : source file 'kits/10/include/10.0.19041.0/ucrt' ignored
cl : Command line warning D9024 : unrecognized source file type 'kits/10/include/10.0.19041.0/shared', object file assumed
cl : Command line warning D9027 : source file 'kits/10/include/10.0.19041.0/shared' ignored
cl : Command line warning D9024 : unrecognized source file type 'kits/10/include/10.0.19041.0/um', object file assumed
cl : Command line warning D9027 : source file 'kits/10/include/10.0.19041.0/um' ignored
cl : Command line warning D9024 : unrecognized source file type 'kits/10/include/10.0.19041.0/winrt', object file assumed
cl : Command line warning D9027 : source file 'kits/10/include/10.0.19041.0/winrt' ignored
cl : Command line warning D9024 : unrecognized source file type 'kits/10/include/10.0.19041.0/cppwinrt', object file assumed
cl : Command line warning D9027 : source file 'kits/10/include/10.0.19041.0/cppwinrt' ignored
main.cpp
c:\VS\VC\Tools\MSVC\14.29.30037\include\yvals.h(12): fatal error C1083: Cannot open include file: 'crtdbg.h': No such file or directory
   ... (rest of output omitted)

* All command lines available in /cygdrive/d/jdk11u-113c646a33d2/build/windows-x86_64-normal-server-slowdebug/make-support/failure-logs.
=== End of repeated output ===

No indication of failed target found.
Hint: Try searching the build log for '] Error'.
Hint: See doc/building.html#troubleshooting for assistance.

make[1]: *** [/cygdrive/d/jdk11u-113c646a33d2/make/Init.gmk:305: main] Error 2
make: *** [/cygdrive/d/jdk11u-113c646a33d2/make/Init.gmk:186: all] Error 2


这是因为Windows Kits的目录带有空格,使用fsutil:

fsutil file setshortname "D:\Windows Kits" Kits

重新配置:

./configure --with-debug-level=slowdebug --with-native-debug-symbols=external --disable-warnings-as-errors --with-tools-dir=/cygdrive/c/VS/VC/Auxiliary

test_json.cpp(357): error C2143: syntax error: missing

遇到报错:

d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(371): note: see previous definition of 'TestBody'
make[3]: *** [lib/CompileGtest.gmk:61: /cygdrive/d/jdk11u-113c646a33d2/build/windows-x86_64-normal-server-slowdebug/hotspot/variant-server/libjvm/gtest/objs/test_json.obj] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [make/Main.gmk:272: hotspot-server-libs] Error 2

ERROR: Build failed for target 'hotspot' in configuration 'windows-x86_64-normal-server-slowdebug' (exit code 2)

=== Output from failing command(s) repeated here ===
* For target hotspot_variant-server_libjvm_gtest_objs_test_json.obj:
test_json.cpp
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(357): error C2143: syntax error: missing ')' before ']'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(355): error C2660: 'JSON_GTest::test': function does not take 1 arguments
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(49): note: see declaration of 'JSON_GTest::test'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(357): error C2143: syntax error: missing ';' before ']'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(357): error C2059: syntax error: ']'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(357): error C2017: illegal escape sequence
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(357): error C2059: syntax error: ')'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(363): error C2143: syntax error: missing ')' before ']'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(361): error C2660: 'JSON_GTest::test': function does not take 1 arguments
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(49): note: see declaration of 'JSON_GTest::test'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(363): error C2143: syntax error: missing ';' before ']'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(363): error C2059: syntax error: ']'
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(363): error C2017: illegal escape sequence
d:/jdk11u-113c646a33d2/test/hotspot/gtest/utilities/test_json.cpp(363): error C2059: syntax error: ')'
   ... (rest of output omitted)

* All command lines available in /cygdrive/d/jdk11u-113c646a33d2/build/windows-x86_64-normal-server-slowdebug/make-support/failure-logs.
=== End of repeated output ===

No indication of failed target found.
Hint: Try searching the build log for '] Error'.
Hint: See doc/building.html#troubleshooting for assistance.

make[1]: *** [/cygdrive/d/jdk11u-113c646a33d2/make/Init.gmk:305: main] Error 2
make: *** [/cygdrive/d/jdk11u-113c646a33d2/make/Init.gmk:186: hotspot] Error 2

可以看出这个错误是单测里的错误,解决方法如下:

1.删除这个文件或者删除报错的这个函数。

文档信息

Table of Contents