编译 下载源码 AdoptOpenJDK/openjdk-jdk11u
jdk-updates
准备boot JDK JDK release
C:\Program Files (x86)\Tencent\微信web开发者工具\dll
安装vs2017
使用C++的桌面开发
通用Windows平台开发
语言包选择English
cygwin 安装必要软件包 <path to Cygwin setup>/setup-x86_64 -q -P autoconf -P make -P unzip -P zip
configu & compile 配置
cd path/openjdk17 bash configure --with-debug-level=slowdebug --with-jvm-variants=server --disable-zip-debug-info --disable-warnings-as-errors --with-boot-jdk=/mnt/d/Aproject/openjdk/
编译
生成compile-database
使用wsl编译 安装必要软件包 下载好jdk源码后,解压到d:\openjdk\jdk11u
打开wsl shell,进入jdk源码目录
配置
bash configure --with-debug-level=slowdebug --with-jvm-variants=server --disable-zip-debug-info --disable-warnings-as-errors --with-boot-jdk=/mnt/d/Aproject/openjdk/
编译
生成 compile database
编译特定的模块
make CONF=config java.base-lib
Clion Debug Run/Debug Configurations > new Custom Build Application
name: jdk11-spring-boot-debug
Executeble:build\jdk\bin\java.exe
Program arguments:
-Xdebug -XX:+UseSerialGC -Xrunjdwp:server=y,transport=dt_socket,address=8099,suspend=n -Xlog:gc -Xms1000M -Xmn1000M -XX:-DoEscapeAnalysis -XX:+UseTLAB -XX:-ResizeTLAB -jar "D:\AProject\edian\backend\etc\api\certification-service\target\cs1.jar" -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintCompilation -XX:+PrintInlining -XX:CompileCommand=quiet
Environment variables:
ref code: src/java.base/share/native/launcher/main.c:146
#ifdef _WIN32 { int i = 0 ; if (getenv (JLDEBUG_ENV_ENTRY) != NULL ) { printf ("Windows original main args:\n" ); for (i = 0 ; i < __argc ; i++) { printf ("wwwd_args[%d] = %s\n" , i, __argv[i]); } } }
问题 assert(strcmp(value, system_value) == 0) failed: property value mustn’t differ from System.getProperty 出现这个问题,通常日志如下
# To suppress the following error report, specify this argument # after -XX: or in .hotspotrc: SuppressErrorAt=\statSampler.cpp:204 # # A fatal error has been detected by the Java Runtime Environment: # # Internal Error (d:\aproject\openjdk\jdk17\src\hotspot\share\runtime\statSampler.cpp:204), pid=4488, tid=21828 # assert(strcmp(value, system_value) == 0) failed: property value mustn't differ from System.getProperty # # JRE version: OpenJDK Runtime Environment (17.0) (slowdebug build 17-internal+0-adhoc.edian.jdk17) # Java VM: OpenJDK 64-Bit Server VM (slowdebug 17-internal+0-adhoc.edian.jdk17, mixed mode, tiered, compressed oops, com pressed class ptrs, g1 gc, windows-amd64) # Core dump will be written. Default location: D:\AProject\openjdk\jdk17\build\windows-x86_64-server-slowdebug\jdk\bin\h s_err_pid4488.mdmp
该问题是由于在bash configure
阶段,启用了调试,如--with-debug-level=*debug
(*指的是 slow
,fast
) 相关定义可在如下文件找到
make/hotspot/lib/JvmFlags.gmk:81
ifeq ($(DEBUG_LEVEL) , release) ifneq ($(HOTSPOT_DEBUG_LEVEL) , optimized) JVM_CFLAGS_DEBUGLEVEL := -DPRODUCT endif else ifeq ($(DEBUG_LEVEL) , fastdebug) JVM_CFLAGS_DEBUGLEVEL := -DASSERT ifeq ($(call isTargetOs, windows aix) , false) JVM_CFLAGS_DEBUGLEVEL += -DCHECK_UNHANDLED_OOPS endif else ifeq ($(DEBUG_LEVEL) , slowdebug) JVM_CFLAGS_DEBUGLEVEL := -DASSERT -D_NMT_NOINLINE_ endif
定位到相关源码则是
statSampler.cpp:180
void StatSampler::assert_system_property (const char * name, const char * value, TRAPS) {#ifdef ASSERT ResourceMark rm (THREAD) ; Handle key_str = java_lang_String::create_from_str (name, CHECK); JavaValue result (T_OBJECT) ; JavaCalls::call_static (&result, vmClasses::System_klass (), vmSymbols::getProperty_name (), vmSymbols::string_string_signature (), key_str, CHECK); oop value_oop = result.get_oop (); assert (value_oop != NULL , "property must have a value" ); char * system_value = java_lang_String::as_utf8_string (value_oop); printf ("\tA system value: %s -> \n%s\n\n" ,name,system_value); assert (strcmp (value, system_value) == 0 , "property value mustn't differ from System.getProperty" ); #endif }
当比较到value
和system_value
不相等时,会抛出异常,
通过断点调试
此时的char* name
值为java.library.path
是由于环境变量PATH
中包含了带有中文的路径,导致system_value
转换为utf8时,中文字符转换为乱码,导致strcmp
不相等,从而抛出异常。
解决办法:把PATH
中的中文路径去掉,或者bash configure
阶段不要启用调试
补充1 如果是Windows平台 此时value
中存储的是GBK
编码后的path
值,value_oop存储的是UTF-16(LE)
编码后的path
值,经过
char* system_value = java_lang_String::as_utf8_string(value_oop);
后,system_value
存储的是utf8编码后的path
值,这个时候strcmp
比较字符串的结果是不相等的(因为有中文)
补充2 假如path
含有中文
字符 eg:c:\Hello\Abc-ZH-中文-Abc;
则有如下
字符
GBK
UTF16
UTF8
中
D6D0
4E2D
E4B8AD
文
CEC4
6587
E69687
value
内存中的值(GBK编码)
6d 33 32 3b 43 3a 5c 57 49 4e 44 4f 57 53 3b 63 │ m32;C:\WINDOWS;c │ 3a 5c 48 65 6c 6c 6f 5c 41 62 63 2d 5a 48 2d d6 │ :\Hello\Abc-ZH-· │ d0 ce c4 2d 41 62 63 3b 43 3a 5c 47 6e 75 57 69 │ ···-Abc;C:\GnuWi │
value_oop
在内存中的值(因为使用UTF16LE编码,所以字节序和大端模式相反)
57 00 53 00 3b 00 63 00 3a 00 5c 00 48 00 65 00 │ W·S·;·c·:·\·H·e· │ 6c 00 6c 00 6f 00 5c 00 41 00 62 00 63 00 2d 00 │ l·l·o·\·A·b·c·-· │ 5a 00 48 00 2d 00 2d 4e 87 65 2d 00 41 00 62 00 │ Z·H·-·-N·e-·A·b· │ 63 00 3b 00 43 00 3a 00 5c 00 47 00 6e 00 75 00 │ c·;·C·:·\·G·n·u· │ 57 00 69 00 6e 00 33 00 32 00 5c 00 62 00 69 00 │ W·i·n·3·2·\·b·i· │
system_value
在内存中的值(UTF8编码)
6d 33 32 3b 43 3a 5c 57 49 4e 44 4f 57 53 3b 63 │ m32;C:\WINDOWS;c │ 3a 5c 48 65 6c 6c 6f 5c 41 62 63 2d 5a 48 2d e4 │ :\Hello\Abc-ZH-· │ b8 ad e6 96 87 2d 41 62 63 3b 43 3a 5c 47 6e 75 │ ·····-Abc;C:\Gnu │
补充3 utf8
最小代码单元是一个字节
utf16
的最小代码单元是2个字节
complication-database.json 导入clion无法正确编译 使用make compile-commands
生成 compilation-database.json
将其导入到clion中,出现编译错误,原因是因为json中的编译命令路径问题,需要把\\\\
和 \\
替换为/
,然后重新导入即可。
arguments.cpp 969 解析+-参数选项 1162 解析JVM -XX参数
ref
jvm char*在内存中的存储方式为小端模式
查看字符编码
Unicode和UTF编码转换
jstring 转char*jstring value_oop; java_lang_String::as_utf8_string (value_oop)
Can not determine compiler Cannot determine compiler type by executable file: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx86\x64\ml64.exe'
Clion plugins cidr-base-plugin.jar 定义了各种编译器匹配实现,以及编译器调用逻辑
OCCompilerResolver
编译器解析工具
OCBuiltInCompilerResolver
默认实现类
主要匹配以下编译器
private static final Map<String, OCCompilerKind> compilerCache = MapsKt.mapOf( new Pair []{ TuplesKt.to("cl" , MSVCCompilerKind.INSTANCE), TuplesKt.to("gcc" , GCCCompilerKind.INSTANCE), TuplesKt.to("g++" , GCCCompilerKind.INSTANCE), TuplesKt.to("xgcc" , GCCCompilerKind.INSTANCE), TuplesKt.to("xg++" , GCCCompilerKind.INSTANCE), TuplesKt.to("colorgcc" , GCCCompilerKind.INSTANCE), TuplesKt.to("cc" , GCCCompilerKind.INSTANCE), TuplesKt.to("c++" , GCCCompilerKind.INSTANCE), TuplesKt.to("cpp" , GCCCompilerKind.INSTANCE), TuplesKt.to("clang" , ClangCompilerKind.INSTANCE), TuplesKt.to("clang++" , ClangCompilerKind.INSTANCE), TuplesKt.to("emcc" , ClangCompilerKind.INSTANCE), TuplesKt.to("em++" , ClangCompilerKind.INSTANCE), TuplesKt.to("tiarmclang" , ClangCompilerKind.INSTANCE), TuplesKt.to("nvcc" , NVCCCompilerKind.INSTANCE), TuplesKt.to(OCBuiltInCompilerKindProvider.CLANG_CL_ID, ClangClCompilerKind.INSTANCE), TuplesKt.to("icl" , MSVCCompilerKind.INSTANCE), TuplesKt.to("icc" , GCCCompilerKind.INSTANCE), TuplesKt.to("icpc" , GCCCompilerKind.INSTANCE), TuplesKt.to("dpcpp-cl" , ClangClCompilerKind.INSTANCE) } );
clion-compdb.jar 主要用于解析compile-commands.json
结构如下
[ { "directory" : "/home/user/llvm/build" , "arguments" : [ "/usr/bin/clang++" , "-Irelative" , "-DSOMEDEF=With spaces, quotes and \\-es." , "-c" , "-o" , "file.o" , "file.cc" ] , "file" : "file.cc" } , { "directory" : "/home/user/llvm/build" , "command" : "/usr/bin/clang++ -Irelative -DSOMEDEF=\"With spaces, quotes and \\-es.\" -c -o file.o file.cc" , "file" : "file2.cc" } , ... ]
当通过Clion
打开compile-commands.json
后,会进行Sync
操作,触发CompDBProjectResolver#resolveProjectInfo
通过遍历compile-commands.json
中的command
值,校验command
是否符合 cidr-base-plugin.jar
中定义的编译器。
如果command
中的命令不符合上述的编译器,那么会出现 Cannot determine compiler type by executable file: '/path/xxx'
这个错误,导致导入失败
private final void reportUnresolvedCompilers (ExternalSystemTaskId resolveTaskId, Set<? extends File> set, ExternalSystemTaskNotificationListener listener, String parentEventId) { if (set.isEmpty()) { return ; } for (File compiler : set) { String message = CompDBBundle.message("project.resolver.cannot.resolve.compiler.error" , compiler); Intrinsics.checkNotNullExpressionValue(message, "CompDBBundle.message(\"pr…ompiler.error\", compiler)" ); listener.onTaskOutput(resolveTaskId, message + "\n" , false ); CompDBLog.INSTANCE.getLOG().debug(message); String compilerEventId = "unresolved-compiler:" + UUID.randomUUID(); OperationDescriptor taskOperationDescriptorImpl = new TaskOperationDescriptorImpl (message, System.currentTimeMillis(), "unresolved-compiler" ); ExternalSystemProgressEvent externalSystemStartEventImpl = new ExternalSystemStartEventImpl (compilerEventId, parentEventId, taskOperationDescriptorImpl); ExternalSystemProgressEvent externalSystemFinishEventImpl = new ExternalSystemFinishEventImpl (compilerEventId, parentEventId, taskOperationDescriptorImpl, new FailureResultImpl (externalSystemStartEventImpl.getEventTime(), externalSystemStartEventImpl.getEventTime(), CollectionsKt.listOf(new FailureImpl (message, message, CollectionsKt.emptyList())))); listener.onStatusChange(new ExternalSystemTaskExecutionEvent (resolveTaskId, externalSystemStartEventImpl)); listener.onStatusChange(new ExternalSystemTaskExecutionEvent (resolveTaskId, externalSystemFinishEventImpl)); } }
解决方法 找到compile_commands.json
把所有含ml64.exe
相关的commands
删掉(注意删掉的是一个整体)
样例
[ { "directory" : "d:/aproject/openjdk/jdk17/make" , "file" : "d:/aproject/openjdk/jdk17/src/jdk.incubator.vector/windows/native/libsvml/svml_d_acos_windows_x86.S" , "command" : "c:/progra~2/micros~2/2017/commun~1/vc/tools/msvc/1416~1.270/bin/hostx86/x64/ml64.exe -nologo -c -Fod:/aproject/openjdk/jdk17/build/windows-x86_64-server-slowdebug/support/native/jdk.incubator.vector/libsvml/svml_d_acos_windows_x86.obj d:/aproject/openjdk/jdk17/src/jdk.incubator.vector/windows/native/libsvml/svml_d_acos_windows_x86.S" } ]
再重新导入一下即可
Menu > Tools > Compilation Database > Reload Compilation Database Project
reference Tips & Tricks: Develop OpenJDK in CLion with Pleasure
GC垃圾回收器 调整参数
不同版本 OpenJDK 源码调试方案
WSL
在Ubuntu中编译和调试OpenJDK
编译 openJDK
Ubuntu下使用rpm
windows 平台编译openjdk12
tar教程
OpenJDK 编译指南(Ubuntu 16.04 + MacOS 10.15)
Cygwin
OpenJDK 编译指南(Ubuntu 16.04 + MacOS 10.15)