1.6.4 进行编译

现在需要下载的编译环境和依赖项目都准备齐全了,最后我们还需要对系统的环境变量做一些简单设置以便编译能够顺利通过。OpenJDK在编译时读取的环境变量有很多,但大多都有默认值,必须设置的只有两个:LANG和ALT_BOOTDIR,前者是设定语言选项,必须设置为:


export LANG=C


否则,在编译结束前的验证阶段会出现一个HashTable内的空指针异常。另外一个ALT_BOOTDIR参数是前面提到的Bootstrap JDK,在Mac OS上笔者设为以下路径,其他操作系统读者对应调整即可。


export ALT_BOOTDIR=/Library/Java/JavaVirtualMachines/jdk1.7.0_04.jdk/Contents/Home


另外,如果读者之前设置了JAVA_HOME和CLASSPATH两个环境变量,在编译之前必须取消,否则在Makefile脚本中检查到有这两个变量存在,会有警告提示。


unset JAVA_HOME

unset CLASSPATH


其他环境变量笔者就不再一一介绍了,代码清单1-1给出笔者自己常用的编译Shell脚本,读者可以参考变量注释中的内容。

代码清单1-1 环境变量设置


语言选项,这个必须设置,否则编译好后会出现一个HashTable的NPE错

export LANG=C

Bootstrap JDK的安装路径。必须设置

export ALT_BOOTDIR=/Library/Java/JavaVirtualMachines/jdk1.7.0_04.jdk/Contents/Home

允许自动下载依赖

export ALLOW_DOWNLOADS=true

并行编译的线程数,设置为和CPU内核数量一致即可

export HOTSPOT_BUILD_JOBS=6

export ALT_PARALLEL_COMPILE_JOBS=6

比较本次build出来的映像与先前版本的差异。这对我们来说没有意义,

必须设置为false,否则sanity检查会报缺少先前版本JDK的映像的错误提示。

如果已经设置dev或者DEV_ONLY=true,这个不显式设置也行

export SKIP_COMPARE_IMAGES=true

使用预编译头文件,不加这个编译会更慢一些

export USE_PRECOMPILED_HEADER=true

要编译的内容

export BUILD_LANGTOOLS=true

export BUILD_JAXP=false

export BUILD_JAXWS=false

export BUILD_CORBA=false

export BUILD_HOTSPOT=true

export BUILD_JDK=true

要编译的版本

export SKIP_DEBUG_BUILD=false

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=/Users/IcyFenix/Develop/JVM/jdkBuild/openjdk_7u4/build

这两个环境变量必须去掉,不然会有很诡异的事情发生(我没有具体查过这些"诡异的

事情",Makefile脚本检查到有这2个变量就会提示警告)

unset JAVA_HOME

unset CLASSPATH

make 2>&1|tee $ALT_OUTPUTDIR/build.log


全部设置结束之后,可以输入make sanity来检查我们前面所做的设置是否全部正确。如果一切顺利,那么几秒钟之后会有类似代码清单1-2所示的输出。

代码清单1-2 make sanity检查


~/Develop/JVM/jdkBuild/openjdk_7u4$make sanity

Build Machine Information:

build machine=IcyFenix-RMBP.local

Build Directory Structure:

CWD=/Users/IcyFenix/Develop/JVM/jdkBuild/openjdk_7u4

TOPDIR=.

LANGTOOLS_TOPDIR=./langtools

JAXP_TOPDIR=./jaxp

JAXWS_TOPDIR=./jaxws

CORBA_TOPDIR=./corba

HOTSPOT_TOPDIR=./hotspot

JDK_TOPDIR=./jdk

Build Directives:

BUILD_LANGTOOLS=true

BUILD_JAXP=true

BUILD_JAXWS=true

BUILD_CORBA=true

BUILD_HOTSPOT=true

BUILD_JDK=true

DEBUG_CLASSFILES=

DEBUG_BINARIES=

……因篇幅关系,中间省略了大量的输出内容……

OpenJDK-specific settings:

FREETYPE_HEADERS_PATH=/usr/X11R6/include

ALT_FREETYPE_HEADERS_PATH=

FREETYPE_LIB_PATH=/usr/X11R6/lib

ALT_FREETYPE_LIB_PATH=

Previous JDK Settings:

PREVIOUS_RELEASE_PATH=USING-PREVIOUS_RELEASE_IMAGE

ALT_PREVIOUS_RELEASE_PATH=

PREVIOUS_JDK_VERSION=1.6.0

ALT_PREVIOUS_JDK_VERSION=

PREVIOUS_JDK_FILE=

ALT_PREVIOUS_JDK_FILE=

PREVIOUS_JRE_FILE=

ALT_PREVIOUS_JRE_FILE=

PREVIOUS_RELEASE_IMAGE=/Library/Java/JavaVirtualMachines/jdk1.7.0_04.jdk/Contents/Home

ALT_PREVIOUS_RELEASE_IMAGE=


Sanity check passed.

Makefile的Sanity检查过程输出了编译所需的所有环境变量,如果看到“Sanity check passed.”,说明检查过程通过了,可以输入“make”执行整个OpenJDK编译(make不加参数,默认编译make all),笔者使用Core i7 3720QM/16GB RAM的MacBook机器,启动6条编译线程,全量编译整个OpenJDK大概需20分钟,编译结束后,将输出类似下面的日志清单所示内容。如果读者之前已经全量编译过,只修改了少量文件,增量编译可以在数十秒内完成。


—Build times—————

Target all_product_build

Start 2012-12-13 17:12:19

End 2012-12-13 17:31:07

00:01:19 corba

00:01:15 hotspot

00:00:14 jaxp

00:7:21 jaxws

00:8:11 jdk

00:00:28 langtools

00:18:48 TOTAL



编译完成之后,进入OpenJDK源码下的build/j2sdk-image目录(或者build-debug、build-fastdebug这两个目录),这是整个JDK的完整编译结果,复制到JAVA_HOME目录,就可以作为一个完整的JDK使用,编译出来的虚拟机,在-version命令中带有用户的机器名。


>./java-version

openjdk version"1.7.0-internal-fastdebug"

O p e n J D K R u n t i m e E n v i r o n m e n t(b u i l d 1.7.0-i n t e r n a l-f a s t d e b u g-icyfenix_2012_12_24_15_57-b00)

OpenJDK 64-Bit Server VM(build 23.0-b21-fastdebug,mixed mode)


在大多数时候,如果我们并不关心JDK中HotSpot虚拟机以外的内容,只想单独编译HotSpot虚拟机的话(例如调试虚拟机时,每次改动程序都执行整个OpenJDK的Makefile,速度肯定受不了),那么使用hotspot/make目录下的Makefile进行替换即可,其他参数设置与前面是一致的,这时候虚拟机的输出结果存放在build/hotspot/outputdir/bsd_amd64_compiler2目录[1]中,进入后可以见到以下几个目录。


0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 debug

0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 fastdebug

0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:25 generated

0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 jvmg

0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 optimized

0 drwxr-xr-x 584 IcyFenix staff 19K 12 13 17:25 product

0 drwxr-xr-x 15 IcyFenix staff 510B 12 13 17:24 profiled


这些目录对应了不同的优化级别,优化级别越高,性能自然就越好,但是输出代码与源码的差距就越大,难于调试,具体哪个目录有内容,取决于make命令后面的参数。

在编译结束之后、运行虚拟机之前,还要手工编辑目录下的env.sh文件,这个文件由编译脚本自动产生,用于设置虚拟机的环境变量,里面已经发布了“JAVA_HOME、CLASSPATH、HOTSPOT_BUILD_USER”3个环境变量,还需要增加一个“LD_LIBRARY_PATH”,内容如下:


LD_LIBRARY_PATH=.:${JAVA_HOME}/jre/lib/amd64/native_threads:${JAVA_HOME}/jre/lib/amd64:

export LD_LIBRARY_PATH


然后执行以下命令启动虚拟机(这时的启动器名为gamma),输出版本号。


../env.sh

./gamma-version

Using java runtime at:/Library/Java/JavaVirtualMachines/jdk1.7.0_04.jdk/Contents/Home/jre

java version"1.7.0_04"

Java(TM)SE Runtime Environment(build 1.7.0_04-b21)

OpenJDK 64-Bit Server VM(build 23.0-b21,mixed mode)


看到自己编译的虚拟机成功运行起来,很有成就感吧!

[1]在不同机器上,最后一个目录名称会有所差别,bsd表示Mac OS系统(内核为FreeBSD),amd64表示是64位JDK(32位是x86),compiler2表示是Server VM(Client VM表示是compiler1)。