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以上。

image

  《深入理解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/j2sdkimage 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高级特性与最佳实践》

猜你喜欢

转载自blog.csdn.net/leonliu06/article/details/78495035