从来没有想过要自己去编译jdk,更没有想过要交叉编译jdk。哈哈,我也真是个人才(主要是领导安排的活)。为了联手以及填坑,先编译x86平台下的openjdk,下面是编译过程其中包含很多错误,记录一下心路历程。
一、环境
软件 |
版本 |
操作系统 |
Redhat7.1 |
bootJdk |
1.7.0_51 |
GNU Make |
3.82 |
g++ (GCC) |
4.8.2 |
Openjdk |
1.8u |
二、步骤
2.1 安装依赖文件(其实就是configure过程中报的错误)
yum install cups-devel yum install libXtst-devel libXt-devel libXrender-devel yum install freetype-devel yum install alsa-lib-devel
如果不能上外网,可参考如何搭建本地yum源。
2.2 configure配置
Configure过程需要指定一个最重要的参数--with-boot-jdk,按照官网编译说明文档,这个参数必须是前一个大版本的jdk,例如我们需要编译jdk1.8,那么boot-jdk必须是jdk1.7。执行如下命令行:
sh configure --prefix=/root/openjdk/output --target=i686 --with-boot-jdk=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.51-2.4.5.5.el7.x86_64 --with-target-bits=64
configure过程其实就是各种依赖文件安装,一般把依赖文件搞定问题就不大。
2.3 进入build目录,执行编译
[root@localhost jdk8u]# cd build/linux-x86_64-normal-server-release/ [root@localhost linux-x86_64-normal-server-release]# ls bootcycle-spec.gmk build.log.old config.h config.status corba docstemp hotspot-spec.gmk jaxp jdk Makefile source_tips spec.sh build.log compare.sh config.log configure-arguments docs hotspot images jaxws langtools nashorn spec.gmk tmp [root@localhost linux-x86_64-normal-server-release]# make [root@localhost linux-x86_64-normal-server-release]#
2.4 MAKE常用参数
参数 |
说明 |
JOBS=X |
同时编译线程数目,默认是16 |
LOG=debug、LOG=trace |
编译日志级别不同,用于编译出错定位 |
clean-XXX |
支持langtools, hotspot, jaxp, jaxws,jdk |
还有一些其他参数,可执行make help。
2.5 测试
[root@localhost test-demo-hello]# ../bin/javac Hello.java [root@localhost test-demo-hello]# ../bin/java Hello Hello World! [root@localhost test-demo-hello]# [root@localhost test-demo-hello]#
三、问题
本篇最核心内容就在于此,搜了很多文章,大部分都是没有问题,这种文章对于我来说一点意义没有。下面这些问题,基本上都是makefile的问题。然而为啥makefile有问题,猜测是代码版本有问题。
【问题1 找不到变量定义】
Generating exceptions classes Compiling 163 files for BUILD_TOOLS /bin/sh: -Xbootclasspath/p:/root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/langtools/dist/bootstrap/lib/javac.jar: 没有那个文件或目录 gmake[2]: *** [/root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/btclasses/_the.BUILD_TOOLS_batch] 错误 127 gmake[2]: *** 正在等待未完成的任务.... gmake[1]: *** [gensrc-only] 错误 2 make: *** [jdk-only] 错误 2 [root@localhost linux-x86_64-normal-server-release]#
问题原因:主要是找不到变量JVM的定义
解决方法:修改两个配置文件
1)修改jdk/make/Tools.gmk,在第60行附近,增加JAVA_SMALL的定义
JAVA_SMALL ?= /root/openjdk/ppc64_openjdk/bootjdk7u79/jdk1.7.0_79/bin/java -Xms64M -Xmx1100M -XX:PermSize=32m -XX:MaxPermSize=160m -XX:ThreadStackSize=1536
2)修改make/common/JavaCompilation.gmk,在553行附近,有一个$$($1_JVM),将其设置为
/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.51-2.4.5.5.el7.x86_64/bin/java -Xms64M -Xmx1100M -XX:PermSize=32m -XX:MaxPermSize=160m -XX:ThreadStackSize=1536
【问题2 异常错误,无影响】
Verifying /home/jdk8u/build/linux-x86_64-normal-server-release//jdk/gensrc_x11wrappers/sizes.64.verification.tmp to /home/jdk8u/build/linux-ppc64-normal-server-release/jdk/gensrc_x11wrappers/sizes.64 [Error] encoded value was less than 0: encode(-8.326673E-17, 5.0, 11.0, 16.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] encoded value was greater than 3: encode(15.029411, 1.0, 14.0, 15.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] encoded value was greater than 3: encode(15.029411, 1.0, 14.0, 15.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] encoded value was greater than 3: encode(15.029411, 1.0, 14.0, 15.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] encoded value was greater than 3: encode(15.029411, 1.0, 14.0, 15.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] encoded value was greater than 3: encode(15.029411, 1.0, 14.0, 15.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] encoded value was greater than 3: encode(15.029411, 1.0, 14.0, 15.0) [Error] encoded value was less than 0: encode(-0.05882353, 1.0, 24.0, 25.0) [Error] Encountered Infinity: encode(-0.00877193, 0.0, 7.0, 7.0)
【问题3 .java(.class)生成异常,文件大小为0】
## Starting jdk Generating beaninfo /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/nio/cs/StandardCharsets.java:365: 错误: 解析时已到达文件结尾 }; ^ /root/openjdk/jdk8u/jdk/src/share/classes/java/io/OutputStreamWriter.java:29: 错误: 无法访问CharsetEncoder import java.nio.charset.CharsetEncoder; ^ 错误的源文件: /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/gensrc/java/nio/charset/CharsetEncoder.java 文件不包含类java.nio.charset.CharsetEncoder 请删除该文件或确保该文件位于正确的源路径子目录中。 /root/openjdk/jdk8u/jdk/src/share/classes/java/lang/ClassValue.java:34: 错误: 找不到符号 import static java.lang.ClassValue.ClassValueMap.probeBackupLocations; ^ 符号: 静态 probeBackupLocations 位置: 类 /root/openjdk/jdk8u/jdk/src/share/classes/java/lang/ClassValue.java:33: 错误: 找不到符号 import static java.lang.ClassValue.ClassValueMap.probeHomeLocation; ^ 符号: 静态 probeHomeLocation 位置: 类 /root/openjdk/jdk8u/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java:50: 错误: 找不到符号 import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; ^ 符号: 静态 GET_CLASSLOADER_PERMISSION 位置: 类 /root/openjdk/jdk8u/jdk/src/share/classes/java/lang/annotation/Retention.java:44: 错误: 找不到符号 @Retention(RetentionPolicy.RUNTIME) ^ 符号: 变量 RUNTIME 位置: 类 RetentionPolicy /root/openjdk/jdk8u/jdk/src/share/classes/java/lang/annotation/Documented.java:40: 错误: 找不到符号 @Retention(RetentionPolicy.RUNTIME) ^ 符号: 变量 RUNTIME 位置: 类 RetentionPolicy /root/openjdk/jdk8u/jdk/src/share/classes/java/lang/annotation/Target.java:77: 错误: 找不到符号 @Retention(RetentionPolicy.RUNTIME) ^ 符号: 变量 RUNTIME 位置: 类 RetentionPolicy /root/openjdk/jdk8u/jdk/src/share/classes/java/lang/SuppressWarnings.java:53: 错误: 找不到符号
问题原因:由于是多线程编译导致文件生成异常或者文件大小为0
解决方案:将异常文件删除掉(也可删除掉目录)并重新执行make JOBS=1
【问题4 找不到bundle类】
## Starting jdk Exception in thread "main" java.util.MissingResourceException: Can't find bundle for base name sun.text.resources.BreakIteratorRules, locale at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1499) at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1322) at java.util.ResourceBundle.getBundle(ResourceBundle.java:841) at build.tools.generatebreakiteratordata.GenerateBreakIteratorData.generateFiles(GenerateBreakIteratorData.java:86) at build.tools.generatebreakiteratordata.GenerateBreakIteratorData.main(GenerateBreakIteratorData.java:70) gmake[2]: *** [/root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources/_the.bifiles] 错误 1 gmake[1]: *** [gendata-only] 错误 2 make: *** [jdk-only] 错误 2 [root@localhost jdk8u]#
再次执行make LOG=trace,查看详细错误信息
SetupJavaCompilation(BUILD_BREAKITERATOR) [2] SETUP := GENERATE_OLDBYTECODE [3] SRC := /root/openjdk/jdk8u/jdk/src/share/classes [4] DISABLE_SJAVAC := true [5] JAVAC_SOURCE_PATH_OVERRIDE := /root/openjdk/jdk8u/jdk/src/share/classes/sun/text/resources [6] INCLUDES := sun/text/resources [7] INCLUDE_FILES := sun/text/resources/BreakIteratorRules.java sun/text/resources/BreakIteratorInfo.java sun/text/resources/th/BreakIteratorRules_th.java sun/text/resources/th/BreakIteratorInfo_th.java [8] BIN := /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/break_iterator/classes gmake[2]: 进入目录“/root/openjdk/jdk8u/jdk/make” /usr/bin/echo "Generating BreakIteratorData" Generating BreakIteratorData /usr/bin/mkdir -p /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources /usr/bin/rm -f /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources/CharacterBreakIteratorData /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources/WordBreakIteratorData /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources/LineBreakIteratorData /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources/SentenceBreakIteratorData /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.51-2.4.5.5.el7.x86_64/bin/java -Xms64M -Xmx1100M -XX:PermSize=32m -XX:MaxPermSize=160m -XX:ThreadStackSize=1536 -cp /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/btclasses build.tools.generatebreakiteratordata.GenerateBreakIteratorData \ -o /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources \ -spec /root/openjdk/jdk8u/jdk/make/data/unicodedata/UnicodeData.txt Exception in thread "main" java.util.MissingResourceException: Can't find bundle for base name sun.text.resources.BreakIteratorRules, locale at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1499) at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1322) at java.util.ResourceBundle.getBundle(ResourceBundle.java:841) at build.tools.generatebreakiteratordata.GenerateBreakIteratorData.generateFiles(GenerateBreakIteratorData.java:86) at build.tools.generatebreakiteratordata.GenerateBreakIteratorData.main(GenerateBreakIteratorData.java:70) gmake[2]: *** [/root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources/_the.bifiles] 错误 1 gmake[2]: 离开目录“/root/openjdk/jdk8u/jdk/make” gmake[1]: *** [gendata-only] 错误 2 gmake[1]: 离开目录“/root/openjdk/jdk8u/jdk/make” make: *** [jdk-only] 错误 2 [root@localhost jdk8u]#
这个问题困扰了我三天,各种谷歌,github,mail list都没有找到解决方法,只能自己分析一下日志。
1)定位过程1:确定错误命令行
/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.51-2.4.5.5.el7.x86_64/bin/java -Xms64M -Xmx1100M -XX:PermSize=32m -XX:MaxPermSize=160m -XX:ThreadStackSize=1536 -cp /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/btclasses build.tools.generatebreakiteratordata.GenerateBreakIteratorData \ -o /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources \ -spec /root/openjdk/jdk8u/jdk/make/data/unicodedata/UnicodeData.txt
单独执行这个命令行就会报这个错误。
2)定位过程2:异常信息提示找不到bundle类,但是实际目录中确实存在这个类文件:
[root@localhost linux-x86_64-normal-server-release]# find ./ -name "*BreakIteratorRules*" ./jdk/classes/sun/text/resources/th/BreakIteratorRules_th.class ./jdk/break_iterator/classes/sun/text/resources/th/BreakIteratorRules_th.class ./jdk/break_iterator/classes/sun/text/resources/BreakIteratorRules.class [root@localhost linux-x86_64-normal-server-release]# [root@localhost linux-x86_64-normal-server-release]#
猜测应该命令行参数有问题,可能需要指定目录
3)定位过程3:研究该命令行各个参数含义
参数 |
含义 |
-cp |
Class搜索路径(进程java的参数) |
-o |
输出文件目录(类GenerateBreakIteratorData的参数) |
-spec |
输入文件(类GenerateBreakIteratorData 的参数) |
尝试修改:在-cp中增加BreakIteratorRules的所在目录路径,然后再次单独执行上面命令行,例如
/root/openjdk/ppc64_openjdk/bootjdk7u79/jdk1.7.0_79/bin/java \ -Xms64M -Xmx1100M -XX:PermSize=32m -XX:MaxPermSize=160m -XX:ThreadStackSize=1536 \ -cp /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/btclasses:/root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/break_iterator/classes/ build.tools.generatebreakiteratordata.GenerateBreakIteratorData -o /root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/classes/sun/text/resources -spec /root/openjdk/jdk8u/jdk/make/data/unicodedata/UnicodeData.txt
其实就是在-cp增加路径,格式内容为 -cp P1:P2:P3。发现这样修改,不在报异常了,说明修改正确(此时此刻非常的兴奋)。
解决方案:增加类路径,修改./jdk/make/Tools.gmk,大概在96行,在-cp后面增加路径/root/openjdk/jdk8u/build/linux-x86_64-normal-server-release/jdk/break_iterator/classes/
四、后记
其实项目要求是编译powerpc平台下面的jdk,通过上面编译x86的平台,本以为编译powerpc应该很顺利,但是还遇到问题,而且是无法解决的问题。
在编译过程生成了一个可执行文件,这个文件是powerpc平台下,需要运行此文件且此文件会生成一些文件以便其他编译能够正常使用。这就带来了一个问题,x86平台下是无法运行powerpc平台。所以交叉编译powerpc平台宣布失败(当然也有其他方式,比如模拟powerpc平台)。
五、总结
以上过程就是编译openjdk整个流程,大概花费了4天时间,这个应该是我有史以来最难编译的软件。虽然辛苦,但最终编译出来了,还是挺欣慰,挺high的。希望本篇能指导更多网友(Powerpc版本是通过虚拟化PowerPc平台系统,在虚拟机中编译的)。