Linux下编译OpenJDK源码以及在Eclipse中调试Hotspot虚拟机
1. 安装mercurial
([mɝ’kjʊrɪəl],水银。同Git一样,是一种分布式版本控制器)
- 先更新source.list
sudo apt-get update
- 安装mercurial
sudo apt-get install mercurial
- 验证安装成功,hg命令显示帮助信息
hg
2. 下载OpenJDK源码
mercurial仓库:http://hg.openjdk.java.net/
hg clone http://hg.openjdk.java.net/jdk7u/jdk7u-dev/
cd jdk7u-dev
chmod 755 get_source.sh
./get_source.sh
==OpenJDK源码有以下几个文件夹:hotspot, langtools, corba, jaxws, jaxp, and jdk==
当执行./get_source.sh脚本,每个文件夹都提示exit code 0时,才成功。如有不成功,多执行几次./get_source.sh
3. Linux上构建OpenJDK源码编译环境
以下引自《深入理解Java虚拟机V2》
OpenJDK的各个组成部分(Hotspot、JDK API、JAXWS、JAXP、Langtools……)有的是使用C++ 编写的,更多的代码则是使用Java自身实现的,因此编译这些Java代码需要用到一个可用的JDK,官方称这个JDK为“Bootstrap JDK”。如果编译OpenJDK 7, Bootstrap JDK必须使用JDK6 Update 14或之后的版本,。最后需要下载 一个1.7.1以上的Apache Ant,用于执行Java编译代码中的Ant脚本。
Ubuntu中GCC和G++应该是默认安装好的,需要确保版本为4.3以上。
《深入理解Java虚拟机v2》中道,编译OpenJDK 7u4 所需的依赖可以使用以下命令一次安装完成。
sudo apt-get install build-essential gawk m4 openjdk-6-jdk libasoundd2-dev libcups2-dev libxrender-dev xorg-dev xutils-dev x11proto-print-dev binutils libmotif3 libmotif-dev ant
上面命令在执行时,可能会有一些问题,安装不成功。下面逐一安装。
- 1 安装gcc、g++、make等
sudo apt-get install build-essential
- 2 安装ant 1.7以上
sudo apt-get install ant
- 3 安装XReader
sudo apt-get install libxrender-dev
sudo apt-get install xorg-dev
- 4 安装alsa
sudo apt-get install libasound2-dev
- 5 Cups
sudo apt-get install libcups2-dev
- 6 安装Bootstrap JKD
安装jdk6作为Bootstrap JDK
sudo apt-get install openjdk-6-jdk
- 7 安装零碎的工具包
sudo apt-get install gawk zip libxtst-dev libxi-dev libxt-dev
4. 设置环境变量
《深入理解JVM》中说道,必须设置的只有两个:LANG和ALT_BOOTDIR,前者是设定语言选项,必须设置为:
export LANG=C
否则, 在编译结束前的验证阶段会出现一个HashTable内的空指针异常。另外一个ALT_BOOTDIR参数是前面提到的Bootstrap JDK。
另外,如果读者之前设置了JAVA_HOME和CLASSPATH两个环境变量,在编译之前必须取消,否则在Makefile脚本中检查到有这两个变量存在,会有警告提示。
unset JAVA_HOME
unset CLASSPATH
以下是根据《深入理解JVM》结合自己电脑编写的build.sh脚本:
#使用系统/bin/bash解释器(即Shell)执行该脚本
#!/bin/bash
#设置语言
export LANG=C
export ALT_BOOTDIR=/usr/lib/jvm/jdk1.7.0_75
export JDK_IMPORT_PATH=/usr/lib/jvm/jdk1.7.0_75
#允许自动下载依赖包
export ALLOW_DOWNLOADS=true
export SKIP_COMPARE_IMAGES=true
#使用预编译头文件,不加这个编译会更慢
export USE_PRECOMPILED_HEADER=true
#要编译的内容
export BUILD_LANGTOOLS=true
export BUILD_JAXP=true
export BUILD_JAXWS=true
export BUILD_CORBA=true
export BUILD_HOSTPOT=true
export BUILD_JDK=true
#要编译的版本
export SKIP_DEBUG_BUILD=true
export SKIP_FASTDEBUG_BUILD=true
export DEBUG_NAME=debug
#把它设置为FALSE可以避免javaws和浏览器Java插件之类的部分build
BUILD_DEPLOY=false
#把它设置为false就不会build出安装包。因为安装包里有一些奇怪的依赖
#但即便不build出它也已经得到完整的JDK镜像,所以还是不用build它
BUILD_INSTALL=false
#存放编译结果
export ALT_OUTPUTDIR=/home/leon/openjdk/build
#这两个环境变量必须去掉,不然会有很的事情发生(Makefile脚本检查到有这2个变量变会提示警告)
unset CLASSPATH
unset JAVA_HOME
# make默认目标,将标准错误输出(2:STDERR)与标准输出(1:STDOUT)合并,合并结果作为标准输入通过管道命令传递给tee命令,
# tee命令读取标准输入并传递给文件$ALT_OUTPUTDIR/build.log
# 参数DEBUG_BINARIES=true用于解决高版本gcc不支持stabs,
# 不加可能会报错:cc1plus: error: the "stabs" debug format cannot be used with pre-compiled headers [-Werror=deprecated]
make DEBUG_BINARIES=true 2>&1 | tee $ALT_OUTPUTDIR/build.log
全部设置结束之后,可以输入make sanity来检查我们前面所做的设置是否全部正确,
make sanity
如果看到“Sanity check passed.”输出,说明检查通过了。
然后执行build.sh脚本(脚本中最后一行是make命令)进行编译。
$ chmod 755 build.sh
$ ./build.sh
5. 编译
执行build.sh脚本(脚本中最后一行是make命令)进行编译。
$ chmod 755 build.sh
$ ./build.sh
5.1. 我的机器上make后出现的错误及解决方法:
5.1.1. ERROR: echo “* This OS is not supported:” ‘uname -a’; exit 1;
注释掉hotspot/make/linux/Makefile里面的checkOS
check_os_version:
#ifeq ($(DISABLE_HOTSPOT_OS_VERSION_CHECK)$(EMPTY_IF_NOT_SUPPORTED),)
# $(QUIETLY) >&2 echo "*** This OS is not supported:" `uname -a`; exit 1;
#endif
或者在make时后面添加参数:DISABLE_HOTSPOT_OS_VERSION_CHECK=OK。(没试过,我采用的是上面方法)
make DISABLE_HOTSPOT_OS_VERSION_CHECK=OK
5.1.2. ERROR: libjvm.so: undefined reference to `void G1SATBCardTableModRefBS::write_ref_array_pre_work
template <class T> void write_ref_array_pre_work(T* dst, int count);
/*
virtual void write_ref_array_pre(oop* dst, int count, bool dest_uninitialized) {
if (!dest_uninitialized) {
write_ref_array_pre_work(dst, count);
}
}
virtual void write_ref_array_pre(narrowOop* dst, int count, bool dest_uninitialized) {
if (!dest_uninitialized) {
write_ref_array_pre_work(dst, count);
}
}
*/
5.2. 编译结束后,将输出类似下面所示内容:
########################################################################
##### Leaving jdk for target(s) sanity all docs images #####
########################################################################
##### Build time 00:02:31 jdk for target(s) sanity all docs images #####
########################################################################
#-- Build times ----------
Target debug_build
Start 2017-06-10 00:35:21
End 2017-06-10 00:38:38
00:00:23 corba
00:00:10 hotspot
00:00:04 jaxp
00:00:06 jaxws
00:02:31 jdk
00:00:03 langtools
00:03:17 TOTAL
-------------------------
编译完成后,生成的二进制文件和相关的文件在
ALTOUTPUTDIR/j2sdk−image目录下,如果没有定义
ALT_OUTPUTDIR环境变量,则默认输出路径为./build/platform/j2sdk-image,其中platform与linux系统有关,可能值是下面之一:
- solaris-sparc
- solaris-sparcv9
- solaris-i586
- solaris-amd64
- linux-i586
- linux-amd64
- windows-i586
- windows-amd64
进入$ALT_OUTPUTDIR/j2sdk-image目录,这是整个JDK的完整编译结果,复制到JAVA_HOME目录,就可以作为一个完整的JDK使用了。
5.3. 查看编译的虚拟机信息
在bin目录下执行./java -version 查看编译的虚拟机信息。
$ ./java -version
#输出:
openjdk version "1.7.0-internal-debug"
OpenJDK Runtime Environment (build 1.7.0-internal-debug-leon_2017_06_09_20_15-b00)
OpenJDK 64-Bit Server VM (build 24.80-b07-jvmg, mixed mode)
见以上输出,表示编译成功!
6. 单独编译HotSpot
6.1 只执行hotspot/make目录下的Makefile即可
为了使用build.sh中的变量,只要将hotspot/make下的Makefile复制到build.sh所在目录即可。然后进行编译。这时候虚拟机的输出结果存放在build/hotspot/outputdir/linux_amd64_compiler2目录(不同机器上,最后一个目录名称会有所差别,bsd表示Mac OS系统,内核为FreeBSD,linux表示linux系统,amd64表示是64位JDK,32位是x86,compiler2表示是Server VM,compiler1表示是 Client VM。),进入后可以见到以下几个目录。
$ cd build/hotspot/outputdir/linux_amd64_compiler2
$ ls -all
total 56
drwxrwxr-x 9 leon leon 4096 Jun 27 17:59 .
drwxrwxr-x 4 leon leon 4096 Jun 27 18:11 ..
drwxrwxr-x 2 leon leon 4096 Jun 27 17:59 debug
drwxrwxr-x 2 leon leon 4096 Jun 27 17:59 fastdebug
drwxrwxr-x 7 leon leon 4096 Jun 27 18:00 generated
drwxrwxr-x 3 leon leon 20480 Jul 29 18:01 jvmg
drwxrwxr-x 2 leon leon 4096 Jun 27 17:59 optimized
drwxrwxr-x 2 leon leon 4096 Jun 27 17:59 product
drwxrwxr-x 2 leon leon 4096 Jun 27 17:59 profiled
-rw-rw-r-- 1 leon leon 1648 Jun 27 17:59 shared_dirs.lst
6.2 编译时出现的错
参考: http://blog.csdn.net/beswkwangbo/article/details/38757677
编译时会有几个错
第一个是 fatal error: sys/cdefs.h: No such file or directory。与gcc版本有关,解决办法:sudo apt-get install libc6-dev-i386
第二个是 bits/c++config.h: No such file or directory。解决办法:sudo apt-get install gcc-multilib g++-multilib
第三个是cc1plus: error: the “stabs” debug format cannot be used with pre-compiled headers [-Werror=deprecated],因为高版本的gcc不再支持stabs,解决办法:在make命令中加上 DEBUG_BINARIES=true
第四个是,cc1plus all warnings being treated as errors ubuntu。解决办法:在hotspot/make/makefiles/gcc.make 中,把 -Werror 选项去掉。
最后一个问题是,自举jdk不能是64位的,装个32位的即可。
6.3 运行虚拟机
在编辑结束之后、运行虚拟机之前,还要手工编辑jvmg目录下的env.sh文件,这个文件由编译脚本自动生成,用于设置虚拟机的环境变量,里面已经发布了“JAVA_HOME、 CLASSPATH、 HOTSPOT_BUILD_USER”3个环境变量(需要修改JAVA_HOME变量为当前编译java),还需要增加一个“LD_LIBRARY_PATH”变量,最后env.sh文件内容如下:
# Generated by /home/leon/OpenJDK7/jdk7u-dev/hotspot/make/linux/makefiles/buildtree.make
: ${JAVA_HOME:=/home/leon/OpenJDK7/build/j2sdk-image}
CLASSPATH=.:${JAVA_HOME}/jre/lib/rt.jar:${JAVA_HOME}/jre/lib/i18n.jar
HOTSPOT_BUILD_USER="leon in hotspot"
LD_LIBRARY_PATH=.:${JAVA_HOME}/jre/lib/amd64/native_threads:${JAVA_HOME}/jre/lib/amd64:
export JAVA_HOME CLASSPATH HOTSPOT_BUILD_USER LD_LIBRARY_PATH
bash
然后执行以下命令启动虚拟机(这时的启动器名为gamma),输出版本号。
$ cd jvmg
$ ./env.sh
$ ./gamma -version
输出如下(同build/j2sdk-image/bin/java -version输出一样)
Using java runtime at: /home/leon/OpenJDK7/build/j2sdk-image/jre
openjdk version "1.7.0-internal-debug"
OpenJDK Runtime Environment (build 1.7.0-internal-debug-leon_2017_06_27_17_51-b00)
OpenJDK 64-Bit Server VM (build 24.80-b07-jvmg, mixed mode)
7. 在Eclipse中调试Hotspot虚拟机源码
请参看 Linux下在Eclipse中调试Hotspot虚拟机源码 http://blog.csdn.net/leonliu06/article/details/78495202。
参考:
《深入理解Java虚拟机——JVM高级特性与最佳实践》
更多推荐
所有评论(0)