一、前言
以Java为主的研发人员,掌握JVM虚拟机是成为高级研发的必要门槛。本文就给大家分享下,如何在mac下编译openjdk源码。
题外话,本人认为:要想成为某一技术上的专家,熟读官方文档和掌握源码的分析能力是绝对必要的。
关于如何编译openjdk源码,网上的文章真是数不胜数,但是跟着网上的流程走,却很难顺利编译通过,因为这类文章作者其实都并没有完全把环境问题考虑全面。
要想编译通过,最好的方式就是阅读官方文档。
二、获取openjdk源码
openjdk源码是使用mercurial管理的,我们可以用hg(类似于git),将源码clone到本地
hg clone http://hg.openjdk.java.net/jdk9/jdk9 jdk9 //不要忘记安装mercuial哦
虽然这样可以获取源码,但是我亲测了下,很难,动不动网络断开,应该是与墙有关。
我这里提供另一种获取源码的方式,进入网址:jdk。选择相应版本,我这里选择9。
点击下面链接就可以下载源码了:
三、准备环境依赖
mac下比较好用的包管理工具推荐homwbrew,我们homwbrew来安装编译需要的依赖,如果么有安装homwbrew可以通过命令安装:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
安装依赖:
brew install ccache //加速编译
brew install freetype //字体引擎,编译过程中会被依赖到
四、编译
编译本身不复杂,但是最容易出问题的环节。
每个人编译的操作系统版本啊,编译器版本不尽相同,我编译成功不见得你就能编译成功,所以大家在编译时,还是要以官方的编译文档为主。文档就在你下载的openjdk的源码里。如下图:
1、编译环境
我的mac os的版本是10.14.2,通过app store安装的xcode是xcode10,在编译openjdk源码时失败了。官方文档里推荐使用的是:10.12.5 (Sierra), using XCode 8.3.2。
由于降操作系统版本太麻烦,我就卸载了通过app store安装的xcode10,到官网下载了xcode8.3.2。悲剧的是8.3.2在10.14.2的系统根本起不来。
于是抱着试试看的态度又下载了xcode9.2,比较幸运一切正常。
这里提供下下载xcode的官方链接:Sign In - Apple
2、编译
编译配置,我们可以调用如下命令设置编译,同时此脚本也会检查你当前的环境是否满足。
./configure --with-target-bits=64 --with-freetype=/usr/local/Cellar/freetype/2.9.1 --enable-ccache --with-jvm-variants=server,client --with-boot-jdk-jvmargs="-Xlint:deprecation -Xlint:unchecked" --disable-warnings-as-errors --with-debug-level=slowdebug 2>&1 | tee configure_mac_x64.log
记得将--with-freetype指向你自己的freetype安装路径。
输出如下内容,基本就说明你的环境没问题了:
A new configuration has been successfully created in
/Users/yourname/jdk9/build/macosx-x86_64-normal-serverANDclient-slowdebug
using configure arguments '--with-target-bits=64 --with-freetype=/usr/local/Cellar/freetype/2.9.1 --enable-ccache --with-jvm-variants=server,client --with-boot-jdk-jvmargs='-Xlint:deprecation -Xlint:unchecked' --disable-warnings-as-errors --with-debug-level=slowdebug'.
Configuration summary:
* Debug level: slowdebug
* HS debug level: debug
* JDK variant: normal
* JVM variants: server client
* OpenJDK target: OS: macosx, CPU architecture: x86, address length: 64
* Version string: 9-internal+0-adhoc.daiyongzhi.jdk9 (9-internal)
Tools summary:
* Boot JDK: java version "1.8.0_101" Java(TM) SE Runtime Environment (build 1.8.0_101-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode) (at /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home)
* Toolchain: clang (clang/LLVM from Xcode 9.2)
* C Compiler: Version 9.0.0 (at /usr/bin/clang)
* C++ Compiler: Version 9.0.0 (at /usr/bin/clang++)
Build performance summary:
* Cores to use: 8
* Memory limit: 16384 MB
* ccache status: Active (3.5)
NOTE: You have requested to build more than one version of the JVM, which
will result in longer build times.
接下来就可以进行编译了
export LANG=C
make all LOG=debug 2>&1 | tee make_mac_x64.log
如果一切顺利,看到此结果就算编译成功了:
可惜在openjdk9的源码,还是有几个问题导致编译不通过。
有这么几个问题:
/hotspot/src/share/vm/memory/virtualspace.cpp:584:14: error: ordered comparison between pointer and zero ('char *' and 'int')
/hotspot/src/share/vm/opto/loopPredicate.cpp:903:73: error: ordered comparison between pointer and zero ('const TypeInt *' and 'int')
/hotspot/src/share/vm/opto/lcm.cpp:42:35: error: ordered comparison between pointer and zero ('address' (aka 'unsigned char *') and 'int')
谷歌一下找到了解决方法:Xcode 9.0 (9A235) problems
3.验证
验证就比较容易了,我的编译结果在这个目录:openjdk/build/macosx-x86_64-normal-serverANDclient-slowdebug。
进入openjdk/build/macosx-x86_64-normal-serverANDclient-slowdebug/jdk/bin目录下,执行:./java -version。
五、调试
编译这一关过了,调试就很简单了。
1、编写Java程序
我们先试着用我们自己编译的jdk编写一段程序。注意使用编译目录下images目录下的jdk,比如我的目录是:build/macosx-x86_64-normal-serverANDclient-slowdebug/images/jdk。注意不是build/macosx-x86_64-normal-serverANDclient-slowdebug/jdk。
打开开发环境,将jdk设置为上边编译好的jdk目录,然后写一段程序,比如我是这么写的(用来debug gc日志打印)
虚拟机参数为:
-XX:NewSize=6m
-XX:SurvivorRatio=4
-XX:MaxNewSize=6m
-Xlog:gc*:stdout:time,level,tags
-XX:+UseParallelGC
可以直接运行上述代码(如果编译没问题,上述代码可以在编译好的jdk上正常运行)
2、通过运行Java程序调试JVM
①导入CLion
我这里用的CLion,将hotspot的源代码导入开发环境,导入目录为openjdk目录下的hotspot。
CLion扫描你的目录,帮你生成一个CMakeLists.txt的文件,但是它生成的include_directories路径不对,导致很多源文件include找不到头文件。可以把生成的include_directories全部删除改成:
include_directories(./src/share/vm)
include_directories(./src/cpu/x86/vm)
include_directories(./src/share/vm/precompiled)
include_directories(./src/share/vm/utilities)
这样c++程序的include就不会报错了。
②配置运行
在CLion的Edit Configurations里新增一个Application,如图:
Executable是你编译生成的java命令,如我的目录是build/macosx-x86_64-normal-serverANDclient-slowdebug/images/jdk/bin/java。
Program arguments就是你启动Java程序的参数,用IDEA运行上边编写的Java程序时,IDEA会打印运行指令如下:
我们只需要把java命令后的参数拷贝到Program arguments里就可以了。例如我的:
保存下,就可以运行了。其实跟我们在Java开发环境里用我们自己编译的jdk运行一个效果。
但是在CLion下,我们可以在源代码打上断电,通过运行Java程序,debug虚拟机源码。
六、总结
本文并没有很详细的介绍编译细节,因为文档里都要,我写的再多也不如官方文档全面准确。
一定要以官方文档为主,其他的文章都只能参考。