编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

时间:2023-02-23 10:06:35

一、前言

最近在看《深入java虚拟机》,看完后,打算自己实际编译一个jvm出来看看,实践一下。

书上提到了Oracle JDK和OpenJdk的关系,Oracle Jdk7 和OpenJdk 7共用了相当多的代码,所以还是很有学习的必要的:

编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

二、环境

我这里的编译的操作系统是CentOS Linux release 7.4.1708 (Core)  (通过 cat /etc/centos-release查看)。

编译环境相当重要,因为编译openjdk的过程中,网上的文章里,大家遇到的各个问题都不一样,就是因为操作系统不一致。

我主要参考了某位园友的博客:https://www.cnblogs.com/gotodsp/p/8975387.html

该博客里有他用到的工具的百度网盘链接。大家可自行下载。我是下载了之后,通过centos中安装的lrzsz命令来上传的。

命令为rz(上传),sz(下载)。

没安装的话,执行 yum install lrzsz

下面是另一个参考的博客:

http://blog.51cto.com/wangyahui/1612838

我这里引用了不少原博客的内容,但是中间还是有很多问题。我这里会补充说明。

2.1 卸载原jdk

rpm -qa | grep java

yum -y remove XXXX   --XXXX是第一条命令查出来的jdk信息

2.2 编译相关的工具

yum -y install gcc gcc-c++ alsa-lib alsa-lib-devel libXrender libXrender-devel libXi-devel libXt-devel libXtst-devel cups cups-devel

2.3 FreeType

注意:我这边,会把所有工具,最后都解压到/usr/local目录下。先上一张我最后成功了的图:

编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

tar -zxvf freetype-2.4.0.tar.gz -C /usr/local

cd /usr/local/freetype-2.4.0

./configure && make && make install    # 编译安装

##注意:如果安装中出现以下错误

rmdir /usr/local/include/freetype2/freetype/internal 
rmdir: failed to remove `/usr/local/include/freetype2/freetype/internal': No such file or directory 
make: [install] Error 1 (ignored) 
/usr/bin/install -c -m 644 ./builds/unix/ft2unix.h \ 
/usr/local/include/ft2build.h 
/usr/bin/install -c -m 644 ./builds/unix/ftconfig.h \ 
/usr/local/include/freetype2/freetype/config/ftconfig.h

执行以下命令处理:

mkdir -p /usr/local/include/freetype2/freetype/internal

重新安装

./configure && make && make install

2.4 Apache Ant

tar -zxvf apache-ant-1.9.7-bin.tar.gz -C /usr/local # 解压

ln -s /usr/local/apache-ant-1.9.7/bin/ant /usr/bin/ant  # 软链接到bin

2.5 BootstrapJDK

上传到你的虚拟机上后,

chmod +x jdk-6u45-linux-x64.bin

./jdk-6u45-linux-x64.bin    # 解压

mv jdk1.6.0_45 /usr/local/  # 移动目录

然后 vim /etc/profile,配置:

#java environment
export JAVA_HOME=/usr/local/jdk1.6.0_45
export CLASSPATH=.:${JAVA_HOME}/jre/lib/rt.jar:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar
export PATH=$PATH:${JAVA_HOME}/bin

然后执行 source /etc/profile.

再执行java -version试试,看看是不是生效。

2.6 OpenJdk

unzip openjdk-7-fcs-src-b147-27_jun_2011.zip   # 解压

原文章中说得有点乱,不管怎样,做成下面我这种目录效果就行:

编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

三、准备环境变量

vim /etc/profile #在末尾加以下内容。注意其中的目录的路径,另外,先不要忙着执行,先把这一节看完:

export ANT_HOME=/usr/local/apache-ant-1.9.7

export ALT_FREETYPE_HEADERS_PATH=/usr/local/include/freetype2
export ALT_FREETYPE_LIB_PATH=/usr/local/lib
export ALT_DROPS_DIR=/usr/local/src/openjdk/drop
export ALT_BOOTDIR=/usr/local/jdk1.6.0_45
export ALT_JDK_IMPORT_PATH=/usr/local/jdk1.6.0_45
export ALT_OUTPUTDIR=/usr/local/openjdk_output
export LANG=C
export HOTSPOT_BUILD_JOBS=8
export ALT_PARALLEL_COMPILE_JOBS=8
export SKIP_COMPARE_IMAGES=true
export USE_PRECOMPILED_HEADER=true
export ALLOW_DOWNLOADS=true
export SKIP_DEBUG_BUILD=false
export SKIP_FASTDEBUG_BUILD=true
export DEBUG_NAME=debug
export BUILD_LANGTOOLS=true
export BUILD_HOTSPOT=true
export BUILD_JDK=true
export BUILD_DEPLOY=false
export BUILD_INSTALL=false
unset JAVA_HOME
unset CLASSPATH
unset LD_LIBRARY_PATH

这里依次解释下各个选项:

  • ANT_HOME   # 编译工具ant的路径
  • ALT_FREETYPE_HEADERS_PATH  #  freetype2头文件安装目录,一般无需替换
  • ALT_FREETYPE_LIB_PATH # 这个也无需修改
  • ALT_DROPS_DIR #这个目录很重要,下图来自参考的那位园友的博客里的:

编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

  • ALT_BOOTDIR  #启动jdk的路径
  • ALT_JDK_IMPORT_PATH #看文章里是配成一致的,暂时还不知道配成不一致的结果
  • ALT_OUTPUTDIR  #最终编译输出的位置,来个直观图展示下

  编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

  • LANG  ##语言选项,这个必须设置,否则编译好后会出现一个HashTable的NPE错
  • HOTSPOT_BUILD_JOBS #并行编译的线程数,设置为和CPU内核数量一致即可
  • ALT_PARALLEL_COMPILE_JOBS #并行编译的线程数,设置为和CPU内核数量一致即可
  • SKIP_COMPARE_IMAGES  #比较本次build出来的映像与先前版本的差异。这对我们来说没有意义,必须设置为true,否则sanity检查会报缺少先前版本JDK的映像的错误提示。
  • USE_PRECOMPILED_HEADER #使用预编译头文件,不加这个编译会更慢一些
  • ALLOW_DOWNLOADS  #允许自行下载依赖
  • SKIP_DEBUG_BUILD  #要编译的版本
  • SKIP_FASTDEBUG_BUILD 要编译的版本
  • BUILD_LANGTOOLS # 是否编译语言工具
  • BUILD_HOTSPOT #编译虚拟机
  • BUILD_JDK 编译jdk
  • BUILD_DEPLOY #把它设置为false可以避开javaws和浏览器Java插件之类的部分的build
  • BUILD_INSTALL #把它设置为false就不会build出安装包。因为安装包里有些奇怪的依赖,但即便不build出它也已经能得到完整的JDK映像,所以还是别build它好了

  • unset JAVA_HOME  unset CLASSPATH  unset LD_LIBRARY_PATH #这三个环境变量必须去掉,不然会有很诡异的事情发生(我没有具体查过这些"诡异的#事情",Makefile脚本检查到有这2个变量就会提示警告)

设置完了后,保存,刷新一下。 source /etc/profile

四、检查

在/usr/local/src/openjdk下运行 make sanity。

如果最后一行显示:

Sanity check passed.

则表示检查通过。

五、编译jvm

在同上目录下,执行 make DISABLE_HOTSPOT_OS_VERSION_CHECK=ok

之所以加DISABLE_HOTSPOT_OS_VERSION_CHECK=ok,是因为遇到了下面的异常:

ERROR:××× recipe for target ‘check_os_version’ failed ×××

为了跳过版本校验,所以加了上述参数。

参考了:https://blog.csdn.net/desiyonan/article/details/80801830

好了,接下来静静等待,我最后那一次成功的编译,花了大概20-30分钟,成功了,会有如下显示(突然发现前面tree了一把,刷屏了,只能网上去找个图了。。。):

编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

(别人家怎么那么快,10分钟。。。)

我这边还是贴一个我这边编译好的虚拟机的version显示吧:

编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码

如果你没那么幸运,发生了各种error,导致make中断的话,不要走开。参考下面一节。

六、遇到的问题

ps:如果看到提示某个文件报错,又不知道在哪,大家直接用find / -name abc.txt查找吧。

1、Error: time is more than 10 years from present: 1136059200000

通过修改CurrencyData.properties文件, 把10年之前的时间修改为10年之内即可
Index: /usr/openjdk/jdk/src/share/classes/java/util/CurrencyData.properties

注意,该文件内有5,6处要修改的地方。不要漏了,漏了又是10+分钟。。

2、 /usr/bin/ld: cannot find -lstdc++

Linking vm...
/usr/bin/ld: cannot find -lstdc++
collect2: error: ld returned 1 exit status
/usr/bin/chcon: cannot access 'libjvm.so': No such file or directory
ERROR: Cannot chcon libjvm.so
/usr/bin/objcopy --only-keep-debug libjvm.so libjvm.debuginfo
/usr/bin/objcopy: 'libjvm.so': No such file
make[4]: *** [libjvm.so] Error 1
make[4]: Leaving directory `/usr/src/openjdk/hotspot/build/hotspot_debug/linux_amd64_compiler2/debug'
make[3]: *** [the_vm] Error 2
make[3]: Leaving directory `/usr/src/openjdk/hotspot/build/hotspot_debug/linux_amd64_compiler2/debug'
make[2]: *** [debug] Error 2
make[2]: Leaving directory `/usr/src/openjdk/hotspot/build/hotspot_debug'
make[1]: *** [generic_build2] Error 2
make[1]: Leaving directory `/usr/src/openjdk/hotspot/make'
make: *** [debug] Error 2


解决:

yum search libc++ 
yum install libstdc++-static

3、不识别'-mimpure-text'参数

报错:gcc: error: unrecognized command line option '-mimpure-text'

make[5]: *** [/openjdk/build/linux-amd64/../linux-amd64-debug/lib/amd64/libverify.so] Error 1

解决:

就在 openjdk源码中的,/make/common/shared/Compiler-gcc.gmk 中去掉 -mimpure-text 命令

4、constantPoolOop.cpp

Error:/openjdk/hotspot/src/share/vm/oops/constantPoolOop.cpp:272:39: error: converting 'false' to pointer type 'methodOop' [-Werror=conversion-null]

将return false 改为return NULL

5、__LEAF 头文件重复定义问题

/openjdk/hotspot/src/share/vm/runtime/interfaceSupport.hpp:430:0: error: "__LEAF" redefined [-Werror]
 #define __LEAF(result_type, header)

/usr/include/x86_64-linux-gnu/sys/cdefs.h:42:0: note: this is the location of the previous definition
 #  define __LEAF , __leaf__

在interfaceSupport.hpp代码的最前面增加:(后面的\也是需要的,宏定义中的换行符)

#ifdef __LEAF
#undef __LEAF

#define __LEAF(result_type, header)                                  \
  TRACE_CALL(result_type, header)                                    \
  debug_only(NoHandleMark __hm;)                                     \
  /* begin of body */
#endif

6、/hotspot/src/share/vm/opto/loopnode.cpp:896:49: error: converting 'fals' to pointer type 'Node*' [-Werror=conversion-null]

解决:修改openjdk/hotspot/src/share/vm/opto/loopnode.cpp: 第896行 return false改为return (Node*)false; 或者 return NULL;

7、无法下载包问题 Redirection detected from https to http. Protocol switch unsafe, not allowed

解决:其实前面已经提到了,网盘里提供了jdk6-jaf-b20.zip、jdk6-jaxp-b20.zip、jdk6-jaxws-b20.zip三个文件即为了解决该问题。将这三个文件复制到openjdk/drop目录下。

同时要配置ALT_DROPS_DIR指向该目录。

七、总结

今天搞这个+写博客,差不多大半天了。。。

一千个人编译jdk,就会有一千个错误。。。

关键是等得又久,错了又得重来。。。不过再怎么说,还是很有成就感的。

看了书,就得实践,毕竟老祖宗说的:纸上得来终觉浅,绝知此事要躬行。

编译你的第一个Java虚拟机--Centos 7 编译openJdk1.7源码的更多相关文章

  1. 深入理解Java虚拟机(程序编译与代码优化)

    文章首发于微信公众号:BaronTalk,欢迎关注! 对于性能和效率的追求一直是程序开发中永恒不变的宗旨,除了我们自己在编码过程中要充分考虑代码的性能和效率,虚拟机在编译阶段也会对代码进行优化.本文就 ...

  2. java开源即时通讯软件服务端openfire源码构建

    java开源即时通讯软件服务端openfire源码构建 本文使用最新的openfire主干代码为例,讲解了如何搭建一个openfire开源开发环境,正在实现自己写java聊天软件: 编译环境搭建 调试 ...

  3. Java 集合系列 09 HashMap详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  4. Java 集合系列 10 Hashtable详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  5. Java 集合系列 06 Stack详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  6. Java 集合系列 05 Vector详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  7. Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  8. Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  9. java 日志体系(四)log4j 源码分析

    java 日志体系(四)log4j 源码分析 logback.log4j2.jul 都是在 log4j 的基础上扩展的,其实现的逻辑都差不多,下面以 log4j 为例剖析一下日志框架的基本组件. 一. ...

随机推荐

  1. 修改/etc/profile文件

    通常情况下,/etc/profile文件是只读的,直接用vi或gedit打开修改后是无法保存的.要修改profile,需要取得root权限,(使用gedit编辑)应该如下: $sudo gedit / ...

  2. Loadrunner关联取参及设置检查点

    Loadrunner关联取参及设置检查点: 获取post的响应值当作参数存储,要在此post请求之上添加 web_reg_save_param("sign", "LB=m ...

  3. 如何成为一名优秀的前端工程师 (share)

    发现一篇不错的博文,和大家分享一下,为有志成为一名优秀前端工程师的童鞋们提供一个参考. :)~ 本文来源:http://www.biaodianfu.com/what-makes-a-good-fro ...

  4. SQL点滴4—筛选数据列的类型,字段大小,是否可为空,是否是主键,约束等等信息

    原文:SQL点滴4-筛选数据列的类型,字段大小,是否可为空,是否是主键,约束等等信息 项目需要将Access数据库中的数据导入到SQL Server中,需要检验导入后的数据完整性,数据值是否正确.我们 ...

  5. GBDT(MART)概念简介

    GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种用于回归的机器学习算法,该算法由 ...

  6. !!!常用CSS代码

    http://www.cnblogs.com/qq21270/p/4854643.html 伪类 http://www.cnblogs.com/qq21270/p/4891167.html CSS3动 ...

  7. e794. 创建JSlider组件

    // Create a horizontal slider with min=0, max=100, value=50 JSlider slider = new JSlider(); // Creat ...

  8. spring浏览器国际化的原理

    We will add two languages support to our application: English and German. Depending on the locale se ...

  9. javascript对象属性的命名规则

    JS标识符的命名规则,即变量的命名规则: 标识符只能由字母.数字.下划线和‘$’组成 数字不可以作为标识符的首字符 对象属性的命名规则 通过[]操作符为对象添加属性时,属性名称可以是任何字符串(包括只 ...

  10. jquery中的$.each跳出循环并获取返回值

    jquery中使用each方法,类似于while或者for循环 一种退出循环的方式是:当数据全部被遍历完成,自然退出, 另一种方法是:当我们在循环中返回一个false时,会跳出循环 这里来使用第二种方 ...