您的位置:首页 > 运维架构 > Linux

[置顶] Linux下编译OpenJDK源码以及在Eclipse中调试Hotspot虚拟机

2017-11-09 22:48 886 查看

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<
4000
span class="hljs-attribute">-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高级特性与最佳实践》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: