前言
才开始看《深入理解Java虚拟机》�这本书,里面第一章就让我们编译jdk,记录一下踩坑的过程。
环境如下
Mac OS 11.1
xcode-select version 2384.
Apple clang version 12.0.0 (clang-1200.0.32.28)
CLion 20202.4
照着书上编译完后,说需要修改CMakeList.txt,否则用Clion进行调试的时候一些头文件会标红。
发现还是JetBrain官方推荐了另一种方法,Tips & Tricks: Develop OpenJDK in CLion with Pleasure
可以先看我的错误记录,修改了源码之后再直接看官方的然后跳到调试部分。
但是只看源码的话vscode 或许也是个很不错的选择,它最起码不会显示include的文件not found
编译jdk12
从http://hg.openjdk.java.net/jdk/jdk12/file/06222165c35f下载jdk12
安装如下依赖
brew install mercurial
brew install autoconf
brew install freetype
brew install ccache
下载jdk11,我原来就下载好了jdk,可以用brew安装jdk11
修改vim ~/.bash_profile
,这一步不是必须
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/
export JAVA_8_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/
export JAVA_11_HOME=/Library/Java/JavaVirtualMachines/jdk-11.0.8.jdk/Contents/Home/
#alias命令动态切换jdk版本
alias jdk8="export JAVA_HOME=$JAVA_8_HOME"
alias jdk11="export JAVA_HOME=$JAVA_11_HOME"
之后在终端输入jdk8或jdk11可以自动切换。
执行configure命令
bash configure --enable-debug --with-jvm-variants=server
之后可以看到一些配置信息,其中boot jdk是jdk11,而我系统中当前jdk是jdk8,所以它会��自动找到N-1版本的JDK,
之后可在build目录下生成一个配置目录,之后如果进行多次编译,或者目录产生后又修改了配置,记得先使用make clean
和make dist-clean
进入这个配置目录,查看生成文件,发现和书上的不太一样
$ tree
.
├── Makefile
├── bootcycle-spec.gmk
├── buildjdk-spec.gmk
├── compare.sh
├── configure-support
│ ├── classes.jsa
│ ├── config.log
│ └── config.status
├── configure.log
└── spec.gmk
编译
输入命令,加入compile-commands参数生成的是compilation database,如果不加这个参数,导入clion头文件一直都是红的,找不到路径。
$ sudo make compile-commands
错误记录
错误一:
make images时候出现
错误二:
打开该文件将这一行注释了,重新执行sudo make clean&&sudo make dist-clean,再执行出现以下错误
参考https://codingnote.cc/p/234919/进行修改,其中在sharedRuntime.cpp上有两处
错误三:
src/java.desktop/macosx/native/libawt_lwawt/awt/CSystemColors.m:134:9: error: converting the result of '?:' with integer constants to a boolean always evaluates to 'true' [-Werror,-Wtautological-constant-compare] if (colorIndex < (useAppleColor) ? sun_lwawt_macosx_LWCToolkit_NUM_APPLE_COLORS : java_awt_SystemColor_NUM_COLORS) { ^ 1 error generated.
参考https://github.com/openjdk/jdk/commit/4622a18a
最后出现下面的信息,就相当于编译成功了
Creating jdk image
Creating CDS archive for jdk image
Stopping sjavac server
Finished building target 'images' in configuration 'macosx-x86_64-server-fastdebug'
执行
make CONF=macosx-x86_64-server-fastdebug
进入jdk12/build/macosx-x86_64-server-fastdebug/jdk/bin
目录查看编译的java版本
$ ./java -version
openjdk version "12-internal" 2019-03-19
OpenJDK Runtime Environment (fastdebug build 12-internal+0-adhoc.root.jdk12)
OpenJDK 64-Bit Server VM (fastdebug build 12-internal+0-adhoc.root.jdk12, mixed mode)
至此,证明我们已经编译完成了 JDK12
compile-commands配置方式解释
在构建一个slowdebug
bash configure --with-debug-level=slowdebug --with-jvm-variants=server
make CONF=macosx-x86_64-server-slowdebug compile-commands
make CONF=macosx-x86_64-server-slowdebug
我debug级别为slowdebug,JetBrain推荐是fastdebug,我为了将两个编译的jdk项目区分
第一个make时候使用了CONF
参数,指定了要编译某个具体的配置,如果只有一个配置,可以省略,但我是编译了fastdebug
和slowdebug
两个级别的JDK
,所以使用了这个参数,执行完该命令,就会在${source_root}/build/macosx-x86_64-server-slowdebug
下生成compile_commands.json
文件。
第二个make是在导入CLion
之前,要编译一下,因为某些模块使用了预编译头,如果不编译,CLion
会在索引过程中提示找不到各种各样的文件。执行以下命令进行编译:
CLion 调试
因为正常情况下直接导入项目文件,会生成CmakeList.txt,书上说我们需要修改这个CmakeList.txt,而我不知道怎么修改,JetBrain官方给我们回答了这个问题。Tips & Tricks: Develop OpenJDK in CLion with Pleasure
生成Compilation Database,然后导入的时候选择compile_commands.json这个文件就好了
所以我用JetBrain官方的方法和通过 compile-commands参数编译之后的jdk和不通过compile-commands参数编译的jdk�也是和下面一样的配置。所以可以一起使用。
配置Toolchains
点击configurations,通过preference进入设置
选择Open or Import
选择compile-commands.json最后一定选上Open as Project
,然后会等待一段时间的索引
再点最上方的Tools->CMake->Change Project Root
,将根目录修改为jdk12所在的目录,就是包含build的目录
配置 Build Targets
配置make,Arguments
要加CONF=
配置clean,注意Arguments
除了要在前面加CONF=
最后还要加上clean
配置Run/Debug configurations
这里的java是编译之后的那个路径下的java二进制文件,即jdk12/macosx-x86_64-server-fastdebug/jdk/bin/java
${source_root}/src/java.base/share/native/libjli/java.c
的JavaMain函数打断点,点击Debug
,效果如下:
以下内容复制自参考博客
SIGSEGV
代表指针所对应的地址是无效地址,没有物理内存对应该地址。其实还有一个,是SIGBUS
,代表指针所对应的地址是有效地址,但总线不能正常使用该指针,通常是未对齐的数据访问所致。
MacOS
的CLion
默认使用LLDB
进行Debug
,所以要避免这种情况,可以通过在进入第一个断点时,执行以下命令避免后面出现此类问题:# LLDB使用如下命令,GDB暂不讨论,原理基本一致,可以自行搜索 pro hand -p true -s false SIGSEGV SIGBUS
这样虽然可以解决问题,但如果每次
Debug
都手动修改,会很繁琐。在JetBrains
的文章Develop OpenJDK in CLion with Pleasure中,文末也提到了解决这种问题,但我试了一下,却总是不生效,也没找到是什么原因。不过最后在这个博客中找到了一个解决方案,博主提到,
LLDB
只支持Session
级别的忽略设置(GDB
貌似支持全局,感兴趣的同学可以尝试),就是需要先启动Debug
,打断点,然后执行忽略命令,才可以生效。然后博主提出了一种解决方案,在~/.lldbinit
文件中,使用如下命令,实现每次Debug
时自动打个断点,然后输入pro hand -p true -s false SIGSEGV SIGBUS
,最后继续执行后续流程,文件内容如下(其中main.c
文件的路径自行替换):breakpoint set --file /Users/XXX/XXX/XXX/jdk12/src/java.base/share/native/launcher/main.c --line 98 -C "pro hand -p true -s false SIGSEGV SIGBUS" --auto-continue true
最后,在控制台查看输出。
修改CMakeList.txt的一点思路
思路一
因为slowdebug和fastdebug是在jdk12下的build目录下,导入的时候都将jdk12设置为project的根目录了,前者是compile-commands命令生成的,使用diffmerge查看两者有什么不一样的地方
逐渐往下翻,发现它们的不同在于除了一些命名,fastdebug多了些slowdebug没有的一点点东西,其余的slowdebug有的fastdebug的都有,那是不是可以合理猜测我根本就不用修这个CMakeList.txt了?
为了验证,我又将fastdebug重新编译了一遍作为对比,如下图,左边是新的参数为compile-commands,右边是旧的
他们的区别和前面的图其实是一样的。只不过之前是使用了make images命令,多了点东西。
建议还是用创建compilation database的方法。
思路二
打开https://github.com/ojdkbuild/ojdkbuild/tree/master/src,看到只有jdk8,11,13,15,没有12怎么办,我去历史记录里找到了12的CMakeList.txt,就是如下链接,下一步就是复制粘贴大法了
https://github.com/ojdkbuild/ojdkbuild/blob/599bc0f760b53e1ecf12777e0443ca991129c3a6/src/java-12-openjdk/CMakeLists.txt
但是这条路还是走不通