转:自己编译JDK

  想要一探JDK内部的实现机制,最便捷的路径之一就是自己编译一套JDK,通过阅读和跟踪调试JDK源码去了解Java技术体系的原理,虽然门槛会高一点,当肯定会比阅读各种文章、书籍来得更加贴近本质些。另外JDK中的很多底层方法都是Native的,需要跟踪这些方法的运作或对JDK进行Hack的时候,都需要自己编译一套JDK
  现在网络上有不少开源的JDK实现可以供我们选择,如Apache HarmonyOpenJDK等。考虑到Sun系列的JDK是现在使用得最广泛的JDK版本,笔者选择了OpenJDK进行这次编译实战。

1.获取JDK源码
  首先确定要使用的JDK版本,OpenJDK 6OpenJDK 7都是开源的,源码都可以在它们的主页(openjdk.java/)上到,OpenJDK 6的源码其实是从OpenJDK 7的某个基线中引出的,然后剥离掉JDK 1.7相关的代码,从而得到一份可以通过TCK 6JDK 1.6实现,
因此直接编译OpenJDK 7会更加原汁原味一些,其实这两个版本的编译过程差异并不大。
  获取源码有两种方式。一是通过Mercurial代码版本管理工具从Repository中直接取得源码(Repository地址:hg.openjdk.java/jdk7/jdk7),这是最直接的方式,从版本管理中看变更轨迹比看什么Release Note都来得实在,不过坏处自然是太麻烦了一些,尤其是Mercurial远不如SVNClearCaseCVS之类的版本控制工具那样普及。另外一种就是直接下载官方打包好的源码包了,可以从Source Releases页面(地址:download.java/openjdk/jdk7/)取得打包好的源码,一般来说大概一个月左右会更新一次,虽然不够及时,但的确方便了许多。笔者下载的是OpenJDK 7 Early Access Source Build b121版,2010129日发布的,大概81.7MB,解压出来约308MB

2 系统需求
  如果可能,笔者建议尽量在LinuxSolaris上构建OpenJDK,这要比在Windows平台上轻松许多,而且网上能到的资料绝大部分都是在Linux上编译的。如果一定要在Windows平台上编译,建议读者认真阅读一下源码中的README-builds.html文档(无论在OpenJDK
网站上还是在下载的源码包里面都有这份文档),因为编译过程中需要注意的细节非常多。虽然不至于像文档上所描述的Building the source code for the JDK requires a high level of technical expertise. Sun provides the source code primarily for technical experts who want to conduct research(编译JDK需要很高的专业技术,Sun提供JDK源码是为了技术专家进行研究之用)那么夸张,但是如果读者是第一次编译,那在上面耗费一整天乃至更多的时间都很正常。
  笔者在本次实战中演示的是在32Windows 7平台下编译x86版的OpenJDK(也就是32位的JDK),如果需要编译x64版,那毫无疑问也需要一个64位的操作系统。另外编译涉及的所有文件都必须存放在NTFS格式的文件系统中,因为FAT32格式无法支持大小写敏感的文件名。在官方文档上写到:编译至少需要512MB的内存和600MB的磁盘空间。如果读者耐心很好的话,512MB的内存基本上也可以凑合使用,不过600MB的磁盘空间仅仅是指存放OpenJDK源码和相关依赖项的空间,要完成编译,600MB肯定是无论如何都不够的,这次实战中所下载的工具、依赖项、源码,全部安装、解压完成最少(最少是指只下载C++编译器,不下载VSIDE)需要超过1GB的空间。
  对系统的最后一点要求就是所有的文件,包括源码和依赖项目,都不要放在包含中文或空
格的目录里面,这样做不是一定不可以,只是这样会为后续建立CYGWIN环境带来很多额外的工作,这是由于LinuxWindows的磁盘路径差别所导致的,我们也没有必要自己给自己麻烦。

3 构建编译环境
  准备编译环境的第一步是去安装一个CYGWIN 。这是一个在Windows平台下模拟Linux运行环境的软件,提供了一系列的Linux命令支持。需要CYGWIN的原因是在编译中要使用GNU Make来执行Makefile文件(C/C++程序员肯定很熟悉,如果只使用Java,那把这个东西当做C++版本的ANT看待就可以了)。安装CYGWIN时不能直接默认安装,因为表1-2中所示的工具都不会进行默认安装,但又是编译过程中需要的,因此要在图1-6的安装界面中进行手工选择。

  表1-2 需要手工选择安装的CYGWIN工具
文件名
分类
描述
ar.exe
Devel
binutils
The GNU assembler, linker and binary utilities
Devel
make
The GNU version of the 'make' utility built for CYGWIN.
m4.exe
Interpreters
m4
GNU implementation of the traditional Unix macro processor
Utils
cpio
A program to manage archives of files
Utils
awk
Pattern-directed scanning and processing language
Utils
file
Determines file type using 'magic' numbers
Archive
zip
Package and compress (archive) files
Archive
unzip
Extract compressed files in a ZIP archive
System
procps
Display amount of free and used memory in the system

  CYGWIN安装时的定制包选择界面如图1-6所示:

1-6 CYGWIN安装界面
建立编译环境的第二步是安装编译器。JDK中最核心的代码(Java虚拟机及JDKNative方法的实现等)是使用C++语言及少量的C语言编写的,官方文档中说他们的内部开发环境是在Microsoft Visual Studio C++ 2003VS2003)中进行编译,同时也在Microsoft Visual Studio C++ 2010VS2010)中测试过,所以最好只选择这两个编译器之一进行编译。如果选择VS2010,那么在编译器之中已经包含了Windows SDK v 7.0a,否则可能还要自己去下载这个SDK,并且更新PlatformSDK目录。由于笔者没有购买Visual Studio 2010IDE,所以仅仅下载了VS2010 Express中提取出来的C++编译器,这部分是免费的,但单独安装好编译器比较麻烦。建议读者选择使用整套Visual Studio C++ 2010Visual Studio C++ 2010 Express版进行编译。
  需要特别注意的一点:CYGWINVS2010安装之后都会在操作系统的PATH环境变量中写入自己的bin目录路径,必须检查并保证VS2010bin目录一定要在CYGWINbin目录之前,因为这两个软件的bin目录之中各自都有个连接器”,但是只有VS2010中的连接器可以完成OpenJDK的编译。
  准备JDK编译环境的第三步就是下载一个已经编译好了的JDK。这听起来也许有点滑稽——要用鸡蛋孵小鸡还真得必须先养一只母鸡呀?但仔细想想其实这个步骤很合理:因为J
DK包含的各个部分(HotspotJDK APIJAXWSJAXP……)有的是使用C++编写的,而更多的代码则是使用Java自身实现的,因此编译这些Javaant安装包代码需要用到一个可用的JDK,官方称这个JDKBootstrap JDK”。而编译OpenJDK 7的话,Bootstrap JDK必须使用JDK6 Update 14或之后的版本,笔者选用的是JDK6 Update 21
  最后一个步骤是下载一个Apache ANTJDKJava代码部分都是使用ANT脚本进行编译的,ANT版本要求在1.6.5以上,这部分是Java的基础知识,对本书的读者来说应该没有难度,笔者就不再详述。

4 准备依赖项
  前面说过,OpenJDK中开放的源码并没有达到100%,还有极少量的无法开源的产权代码存在。OpenJDK承诺日后将逐步使用开源实现来替换掉这部分产权代码,但至少在今天,编译JDK还需要这部分闭源包,官方称之为JDK Plug”(注1 ,它们从前面的Source Releases页面就可以下载到。在Windows平台的JDK Plug是以Jar包的形式提供的,通过下面这条命令可以安装它:
Console代码 
1. java –jar jdk-7-ea-plug-b121-windows-i586-09_dec_2010.jar 
java –jar jdk-7-ea-plug-b121-windows-i586-09_dec_2010.jar
  运行后将会显示如图1-7的协议,点击ACCEPT接受协议,然后把Plug安装到指定目录即可。安装完毕后建立一个环境变量ALT_BINARY_PLUGS_PATH”,变量值为此JDK Plug的安装路径,后面编译程序时需要用到它。

1-7 JDK Plug安装协议

  除了要用到JDK Plug外,编译时还需要引用JDK的运行时包,这个是编译JDK中用Java代码编写的那部分所需要的,如果仅仅是想编译一个HotSpot虚拟机的话则可以不用。官方文档把这部分称之为Optional Import JDK”,可以直接使用前面Bootstrap JDK的运行时包,我们需要建立一个名为ALT_JDK_IMPORT_PATH”的环境变量指向JDK的安装目录。
  第三步是安装一个大于2.3版的FreeType ,这是一个免费的字体渲染库,JDKSwing部分和JConsole这类工具要使用到它。安装好后建立两个环境变量ALT_FREETYPE_LIB_PATH”和ALT_FREETYPE_HEADERS_PATH”,分别指向FreeType安装目录下的bin目录和include目录。另外还有一点官方文档没有提到但必须要做的事情是把FreeTypebin目录加入到PATH环境变量中。
  第四步是下载Microsoft DirectX 9.0 SDKSummer 2004),安装后大约有298MB,在微软上搜索一下就可以到下载地址,它是免费的。安装后建立环境变量ALT_DXSDK_PATH”指向DirectX 9.0 SDK的安装目录。
  第五步是去寻一个名为MSVCR100.DLL”的动态链接库,如果读者在前面安装了全套的Visual Studio 2010,那这个文件在本机就能到,否则上网搜索一下也能到单独的下载
地址,大概有744KB。建立环境变量ALT_MSVCRNN_DLL_PATH”指向这个文件所在的目录。如果读者选择的是VS2003,这个文件名应当为MSVCR73.DLL”,应该在很多软件中都包含有这个文件,如果不到的话,前面下载的Bootstrap JDK”的bin目录中应该也有一个,直接拿来用吧。

5 进行编译
  现在需要下载的编译环境和依赖项目都准备齐全了,最后我们还需要对系统做一些设置以便编译能够顺利通过。
  首先执行VS2010中的VCVARS32.BAT,这个批处理文件的目的主要是设置INCLUDELIB、和PATH这几个环境变量,如果和笔者一样只是下载了编译器的话则需要手工设置它们,各个环境变量的设置值可以参考下面给出的代码清单1-1中的内容。批处理运行完之后建立ALT_COMPILER_PATH”环境变量让Makefile知道在哪里可以到编译器。
  再建立ALT_BOOTDIR”和ALT_JDK_IMPORT_PATH”两个环境变量指向前面提到的JDK 1.6的安装目录。建立ANT_HOME”指向Apache ANT的安装目录。建立的环境变量很多,为了避免遗漏,笔者写了一个批处理文件以供读者参考,如代码清单1-1所示。


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

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。