JDK编译

CHEN SHANGHE

_:nil

TOC TOC

Building in WSL

  1. 中文vs2019需要改下 make/autoconf/toolchain.m4 里的 Microsoft.*Compiler
  2. 在vs的prompt里build
  3. configure使用的命令:

    bash configure --with-boot-jdk=/mnt/d/Users/hh/Apps/jdk-14 --with-toolchain-version=2019 --with-tools-dir=/mnt/d/ProgramData/Microsoft/VisualStudio/2019_Community/VC/Auxiliary/Build/  --disable-warnings-as-errors 
    
    (之前是用13 boot的,14 ga后更换至14(13有些class不兼容的问题))
  4. 编译matcherCompiler.cpp失败,添加 --disable-warnings-as-errors 后编译成功
  5. 测试木有跑过,少了个啥 jtreg 之类的
  6. 使用的时候问题不大:
    1. 正常选用编译的jdk即可
    2. 源码需要在idea里设置到对应的路径:

      File -> Project Structures -> SDKs -> 选取对应的sdk 然后 添加 source path。 添加 src\java.base\share\classes 为 source path
    3. 更改源码的时候,需要到vs的prompt里(测试发现不在vs prompt也阔以)
    4. 执行 make java.base 不过这步非常慢…… 即使使用并行依旧很慢
  7. github的mirror拉下来换行格式不对、原因未名: 使用: ls -Recurse -File | % {dos2unix.exe $_.FullName $_.FullName} 修掉了 make 目录 重新checkout了一次,又好了,应该是和 autoclrf 之类的有关

    重新设置了 git config --global core.autocrlf false , 重新拉了一次, configuremake 都OK
  8. 并行compile阔以用 make JOBS=N

对于代码的一些改动

diff -r bb0a7975b31d make/autoconf/toolchain.m4
--- a/make/autoconf/toolchain.m4    Tue Dec 24 09:38:41 2019 +0000
+++ b/make/autoconf/toolchain.m4    Mon Jan 06 11:21:25 2020 +0800
@@ -452,7 +452,7 @@
     # Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
     COMPILER_VERSION_OUTPUT=`"$COMPILER" 2>&1 | $GREP -v 'ERROR.*UtilTranslatePathList' | $HEAD -n 1 | $TR -d '\r'`
     # Check that this is likely to be Microsoft CL.EXE.
-    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Microsoft.*Compiler" > /dev/null
+    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Microsoft.*" > /dev/null
     if test $? -ne 0; then
       AC_MSG_NOTICE([The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler.])
       AC_MSG_NOTICE([The result from running it was: "$COMPILER_VERSION_OUTPUT"])
@@ -460,8 +460,9 @@
     fi
     # Collapse compiler output into a single line
     COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT`
-    COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \
-        $SED -e 's/^.*ersion.\(@<:@1-9@:>@@<:@0-9.@:>@*\) .*$/\1/'`
+    # COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \
+    #     $SED -e 's/^.*ersion.\(@<:@1-9@:>@@<:@0-9.@:>@*\) .*$/\1/'`
+    COMPILER_VERSION_NUMBER='19.20.27508.1'
   elif test  "x$TOOLCHAIN_TYPE" = xgcc; then
     # gcc --version output typically looks like
     #     gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
@@ -1033,7 +1034,8 @@
   if test  "x$TOOLCHAIN_TYPE" = xmicrosoft; then
     # On Windows, double-check that we got the right compiler.
     CC_VERSION_OUTPUT=`$CC 2>&1 | $GREP -v 'ERROR.*UtilTranslatePathList' | $HEAD -n 1 | $TR -d '\r'`
-    COMPILER_CPU_TEST=`$ECHO $CC_VERSION_OUTPUT | $SED -n "s/^.* \(.*\)$/\1/p"`
+    # COMPILER_CPU_TEST=`$ECHO $CC_VERSION_OUTPUT | $SED -n "s/^.* \(.*\)$/\1/p"`
+    COMPILER_CPU_TEST='x64'
     if test "x$OPENJDK_TARGET_CPU" = "xx86"; then
       if test "x$COMPILER_CPU_TEST" != "x80x86" -a "x$COMPILER_CPU_TEST" != "xx86"; then
         AC_MSG_ERROR([Target CPU mismatch. We are building for $OPENJDK_TARGET_CPU but CL is for "$COMPILER_CPU_TEST"; expected "80x86" or "x86".])
diff -r bb0a7975b31d test/hotspot/gtest/utilities/test_json.cpp
--- a/test/hotspot/gtest/utilities/test_json.cpp    Tue Dec 24 09:38:41 2019 +0000
+++ b/test/hotspot/gtest/utilities/test_json.cpp    Mon Jan 06 11:21:25 2020 +0800
@@ -354,23 +354,23 @@
 TEST_VM(utilities, json_key_values_1) {
   JSON_GTest::test("/* comment */{ key1 : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\","
           "{ \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\""
-          " : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true);
+          " : true }, \"key6\" : [ \"santa\" ], key7 : \"val\",}", true);
 }

 TEST_VM(utilities, json_key_values_2) {
   JSON_GTest::test("/* comment */ { \"key1\" : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\","
           "{ \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\""
-          " : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true);
+          " : true }, \"key6\" : [ \"santa\" ], key7 : \"val\",}", true);
 }

 TEST_VM(utilities, json_quoted_symbols) {
-  JSON_GTest::test("/*comment*/{\"ff1 fsd\":{\"☃\":{\"☃\":[\"☃\",\"☃\"]},"
-          "\"☃\":true},\"☃\":[\"☃\"],\"foo\":\"☃\",}", true);
+  JSON_GTest::test("/*comment*/{\"ff1 fsd\":{\"santa\":{\"santa\":[\"santa\",\"santa\"]},"
+          "\"santa\":true},\"santa\":[\"santa\"],\"foo\":\"santa\",}", true);
 }

 TEST_VM(utilities, json_incorrect_key) {
-  JSON_GTest::test("/* comment */ { key1 error : { \"☃\" : { \"☃\" : [ \"☃\","
-          " \"☃\" ] }, \"☃\" : true }, \"baz\" : [ \"☃\" ], foo : \"☃\",}",
+  JSON_GTest::test("/* comment */ { key1 error : { \"santa\" : { \"santa\" : [ \"santa\","
+          " \"santa\" ] }, \"santa\" : true }, \"baz\" : [ \"santa\" ], foo : \"santa\",}",
           false); // first key needs to be quoted since it contains a space
 }

具体原因:

  1. 中文vs
  2. 似乎cl.exe编译这个符号 有点问题

issues

偶发lombok编译失败

估计是环境变量的问题

configure的时候偶发C compiler cannot create executables

使用vscode x64的promopt解决

JDK8标准库重新编译

参考: 编译src.zip Java1.8 src.zip_Java_u011515961的专栏-CSDN博客

编译后还是 exploded class,木有打成jar包,不过这没啥问题。

调整classpath路径稍微麻烦一点,要删掉原有rt.jar再添加

源码路径再选择:

JDK14 java.base 重新编译 ATTACH

Intelij Idea中阔以比较方便的查看java标准库的相关实现,但是为了更好的理解、更方便的实现或者添加相关备注等等,可以更改标准库的代码,重新编译会更方便一些。 JDK8及之前,标准库的相关实现都在 rt.jar 中,编译替换还是方便的。 JDK9之后,标准库的相关实现(默认link的runtime)都在 lib/modules 文件下,这就比较难改动了。

一番尝试后,比较方便的做法是:

编译 exploded 版本的openJDK。

默认编译的openJDK就是 exploded (以及debug)的,exploded即所有的module还是以class文件的方式放置在输出路径,具体来说,所有编译的class文件都位于 modules 文件夹下。 编译 openJDK 后,每次改动标准库java文件当然可以重新编译一次(使用内置的编译链工具, make java.base )即可。但是这样仍然很慢,比较之下,最后用 Intellij Idea在不对整个模块重新编译时会快很多。

openJDK在 windows 的编译可以参考 Building in WSL , WSL作编译工具的编译是最近的版本才添加的,以前都是 cygwin。

openjdk的编译还算比较方便,具体参考 Building OpenJDK 走一边就阔以。

在intellij idea中编译 java.base 模块

java.base 模块的源代码拷贝出来做一个单独的 maven 模块:

~\Repos\java.base-jdk-14\java.base\
├───pom.xml
├───src
│   └───main
│       └───java    <--- 这个目录即对应 openjdk 源码(留意从发行版中拷贝,别从源码拷贝)的目录
│           ├───com
│           ├───java
│           ├───javax
│           ├───jdk
│           ├───module-info.java
│           └───sun
└───target

拷贝出来作为一个 maven module的好处是:

a. 可以和intellij idea的编译链相互校验配置参数 b. 必要时可以使用maven的命令编译 c. 便于配置的持久化(当然intellij idea其实也是阔以的)

pom.xml 主要需要注意一下 build 节点中 javac 相关参数的设置:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <release>14</release>
                <compilerArgs>
                    <arg>
                        --patch-module=java.base=${project.basedir}/src/main/java
                    </arg>
                    <arg>
                        -XDstringConcat=inline
                    </arg>
                </compilerArgs>
            </configuration>
        </plugin>
    </plugins>

--patch-module 参数是因为 java.base 已经在包含在 openjdk 中了,再次编译的话需要添加这个命令行参数。 (⚠ 不过intelij idea似乎识别不了这个参数,导致整个 java.base 目录都需要被拷贝出来。直接用maven命令编译的话,只拷贝部分目录实测下也是可以的)

-XDstringConcat=inline 是因为编译后运行时的一个报错,具体可以参考: classpath - Patching java.base results in java.lang.LinkageError - Stack Overflow

intellij idea中配置编译jdk

这里的主要目的是区分开编译 java.base 所使用的openjdk和编译自己的测试/学习模块所使用的jdk。区分开阔以避免一些利用需要修改的jdk来编译修改的代码等等之类的问题。

Repos\java.base-jdk-14\
├───core  <- 个人测试/学习代码对应的模块
│   ├───pom.xml
│   ├───src
│   │   ├───main
│   │   │   └───java
│   │   └───test
│   │       └───java
│   └───target
├───java.base  <- 从 opendjk中拷贝的代码所对应的模块
│   ├───pom.xml
│   ├───src
│   │   └───main
│   │       └───java <- 拷贝的代码放在这里 (zip包中java.base目录)
│   └───target
└───pom.xml

这里最主要的注意点是:

idea中可以针对不同的模块设置不同的JDK:

将java.base编译结果外链回 exploded jdk

这个是前面提到的只能使用自行编译的exploded jdk的原因。从官网中下载的openjdk预编译版本,内置的模块里面的java.base总是会被先加载的,因此无法使用。(在jdk8的时候,还阔以通过更改classpath的方式,改zip包的方式加到rt.jar前面)

具体外链的关系是:

~\Repos\java.base-jdk-14\
├───core
│   ├───pom.xml
│   ├───src
│   │   ├───main
│   │   │   └───java
│   │   └───test
│   │       └───java
│   └───target
│       ├───classes
│       └───test-classes
│           └───core
├───java.base
│   ├───pom.xml
│   ├───src
│   │   └───main
│   │       └───java
│   └───target
│       └───classes
│           ├───com
│           ├───java  <--> 软链至 exploded jdk 的 modules/java.base/java目录
│           ├───javax
│           ├───jdk
│           ├───module-info.class
│           └───sun
└───pom.xml

windows下的具体软链命令为:

cmd /c mklink /J ~\Apps\jdk14-exploded\modules\java.base\java ~\Repos\java.base-jdk-14\java.base\target\classes\java

具体使用示例

按上面步骤做完后应该就阔以正常使用了。测试改一下代码:

public void lock() {
    System.out.println("lock in ReentrantLock");
    sync.lock();
}

编译的速度还是很快的,虽然使用maven/直接 make java.base 的方式也阔以达到更改源码、调试学习的目的,但是速度上还是比Intellij Idea编译慢很多。

尝试过程中的一些脚本和链接日志

*这部分仅作备忘和日志用途*,后面删掉,主要是为了后面看下模块系统

- split-package issue when compiling - JDK 10 · Issue #27 · javapathfinder/jpf-core

参考上面issue的设置,使用:

d:\Users\hh\Apps\jdk-14\bin\javac.exe -J-D"user.language=en" -J-D"file.encoding=UTF-8" --module-source-path=src --patch-module java.base=src/java.base -d build d:\Users\haha\Repos\java.base-jdk-14\src\java.base\java\io\Bits.java

可以正常build。尝试过的一个powershell脚本是:

,(ls .\src\ -Recurse  -File -Filter *.java).FullName | %{
    $total = $_.Length
    $_|%{$cnt=0}{
    $class_file =  $_|%{
            $_ -replace "\\src\\","\build\"
        }|%{
            $_ -replace "\.java$",".class"
        }
    Write-Debug $_
    $cnt = $cnt+1
    if(Test-Path $class_file) {
    } else {
        d:\Users\hh\Apps\jdk-14\bin\javac.exe -J-D"user.language=en" -J-D"file.encoding=UTF-8" --module-source-path=src --patch-module java.base=src/java.base/classes -d build $_
    }
    Write-Progress "Compiled $_" -PercentComplete (100.0 * $cnt / $total)
}}

可能也阔以用ant

虽然class文件是可以生成了,但是idea中SDK的classpath还是无法调整。

module - Is there a way to read programmatically a .jmod file in Java? - Stack Overflow

jmod 目前就是zip包,可以用替换文件的方式替换掉

目前来看阔以直接用模块系统搞定 Using jlink to Build Java Runtimes for non-Modular Applications

d:\Users\hh\Apps\jdk-14\bin\jlink.exe -J-D"user.language=en" --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base --output test-runtime

看看如果阔以选用自己的 java.base

jmod:

& "d:\Users\userxx\Apps\jdk-14\bin\jmod.exe" -J-D"user.language=en" create --class-path classes\ java.base.jmod

(可能不需要打jmod,直接exploded的classes也阔以用在module-path的位置)

留意一下version,jlink的version是jdk版本,因此maven里版本号按着走

Error: ModuleTarget attribute is missing

Filling the Packager gap

Getting Started with the Java Platform Module System Part 3 | Pluralsight

Java Modules

modules 在 d:-14

相对路径即 : lib\modules

https://stackoverflow.com/questions/46438557/how-to-extract-the-file-jre-9-lib-modules

还是回归用openjdk build的exploded了

即使用 exploded,还是有些问题(这块没整理好)

突然持续出现了这个错误:

stackoverflowerror

看着应该是和 java.lang 有关.

只同步 java 下面 像 util/io 之类的子模块好了,没有必要同步所有的

针对不同module可以用不同jdk

目前外链了 io/util/nio

cannot compile Java 9 module with –patch-module in IntelliJ IDEA 2017.2.1 - Stack Overflow

https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000716224-IntelliJ-ignores-Maven-compiler-options

Locating IDE log files – IDEs Support (IntelliJ Platform) | JetBrains

java - How can I see the javac command IntelliJ IDEA uses to compile my code? - Stack Overflow

只能够全部拷贝

classpath - Patching java.base results in java.lang.LinkageError - Stack Overflow

<arg>
-XDstringConcat=inline
</arg>

这个参数必须加上,参考上面的链接