OpenJDK:构建JDK

编者注:在这一期的 开源之路 中,作者和 Cafe Au Lait 的创始人 Elliotte Rusty Harold 接管了目前的 Java SE 7 开发系列文章。因为 OpenJDK 项目 的目标和流程已经在 第一期 介绍过,所以 Elliotte 将在此教程中直接介绍 JDK 7 的实际构建。

在此之前, 如果 OpenJDK 项目有更新,我们会将其发布在每期“开源之路”的开始部分。最新的 发行版 是 b23,发行日期是 10 月 30 日。此发行版解决了一小部分缺陷和功能要求,这些内容可详见其 发行说明,其中许多都与管理问题相关,比如顶层 README 文件、空格清理和遗留 “j2se” 引用的移除。上一个版本 b22 解决的问题比较多,集成了 65 个缺陷修复和 14 个功能,其中包括 将 CORBA、JAXP 和 JAXWS 分割到各自的工作区中,将 Swing ThreadPool 创建 替换为 java.util.concurrent 功能,支持各种时间区更改,以及 OpenJDK RenderingEngine 插件的创建,这意味着“为 Open JDK 提供了替代 Ductus 库的起点。”

但如何达到所有这些新目标呢?这正是 Elliotte 将在在本文中阐述的内容,他将介绍如何从源码构建 JDK。

由于 Sun 的 Java 开发工具包是自由软件(只需在替换的过程中对一些小组件建模),因此我们不妨对经进行一些修改。无论您的激情在于优化、实验、语言设计、调试还是文档,都有大量的工作需要您来做,都有大量的机会提供给各种技能水平的开发人员。在本系列的后续文章中,我将详述 Java 7 或更高版本中可能出现的各种 API 开发。但是,要玩转这些 API,您将需要浴血奋战,所以立即甩掉您的急救箱,撕掉止血带,准备流一些血吧!我们要开始构建 JDK 了。

系统需求

首先,构建 JDK 需要一个受支持的操作系统。这包括 Linux、Solaris、Windows XP 和 Windows Vista。不支持 Mac OS X。Apple 负责将 JDK 迁移至 Mac 中,然而,这往往滞后于潮流。但是,Mac 用户可以使用 Parallels、VMWare Fusion 或 Boot Camp 来运行 Windows 或 Linux,并在其中构建 JDK。的确,我撰写此文时用的就是这种方法,当时我电脑中的以太网卡在项目完成前两天意外死亡了。然而,在 Apple 发布最新的 JDK 之前,我们仍然无法在 Mac OS 中运行 Java 7(或 6)应用程序。这可能发生在明天,可能发生在明年,也可能永远都不会发生。

其次,我们需要一个最新的 Java 6 SDK。Java 7 不能通过 Java 5 来编译。就我个人来说,我在设计软件时不喜欢太多的版本依赖,这对于开源软件尤其重要。但是,JDK 只是在最近才开放源码,而且显示了公司 IT 的一些遗留态度:“我们可以控制每个人的构建环境”。移除其中的一些依赖是一项正在进行的并将花费数年的任务,但是,这个过程已经取得了初步进展。就在最近,Sun 将其源码库从专用 Teamware 转移到了开源的 Mercurial 中。从封闭开发模式切换到开放开发模式是一项艰巨的任务,但最终结果是更强大、更灵活、更健壮的代码库。

第三,我们需要一个 C 编译器。其中一些 JDK 是用原生代码编写的。它们不可能都是纯 Java 编写的。对于 Linux,我们需要使用 gcc4。结于 Windows,需要使用 Microsoft Visual Studio .NET。对于 Solaris,需要使用 Sun Studio 11。

在 Linux 中,可能还需要安装或更新一些库。具体要安装哪些库,取决于您的发行版和版本。您可能还需要为现有库安装一组 C 头文件。在本文中,我使用现有的 Ubuntu 7.10 Gutsy Gibbon 发行版。大多数其他合理流通的发行版应该也能工作。如果您发现有一些发行版无法工作,不妨找出其原因并记录缺陷。

最后,在 Windows 中,您可以在 NTFS 文件系统上进行构建。您不能在 FAT-32 上构建 JDK。您还需要安装 Cygwin,因为在 Windows 上构建的 JDK 是 Windows 和 Unix 实用工具的奇异混合物。

获取源码

大约每隔一个月,Sun 会在 OpenJDK 源码发布页面 上发布一组完整的 JDK 源码。下面列出了几种不同的包:

OpenJDK 源码 JDK 7 大约 95% 的主要源码。 平台的二进制插件 Sun 实际并不拥有 JDK 中的所有代码,并且他们无法重新注册他们不拥有的代码。相反,一些代码段必须以闭源二进制软件包来提供。您将需要为您的平台下载其中一些代码。Linux、Solaris 和 Windows 在 32 位和 64 位版本中都受支持 。 Jtreg 测试工具二进制软件包下载 代码的测试框架。您不必真正使用测试框架来构建或修改代码,但是不论如何您都应该掌握它。 OpenJDK 模块项目 这包括 Java 7 的新模块系统。(我将在本系列的后续文章中介绍。) 最终,此项目将汇总到 JDK 中,但现在您并不立即需要它。

因为这些项目所占空间在 120MB 以上,下载服务器的速度可能不是一直都特别快,所以要想全部下载可能需要一段时间。开源的一个好处就是不用单击通过令人讨厌的使用许可。从普通的 URL 中可以下载任何开源软件。这使得 curl、wget 等类似工具的使用更加容易。设置批处理作业来获取这些工具,然后您就可以悠闲地喝一杯咖啡。事实上,无点击还使正常浏览器的使用更加容易。点击通过注册的方式应该可以废除了。点击通过注册只是使律师更加忙碌,除了律师谁还需要这些东西?

jars@jars-desktop:~/openjdk$ wget  http://www.java.net/download/openjdk/jdk7/promoted/b23/openjdk-7-ea-src-b23-30_oct_2007.zip--18:02:02-- http://www.java.net/download/openjdk/jdk7/promoted/b23/openjdk-7-ea-src-b23-30_oct_2007.zip      => `openjdk-7-ea-src-b23-30_oct_2007.zip'Resolving www.java.net... 64.125.132.37, 64.125.132.39Connecting to www.java.net|64.125.132.37|:80... connected.HTTP request sent, awaiting response... 301 Moved PermanentlyLocation:  http://download.java.net/openjdk/jdk7/promoted/b23/openjdk-7-ea-src-b23-30_oct_2007.zip[following]--18:02:02--  http://download.java.net/openjdk/jdk7/promoted/b23/openjdk-7-ea-src-b23-30_oct_2007.zip      => `openjdk-7-ea-src-b23-30_oct_2007.zip'Resolving download.java.net... 72.5.124.114Connecting to download.java.net|72.5.124.114|:80... connected.HTTP request sent, awaiting response... 200 OKLength: 84,617,174 (81M) [application/zip]44% [===============>       ] 37,717,212  55.36K/s  ETA 12:19

现在,我们只需要前两个条件:OpenJDK 源码和二进制插件。但是,将来您可能还需要其他两个条件。

Mercurial

Sun 尚未完全开放 JDK 源码控制库。然而,这随时都可能发生。他们正在使用的系统是 Sun 专用产品,名为 Teamware。他们正在转换到开源的 Mercurial(不是子版本或 CVS)。转换完成之后,您就能够使用绝对最新的商业版本。

忽略 OpenJDK 站点上对子版本的所有引用。这些仅是 java.net 项目模板的标准部分。Sun 实际并未使用 java.net 库或子版本来管理 OpenJDK。子版本中实际上只有 openjdk.java.net 网站的 HTML 代码。真正的 JDK 源码并不在子版本中。

下载快照版本会为您提供可能不会构建的代码(虽然有一些快照已经完全破坏)。然而,代码也可能过时一个多月或更久了。检查 Mercurial 中的代码会得到绝对最新的代码。然而,这些代码可能完全破坏了,您无法确定如果构建失败到底是您的错误还是代码的错误。完成库的开发之后,我建议您首先从已知的好快照开始构建,来解开整个过程的所有疙瘩,然后在您确信自己的设置之后,前进到版本控制中最新的部分。

编译

现在,下载以下软件包,并解压它们:

$ unzip openjdk-7-ea-src-b23-30_oct_2007.zip  inflating: openjdk/control/make/Makefile   inflating: openjdk/control/make/README   inflating: openjdk/control/make/jprt.config   inflating: openjdk/control/make/jprt.properties   inflating: openjdk/control/make/make/Defs-internal.gmk   inflating: openjdk/control/make/make/README.pre-components   ...

然后,将二进制插件 JAR 文件移动到一个方便的目录中。在 Linux 中,默认目录是 /opt/java/openjdk-binary-plugs。在 Solaris 中,默认目录是 /usr/jdk/instances/openjdk-binary-plugs。在 Solaris 中,默认目录是 C:/openjdk-binary-plugs. 可以将 JAR 置于您喜欢的其他位置,但是在构建之前,必须设置 ALT_BINARY_PLUGS_PATH 环境变量指向此位置。

将仅用于构建的二进制插件分布到太多位置是一种愚蠢的做法。由于这是一个开源项目,任何人都能修复问题,所以将此作为我们的第一个 TODO:

TODO:重写构建文件,以便它首先查找其他源码所在的标准 openjdk/binary-plugs 目录。

事实上,二进制插件真正并没有多大,因此只将其全部分布在第一个位置的源码包中可能很明智。

解压后的 openjdk 目录包含一些 readme 文件和各个子项目的目录,其中包括 jdk、hotspot、langtools、jaxws 和 jaxp。这些目录应该能够单独构建 ,但是我曾这样做,却没有成功。

生成 Make 文件

要构建 JDK,需要制作 jdk_generic_profile.sh 可执行脚本并运行它。在顶层 openjdk 目录中,键入:

$ chmod +x ./jdk/make/jdk_generic_profile.sh$ ./jdk/make/jdk_generic_profile.sh

多半可能,这将失败。第一次我这样做,得到如下消息:

WARNING: Cannot Access ALT_BOOTDIR=/opt/java/jdk1.6.0WARNING: Missing ALT_BINARY_PLUGS_PATH: /opt/java/openjdk-binary-plugs

我已经安装了这些软件,但是 makefile 没有在预期的正确位置找到它们。ALT_BINARY_PLUGS_PATH 和 ALT_BOOTDIR 环境变量需要分别设置为 JDK 的安装位置和二进制插件目录。所以我这样做了:

$ export ALT_BOOTDIR=/usr/local/java;$ export ALT_BINARY_PLUGS_PATH=~/plugs

然后,jdk_generic_profile 脚本运行并创建 makefile。

完整性检查

在下一个源码库中,可能有顶层 makefile, 但是如果使用 b23,则需要更改为 control/make 目录。然后,在您的构建环境中使用 make sanity 进行完整性检查:

$ cd control/make$ make sanity

这将警告您一些忘记安装的软件和忘记设置的环境变量。下面是我的第一次完整性检查的结果:

$ make sanity/bin/sh: /usr/bin/gawk: not found/bin/sh: /usr/bin/gawk: not found/bin/sh: /NOT-SET/devtools/share/ant/latest/bin/ant: not found/bin/sh: /NOT-SET/devtools/share/findbugs/latest/bin/findbugs: not found../make/common/shared/Sanity-Settings.gmk:121: WARNING: ANT_VER should not be empty [Sanity-Settings.gmk]../make/common/shared/Sanity-Settings.gmk:122: WARNING: FINDBUGS_VER should not be empty [Sanity-Settings.gmk]../make/common/shared/Sanity-Settings.gmk:191: WARNING: TEMP_FREE_SPACE should not be empty [Sanity-Settings.gmk]../make/common/shared/Sanity-Settings.gmk:192: WARNING: FREE_SPACE should not be empty [Sanity-Settings.gmk]../build/linux-i586/tmp/alsaversioncheck.c:1:28: error: alsa/asoundlib.h: No such file or direcTory../build/linux-i586/tmp/alsaversioncheck.c: In function 'main':../build/linux-i586/tmp/alsaversioncheck.c:3: warning: incompatible implicit declaration of built-in function 'printf'../build/linux-i586/tmp/alsaversioncheck.c:3: error: 'SND_LIB_VERSION_STR' undeclared (first use in this function)../build/linux-i586/tmp/alsaversioncheck.c:3: error: (Each undeclared identifier is reported only once../build/linux-i586/tmp/alsaversioncheck.c:3: error: for each function it appears in.)make: *** [../build/linux-i586/tmp/alsaversioncheck] Error 1

我缺少了 gawk、ant、findbugs 和 ALSA。继续安装缺少的内容并重试。安装完这些代码段(使用 Synaptic)之后,构建仍然没有找到 Ant,虽然 Ant 就在我的路径中:

$ make sanity/bin/sh: /NOT-SET/devtools/share/ant/latest/bin/ant: not found/bin/sh: /NOT-SET/devtools/share/findbugs/latest/bin/findbugs: not found../make/common/shared/Sanity-Settings.gmk:121: WARNING: ANT_VER should not be empty [Sanity-Settings.gmk]...$ /usr/bin/ant -vApache Ant version 1.7.0 compiled on August 29 2007Buildfile: build.xml does not exist!Build failed

我断定如果尝试设置 ANT_VER 将会行得通,但我已经对 Ant 做了足够的工作,我猜想 ANT_HOME 可能是 make 脚本真正需要的。我试着设置 ANT_HOME 并再次运行完整性检查:

$ export ANT_HOME=/usr/share/ant$ make sanity/bin/sh: /NOT-SET/devtools/share/findbugs/latest/bin/findbugs: not found../make/common/shared/Sanity-Settings.gmk:122: WARNING: FINDBUGS_VER should not be empty [Sanity-Settings.gmk]...

系统不再抱怨 Ant,但仍想运行 FindBugs。就个人而言,尽管我非常喜欢 FindBugs,但我发现代码库构建是否需要它是可质疑的。当前,我们应该试着移除依赖,而不是引入依赖。尽管如此,构建脚本需要它,因此我必须安装。FindBugs 在 Synaptic 中不可用,因此我不得不手动安装它。系统发出错误消息,抱怨:

../make/common/shared/Sanity-Settings.gmk:122: WARNING: FINDBUGS_VER should not be empty [Sanity-Settings.gmk]

因此,我将 FINDBUGS_VER 设置为 1.3.0。

$ export FINDBUGS_VER=1.3.0

这没有起作用,因此我花了十五分钟浏览构建文件,并尝试使用不同的值,直到我无意中发现了 FINDBUGS_HOME。将此环境变量设置为 FindBugs 的位置修复了这个问题。

$ export FINDBUGS_HOME=/opt/java/findbugs-1.3.0

TODO:如果问题是缺少 FINDBUGS_HOME 或 ANT_HOME 环境变量,则将得到上述错误消息,而非“FINDBUGS_VER/ANT_VER 为空”。较好的方法是完全移除对 FindBugs 的依赖。

下一个问题似乎是 Freetype。我又返回到 Synaptic 来安装它。结果是,尽管默认情况下已经在 Ubuntu 中安装了 Freetype,但开发的库和头文件还没安装。因此我需要去安装 libfreetype6-dev 软件包。这将成为其余安装的公共课。如果您使用 Ubuntu 开发者配置而非基本桌面配置来开始,可能会碰到一点小麻烦。

无论如何,现在我们总算有些进展了。我承认,我还不能随心所欲:

$ make sanitymake[1]: Entering direcTory `/home/jars/openjdk/jdk/make/tools/freetypecheck'make[1]: Nothing to be done for `all'.make[1]: Leaving direcTory `/home/jars/openjdk/jdk/make/tools/freetypecheck'Bootstrap Settings:  BOOTDIR = /usr/local/java   ALT_BOOTDIR = /usr/local/java  BOOT_VER = 1.6 [requires at least 1.5]  UTPUTDIR = ./../build/linux-i586   ALT_OUTPUTDIR =  ABS_OUTPUTDIR = /home/jars/openjdk/jdk/build/linux-i586Build Tool Settings:  SLASH_JAVA = /NOT-SET   ALT_SLASH_JAVA =  VARIANT = OPT  JDK_DEVTOOLS_DIR = /NOT-SET/devtools   ALT_JDK_DEVTOOLS_DIR =  ANT_HOME = /usr/share/ant  FINDBUGS_HOME = /home/jars/findbugs-1.3.0  UNIXCOMMAND_PATH = /bin/   ALT_UNIXCOMMAND_PATH =  COMPILER_PATH = /usr/bin/   ALT_COMPILER_PATH =  DEVTOOLS_PATH = /usr/bin/   ALT_DEVTOOLS_PATH =  UNIXCCS_PATH = /usr/ccs/bin/   ALT_UNIXCCS_PATH =  USRBIN_PATH = /usr/bin/   ALT_USRBIN_PATH =  COMPILER_NAME = GCC  COMPILER_VERSION =  CC_VER = 4.1 [requires at least 3.2]  ZIP_VER = 2.32 [requires at least 2.2]  UNZIP_VER = 5.52 [requires at least 5.12]  ANT_VER = 1.7 [requires at least 1.6.3]  FINDBUGS_VER = 1.3 [requires at least 1.1]  TEMPDIR = ./../build/linux-i586/tmpBuild Directives:  PENJDK = true  USE_HOTSPOT_INTERPRETER_MODE =  PEDANTIC =  DEV_ONLY =  NO_DOCS =  NO_IMAGES =  TOOLS_ONLY =  INSANE =  COMPILE_APPROACH = parallel  PARALLEL_COMPILE_JOBS = 2   ALT_PARALLEL_COMPILE_JOBS =  FASTDEBUG =  COMPILER_WARNINGS_FATAL = false  COMPILER_WARNING_LEVEL =  INCREMENTAL_BUILD = false  CC_HIGHEST_OPT = -O3  CC_HIGHER_OPT = -O3  CC_LOWER_OPT = -O2  CXXFLAGS = -O2 -fPIC -DCC_NOEX -W -Wall -Wno-unused  -Wno-parentheses -fno-omit-frame-pointer -D_LITTLE_ENDIAN  CFLAGS = -O2  -fno-strict-aliasing -fPIC -W -Wall   -Wno-unused -Wno-parentheses -fno-omit-frame-pointer -D_LITTLE_ENDIAN  BOOT_JAVA_CMD = /usr/local/java/bin/java -client -Xmx375m -Xms128m  -XX:PermSize=32m -XX:MaxPermSize=160m  BOOT_JAVAC_CMD = /usr/local/java/bin/javac   -J-XX:ThreadStackSize=768 -J-client -J-Xmx375m -J-Xms128m  -J-XX:PermSize=32m -J-XX:MaxPermSize=160m -encoding ascii  BOOT_JAR_CMD = /usr/local/java/bin/jar  BOOT_JARSIGNER_CMD = /usr/local/java/bin/jarsigner  JAVAC_CMD = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/bin/javac  -J-XX:ThreadStackSize=768 -J-client -J-Xmx375m -J-Xms128m  -J-XX:PermSize=32m -J-XX:MaxPermSize=160m -source 1.5 -target 5  -encoding ascii -Xbootclasspath:./../build/linux-i586/classes  JAVAH_CMD = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/bin/javah  -bootclasspath ./../build/linux-i586/classes  JAVADOC_CMD = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/bin/javadoc  -J-client -J-Xmx375m -J-Xms128m -J-XX:PermSize=32m -J-XX:MaxPermSize=160mBuild Platform. Settings:  USER = jars  PLATFORM. = linux  ARCH = i586  LIBARCH = i386  ARCH_FAMILY = i586  ARCH_DATA_MODEL = 32  ARCHPROP = i386  LINUX_VERSION = Unknown linux  ALSA_VERSION = 1.0.14a  OS_VERSION = 2.6.22-14-generic [requires at least 2.4.9-e.3]  OS_NAME = linux  TEMP_FREE_SPACE = 7515236  FREE_SPACE = 7515236  MB_OF_MEMORY = 503GNU Make Settings:  MAKE = make  MAKE_VER = 3.81 [requires at least 3.78]  MAKECMDGOALS = sanity  MAKEFLAGS =  SHELL = /bin/shTarget Build Versions:  JDK_VERSION = 1.7.0  MILESTONE = internal  RELEASE = 1.7.0-internal  FULL_VERSION = 1.7.0-internal-jars_17_nov_2007_21_32-b00  BUILD_NUMBER = b00External File/Binary Locations:  USRJDKINSTANCES_PATH = /opt/java  BUILD_JDK_IMPORT_PATH = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries   ALT_BUILD_JDK_IMPORT_PATH =  JDK_IMPORT_PATH = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586   ALT_JDK_IMPORT_PATH =  LANGTOOLS_DIST =   ALT_LANGTOOLS_DIST =  CORBA_DIST =   ALT_CORBA_DIST =  JAXP_DIST =   ALT_JAXP_DIST =  JAXWS_DIST =   ALT_JAXWS_DIST =  HOTSPOT_DOCS_IMPORT_PATH = /NO_DOCS_DIR   ALT_HOTSPOT_DOCS_IMPORT_PATH =  HOTSPOT_IMPORT_PATH = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586   ALT_HOTSPOT_IMPORT_PATH =  HOTSPOT_CLIENT_PATH = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/jre/lib/i386/client   ALT_HOTSPOT_CLIENT_PATH =  HOTSPOT_SERVER_PATH = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/jre/lib/i386/server   ALT_HOTSPOT_SERVER_PATH =  CACERTS_FILE = ./../src/share/lib/security/cacerts   ALT_CACERTS_FILE =  CUPS_HEADERS_PATH = /usr/include   ALT_CUPS_HEADERS_PATH =OpenJDK-specific settings:  FREETYPE_HEADERS_PATH = /usr/include   ALT_FREETYPE_HEADERS_PATH =  FREETYPE_LIB_PATH = /usr/lib   ALT_FREETYPE_LIB_PATH =OPENJDK Import Binary Plug Settings:  BINARY_PLUGS_JARFILE = /home/jars/plugs/jre/lib/rt-closed.jar   ALT_BINARY_PLUGS_JARFILE =  BINARY_PLUGS_PATH = /home/jars/plugs   ALT_BINARY_PLUGS_PATH = /home/jars/plugs  BUILD_BINARY_PLUGS_PATH = /NOT-SET/re/jdk/1.7.0/promoted/latest/openjdk/binaryplugs   ALT_BUILD_BINARY_PLUGS_PATH =  PLUG_LIBRARY_NAMES =Previous JDK Settings:  PREVIOUS_RELEASE_PATH = /NOT-SET/re/jdk/1.6.0/archive/fcs/bundles/linux-i586   ALT_PREVIOUS_RELEASE_PATH =  PREVIOUS_JDK_VERSION = 1.6.0   ALT_PREVIOUS_JDK_VERSION =  PREVIOUS_JDK_FILE = jdk-6-linux-i586.tar.gz   ALT_PREVIOUS_JDK_FILE =  PREVIOUS_JRE_FILE = jre-6-linux-i586.tar.gz   ALT_PREVIOUS_JRE_FILE =  PREVIOUS_RELEASE_IMAGE =   ALT_PREVIOUS_RELEASE_IMAGE =WARNING: This machine appears to only have 503Mb of physical memory,     builds on this machine could be slow.WARNING: LANG has been set to en_US.UTF-8, this can cause build failures.     Try setting LANG to "C".WARNING: The direcTory HOTSPOT_IMPORT_PATH=/NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586    does not exist, check your value of ALT_HOTSPOT_IMPORT_PATH.WARNING: HOTSPOT_IMPORT_PATH does not contain the interface file jvmti.h.     Check your value of ALT_HOTSPOT_IMPORT_PATH.WARNING: File /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/lib/sa-jdi.jar     does not exist. The JDI binding for the Serviceability Agent will not be     included in the build.     Please check your Access to      /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/lib/sa-jdi.jar     and/or check your value of ALT_HOTSPOT_IMPORT_PATH.ERROR: You do not have Access to valid Cups header files.    Please check your Access to      /usr/include/cups/cups.h    and/or check your value of ALT_CUPS_HEADERS_PATH,    CUPS is frequently pre-installed on many systems,    or may be downloaded from http://www.cups.orgERROR: HOTSPOT_CLIENT_PATH does not point to a valid HotSpot VM.    Please check your Access to      /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/jre/lib/i386/client/libjvm.so    and/or check your value of ALT_HOTSPOT_CLIENT_PATH.ERROR: HOTSPOT_SERVER_PATH does not point to a valid HotSpot VM.    Please check your Access to      /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586/jre/lib/i386/server/libjvm.so    and/or check your value of ALT_HOTSPOT_SERVER_PATH.Exiting because of the above error(s). 

按顺序继续查看实际的错误消息,下一个问题似乎是默认情况下 Ubuntu 将 LANG 环境变量设置为 en_US.UTF-8,构建脚本想要设置为 C。Ubuntu 刚好在此。在 2007 年,UTF-8 任何人做任何事都应使用的惟一默认编码。尽管如此,我们进行了修复并继续前进:

$ export LANG=C

TODO: 弄清楚构建脚本为什么坚持使用 C 作为 LANG。我怀疑两种基本不同的属性(自然语言和编程语言)在相同的环境变量名称上发生了冲突。

下一个错误是:

HOTSPOT_IMPORT_PATH=/NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-i586 does not exist, check your value of ALT_HOTSPOT_IMPORT_PATH.

到底应该是什么呢?正式构建指令 没有提到。看起来实际上应该是 Java 7 的事,甚至没有引导程序 JDK 的份。或许我在构建 JDK 之前必须构建 HotSpot?

又读了 15 分钟不同的博客之后,我发现 Sun 发布的构建指令是错误的(大吃一惊)。他们谈论的“顶层 Makefile”根本不存在。相反,我必须在 control/make 目录下运行 makefile 并应该构建一切:openjdk、hotspot 等等一切。我们来试一下:

$ make sanitymake[1]: Entering direcTory `/home/jars/openjdk/jdk/make'make[2]: Entering direcTory `/home/jars/openjdk/jdk/make/tools/freetypecheck'freetypecheck.c: In function 'main':freetypecheck.c:45: warning: comparison is always falsedue to limited range of data typefreetypecheck.c:54: warning: comparison is always falsedue to limited range of data typemake[2]: Leaving direcTory `/home/jars/openjdk/jdk/make/tools/freetypecheck'make[1]: Leaving direcTory `/home/jars/openjdk/jdk/make'

该死,我以为我已经修复了 freetype 问题。但是仔细一看,似乎这些消息只是针对 Sun 包括在构建中的 freetypecheck C 程序的一个问题,而非 freetype 本身有问题。相关的代码行是:

if (strcmp(v, QUOTEMACRO(REQUIRED_FREETYPE_VERSION)) < 0) {    printf("Failed: headers are too old./n");  }

and

  if (strcmp(v, QUOTEMACRO(REQUIRED_FREETYPE_VERSION)) < 0) {    printf("Failed: too old library./n");  }

似乎是如果这个测试总是失败,那么 freetype 就是好的,所以我们就忽略这个问题吧。

TODO: 弄清楚正在进行的问题并进行修复。

现在只剩下一个警告和一个错误:

WARNING: This machine appears to only have 503Mb of physical memory,     builds on this machine could be slow.ERROR: You do not have Access to valid Cups header files.    Please check your Access to      /usr/include/cups/cups.h    and/or check your value of ALT_CUPS_HEADERS_PATH,    CUPS is frequently pre-installed on many systems,    or may be downloaded from http://www.cups.org 

我已经为这台笔记本订购了 4GB 的 RAM ,但货还没到。与此同时,我只能忍受缓慢的构建。但是,CUPS 可能是一个问题。返回到 Synaptic。好像又是一个设备安装问题。似乎是我需要的 libcupsys2-dev。我安装了并重试:

$ make sanitymake[1]: Entering direcTory `/home/jars/openjdk/jdk/make'make[2]: Entering direcTory `/home/jars/openjdk/jdk/make/tools/freetypecheck'make[2]: Nothing to be done for `all'.make[2]: Leaving direcTory `/home/jars/openjdk/jdk/make/tools/freetypecheck'make[1]: Leaving direcTory `/home/jars/openjdk/jdk/make'Build Machine Information:  build machine = jars-desktop...Previous JDK Settings:  PREVIOUS_RELEASE_PATH = /NOT-SET/re/jdk/1.6.0/archive/fcs/bundles/linux-i586   ALT_PREVIOUS_RELEASE_PATH =  PREVIOUS_JDK_VERSION = 1.6.0   ALT_PREVIOUS_JDK_VERSION =  PREVIOUS_JDK_FILE = jdk--linux-i586.tar.gz   ALT_PREVIOUS_JDK_FILE =  PREVIOUS_JRE_FILE = jre--linux-i586.tar.gz   ALT_PREVIOUS_JRE_FILE =  PREVIOUS_RELEASE_IMAGE =   ALT_PREVIOUS_RELEASE_IMAGE =WARNING: This machine appears to only have 503Mb of physical memory,     builds on this machine could be slow.Sanity check passed. 

终于!在开始了大约 7 个小时之后,完整性检查通过了。现在试着用 make 开始实际构建:

构建 Make 文件$ makelinux i586 1.7.0-internal build started: 07-11-17 22:33/bin/mkdir -p ../../control/build/linux-i586/j2sdk-image/bin/mkdir -p /home/jars/openjdk/control/build/linux-i586/j2sdk-image...# Running javac:Check_ALT_JDK_IMPORT_PATH/bin/javac -J-XX:ThreadStackSize=768  -J-client -J-Xmx375m -J-Xms128m -J-XX:PermSize=32m  -J-XX:MaxPermSize=160m -source 1.5 -target 5 -encoding ascii  -classpath /usr/local/java/lib/tools.jar -sourcepath /home/jars/openjdk/control/build/linux-i586/corba/gensrc:../../../src/solaris/classes:../../../src/share/classes -d/home/jars/openjdk/control/build/linux-i586/corba/classes@/home/jars/openjdk/control/build/linux-i586/corba/tmp/sun/javax.transaction.xa/.classes.list/bin/sh: Check_ALT_JDK_IMPORT_PATH/bin/javac: not foundmake[3]: *** [.compile.classlist] Error 127make[3]: Leaving direcTory `/home/jars/openjdk/corba/make/javax/xa'make[2]: *** [build] Error 1make[2]: Leaving direcTory `/home/jars/openjdk/corba/make/javax'make[1]: *** [build] Error 1make[1]: Leaving direcTory `/home/jars/openjdk/corba/make'make: *** [corba-build] Error 2

嗯,好像是需要一个 ALT_JDK_IMPORT_PATH 环境变量。完整性检查没有捕获到这一点。系统似乎正试着加载 javac。我不知道为什么 JAVA_HOME 不够好,但是我们可以尝试只将其设置为正常的 JDK 目录:

$ export ALT_JDK_IMPORT_PATH=/usr/local/java

现在构建似乎在前进。系统出现了许多不同类型的错误消息,比如:

../../../../../../../src/share/classes/org/omg/CORBA/ORB.java:593: warning:non-varargs call of varargs method with inexact argument type for last parameter;cast to java.lang.Object for a varargs callcast to java.lang.Object[] for a non-varargs call and to suppress this warning       return (org.omg.CORBA.NVList)meth.invoke(this, argx);

似乎并非 JDK 中的所有代码都要遵循最新的 Sun 编码规范。但是,这仅仅是警告。代码仍在构建。

TODO:修复此问题以获得无警告的构建。

构建机器上的风扇/硬盘驱动器现在已过度疲劳了,整个房间都可以听到旋转的噪音。这只是一台笔记本。我希望它不要烧坏。如果它烧坏了,至少我还在 90 天的保修期内。好了,它安静了一点。哇。噢,等一下。它安静下来的原因是因为它出错了:

/home/jars/openjdk/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86Thread.java:42:cannot find symbolsymbol : class RemoteX86ThreadContextlocation: class sun.jvm.hotspot.debugger.remote.x86.RemoteX86Thread   RemoteX86ThreadContext context = new RemoteX86ThreadContext(debugger);   ^/home/jars/openjdk/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86Thread.java:42: cannot find symbolsymbol : class RemoteX86ThreadContextlocation: class sun.jvm.hotspot.debugger.remote.x86.RemoteX86Thread   RemoteX86ThreadContext context = new RemoteX86ThreadContext(debugger);                     ^注意:/home/jars/openjdk/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java uses or overrides a deprecated API.注意:Recompile with -Xlint:deprecation for details.2 errorsmake[6]: *** [/home/jars/openjdk/control/build/linux-i586/hotspot/outputdir/linux_i486_compiler2/product/../generated/sa-jdi.jar] Error 1make[6]: Leaving direcTory`/home/jars/openjdk/control/build/linux-i586/hotspot/outputdir/linux_i486_compiler2/product'make[5]: *** [all] Error 2make[5]: Leaving direcTory`/home/jars/openjdk/control/build/linux-i586/hotspot/outputdir/linux_i486_compiler2/product'make[4]: *** [sa_stuff] Error 2make[4]: Leaving direcTory`/home/jars/openjdk/control/build/linux-i586/hotspot/outputdir/linux_i486_compiler2/product'make[3]: *** [product] Error 2make[3]: Leaving direcTory`/home/jars/openjdk/control/build/linux-i586/hotspot/outputdir'make[2]: *** [generic_build2] Error 2make[2]: Leaving direcTory `/home/jars/openjdk/hotspot/make'make[1]: *** [product] Error 2make[1]: Leaving direcTory `/home/jars/openjdk/hotspot/make'make: *** [hotspot-build] Error 2

但仍有进展。至少这像是一个真正的 Java 缺陷,而不是环境问题或 C 缺陷。指定的缺陷似乎是没有可访问的把 RemoteThreadContext 构造器,该构造器接受 RemoteDebuggerClient 作为参数。打开 RemoteX86Thread.java 来查看可能正在发生的事情,我没查到任何问题,但是当我打开 RemoteThreadContext.java 时,问题显而易见:文件是空的!我想知道发生了什么。

当我解压或下载原始文件时,也许一些事情中断操作了。我又弄到了一个新的副本,它似乎包含 RemoteThreadContext.java,因此我将其完全复制到它该在的位置,并再次运行 make。这一次,在 make 中止之前,我设法在 Arathi Basin 中完整地玩了一圈:

Timing: 00000 seconds or 0s for make-java-jvm<<>>Recursively making redist all @ Sat Nov 17 23:54:14 CET 2007 ...make[3]: Entering direcTory `/home/jars/openjdk/jdk/make/java/redist'BinaryPlugs import started: Sat Nov 17 23:54:14 CET 2007BINARY_PLUGS_PATH=/home/jars/plugsmake[3]: *** No rule to make target `/home/jars/plugs/jre/lib/i386/libjsoundhs.so', needed by `/home/jars/openjdk/control/build/linux-i586/lib/i386/libjsoundhs.so'. Stop.make[3]: Leaving direcTory `/home/jars/openjdk/jdk/make/java/redist'make[2]: *** [all] Error 1make[2]: Leaving direcTory `/home/jars/openjdk/jdk/make/java'make[1]: *** [all] Error 1make[1]: Leaving direcTory `/home/jars/openjdk/jdk/make'make: *** [jdk-build] Error 2

也许是我没有正确安装插件?也许我必须将其 unjar?不。不会是一个恶作剧吧。等一下:它是一个自运行的 JAR:

$ java -jar jdk-7-ea-plug-b23-linux-i586-30_oct_2007.jarError: Install failed: java.awt.HeadlessException:No X11 DISPLAY variable was set, but this program performedan operation which requires it.java.awt.HeadlessException:No X11 DISPLAY variable was set, but this program performedan operation which requires it.  at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:159)...

嗯,我猜我不能在控制台中运行它。我必须把椅子转向笔记本,在它上面运行。

TODO:让二进制插件安装程序能够无头运行。

好了。现在我在 /home/jars/plugs/openjdk-binary-plugs 中找到了未压缩的二进制插件。我需要更新环境变量以再次匹配 make:

$ export ALT_BINARY_PLUGS_PATH=/home/jars/openjdk-binary-plugs$ make

Make 再次运行,但不久在另一个位置中止了:

In file included from/home/jars/openjdk/jdk/src/share/native/sun/awt/../java2d/pipe/Region.h:34,  from /home/jars/openjdk/jdk/src/share/native/sun/awt/../java2d/pipe/Region.c:30:/home/jars/openjdk/jdk/src/solaris/native/sun/awt/utility/rect.h:31:22: error:X11/Xlib.h: No such file or direcToryIn file included from.../home/jars/openjdk/jdk/src/solaris/native/sun/awt/img_util_md.h:32:  error: expected specifier-qualifier-list before 'XID'/home/jars/openjdk/jdk/src/share/native/sun/awt/image/BufImgSurfaceData.c:  In function 'Java_sun_awt_image_BufImgSurfaceData_freeNativeICMData':/home/jars/openjdk/jdk/src/share/native/sun/awt/image/BufImgSurfaceData.c:95:  warning: cast to pointer from integer of different sizemake[4]: ***[/home/jars/openjdk/control/build/linux-i586/tmp/sun/sun.awt/awt/obj/BufImgSurfaceData.o]Error 1make[4]: Leaving direcTory `/home/jars/openjdk/jdk/make/sun/awt'make[3]: *** [library_parallel_compile] Error 2make[3]: Leaving direcTory `/home/jars/openjdk/jdk/make/sun/awt'make[2]: *** [all] Error 1make[2]: Leaving direcTory `/home/jars/openjdk/jdk/make/sun'make[1]: *** [all] Error 1make[1]: Leaving direcTory `/home/jars/openjdk/jdk/make'make: *** [jdk-build] Error 2

也许是我丢掉了一些 X11 开发库?返回到 Synaptic。让我们安装 libx11-dev 并重试。不,不能那样做。看起来像是 libxt-dev 的一个小 Googling 是缺少的部分。我次我又前进了一点。现在又缺少了另一个文件:

/home/jars/openjdk/jdk/src/solaris/native/sun/awt/splashscreen/splashscreen_config.h:33:34: error: X11/extensions/shape.h: No such file or direcTory.

这次我直接转到 Google,发现“包括文件是非矩形窗口形状扩展标准的一部分”。似乎 libext-dev 是我需要的软件包。又一次突破。

我想这可能是最后一个了。我似乎已经编译了所有的东西。当然,这是 C 而不是 Java,这并不意味着我完成了。现在出现了链接器错误:

/usr/bin/ld: cannot find -lXtst

因此我安装 libxtst-dev 头文件。

越来越烦人了。我仅列出我必须安装的其他库:

libXi-dev

嗯,可能就是它。现在它似乎正在生成 JavaDoc。有许多已破坏的但容易固定的 JavaDoc 标记,但是我想实际上已经完成了。现在,我只能弄清楚构建将每件东西放在哪里。:-)

安装

输出似乎位于 openjdk/control/build/linux-i586/j2sdk-image。(其他一些构建产品,比如无开发工具的 JRE,也位于 openjdk/control/build/linux-i586/。) 试着将其复制到 /opt/java 中,设置为 JAVA_HOME,并将其添加到以下路径中:

$ sudo cp -R j2sdk-image /opt/java$ export JAVA_HOME=/opt/java$ export PATH=/opt/java/bin:$PATH

现在到了实现真理的时刻了:

$ java -versionopenjdk version "1.7.0-internal"OpenJDK Runtime Environment (build 1.7.0-internal-jars_18_nov_2007_01_03-b00)OpenJDK Client VM (build 12.0-b01, mixed mode)$ javac -versionjavac 1.7.0-internal

成功了!此时正好是上午 12:32 ,我大约在 10:00(上午而非下午)左右开始;但毕竟完成了。既然已经安装了所有正确的库,也许下一个安装只用七个小时就够了。

更简单的方法

带有 make 的原始构建对于自动化、测试、接口和连续集成是十分重要的。然而,对于日复一日的开发,它们通常都不是最容易的方法。如果这对于您来说似乎太繁琐的话,那么还有其他方法,但它们都有各自的类似问题。

预建的二进制软件包

如果您觉得调试 makefile 不是度过周末的好方法,那么您可能就需要从 JDK 7 二进制快照页面 中安装预建的二进制软件包。

IDE

我已经集中从命令行开始构建了,因为这是最通用的且能交互操作的方法。它还使得自动化和测试更加容易。命令行构建应该被所有好的开源软件支持。也就是说,有时 IDE 也有用。Sun 积极鼓励使用 NetBeans 来构建和修改 JDK,而且 openjdk 下载附带了预配置的 NetBeans 项目 openjdk/jdk/make/netbeans。仅在 NetBeans 中打开并运行。更多指令,请访问 NetBeans 网站。一定要小心,这些指令并不完全准确,或者您可能仍需进行一些调试以达到完全构建,甚至是在 NetBeans 中。

结束语

我们学到了什么?可以构建 JDK 了。第一次做这件事仅花费一天或两天的时间,而且熟练一下 Unix 和 C 库不是一件坏事。希望它能够让您比我花费更少的时间。从现有 Ubuntu 桌面配置开始,您需要进行如下操作:

从 Sun 中安装最新的 JDK 6。(Ubuntu 仅附带 JRE。)

从 OpenJDK 源码发布页面 下载源码包并解压,以创建 openjdk 目录。

从同一页面下载二进制插件 JAR 并运行以创建 openjdk-binary-plugs 目录。

安装以下软件包:

gawk

ant

findbugs

ALSA

libcupsys2-dev

libext-dev

libXi-dev

libxt-dev

libxtst-dev

手动安装 FindBugs

设置以下环境变量:

ALT_BOOTDIR= JDK 6 的安装位置

ALT_BINARY_PLUGS_PATH= 二进制插件的任意安装位置

ANT_HOME= Ant 的任意安装位置

FINDBUGS_HOME= wherever 的任意安装位置

ALT_JDK_IMPORT_PATH= JDK 6 的安装位置

LANG=C

生成 openjdk/jdk/make/jdk_generic_profile.sh 可执行文件并运行。

移至 openjdk/control/make 并键入 make sanity。调试所发生的任何问题。

通过完整性检查之后,请键入 make。去拿一杯咖啡。这将需要一段时间。

构建完成之后,请将 openjdk/control/build/linux-i586/j2sdk-image 目录复制到您想放置 JDK 的任意位置。/opt/java7 目录可能是一个不错的选择。

在其他 Linux 发行版中,可能需要添加 Ubuntu 默认打包的另外一些库,或者可能不需要添加此处列出的所有库。在其他操作系统(比如 Solaris)中,可能需要指定 gnumake 而非 make(gnumake 是 Ubuntu 上的默认 make)。在 Windows 中,祝您好运。我确信它能够完成,但是我没有完整的一天来调试这一环境了。也许会在另一篇文章中完成这些。

一个有信念者所开发出的力量,大于99个只有兴趣者。

OpenJDK:构建JDK

相关文章:

你感兴趣的文章:

标签云: