热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:羊老姆上线:抄起键盘就编译JDK源码,结果上头了

本文由编程笔记#小编为大家整理,主要介绍了羊老姆上线:抄起键盘就编译JDK源码,结果上头了相关的知识,希望对你有一定的参考价值。
本文由编程笔记#小编为大家整理,主要介绍了羊老姆上线:抄起键盘就编译JDK源码,结果上头了相关的知识,希望对你有一定的参考价值。








好奇害死羊

很多小伙伴们做Java开发,天天写Java代码,肯定离不开Java基础环境:JDK,毕竟我们写好的Java代码也是跑在JVM虚拟机上。


一般来说,我们学Java之前,第一步就是安装JDK环境。这个简单啊,我们一般直接把JDK从官网下载下来,安装完成,配个环境变量就可以愉快地使用了。


不过话说回来,对于这个天天使用的东西,我们难道不好奇这玩意儿它到底是怎么由源码编译出来的吗?


带着这个原始的疑问,今天准备大干一场,自己动动呆萌的小手,来编译一个属于自己的JDK吧!




还有个待填的坑

记得之前不是出过一期关于相关的视频以及文章嘛,细心的小伙伴,可能会发现一个很实际的问题:



我们将src.zip包里的JDK源码解压出来,关联到这份源码之后,调试时是可以进,但是我们在加注释的时候却只能在行尾添加,并不能改变原代码的行结构。换句话说,如果在源码中加了跨行的多行注释,则debug调试的时候就会出现当前行的运行错位问题,这个有点尴尬了。



当然那个视频的评论区,的确也有几个小伙伴提了这个问题:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了


羊老姆上线:抄起键盘就编译JDK源码,结果上头了


羊老姆上线:抄起键盘就编译JDK源码,结果上头了

原因也很简单,因为实际支撑调试运行的代码,并不是我们解压出来的那份JDK源码,那个仅仅是做关联用,实际运行用到的JDK,还是之前系统安装好的那个JDK环境。


要想解决这个问题,那就只能使用自己修改过的代码来自行编译生成自己的JDK,然后用到项目中去!


所以什么都憋说了,肝就完了!




环境准备

首选说在前面的是,编译前的软件版本关系极其重要,自己在踩坑时,所出现的各种奇奇怪怪的问题几乎都和这个有关,后来版本匹配之后,就非常顺利了。



我们来盘点和梳理一下编译一个JDK需要哪些环境和工具:


1、boot JDK


我们要想编译JDK,首先自己本机必须提前已经安装有一个JDK,官方称之为bootstrap JDK(或者称为boot JDK)。


比如想编译JDK 8,那本机必须最起码得有一个JDK 7或者更新一点的版本;你想编译JDK 11,那就要求本机必须装有JDK 10或者11



所以鸡生蛋、蛋生鸡又来了...



2、Unix环境


编译JDK需要Unix环境的支持!


这一点在Linux操作系统和macOS操作系统上已经天然的保证了,而对于Windows兄弟来说稍微麻烦一点,需要通过使用Cygwin或者MinGW/MSYS这种软件来模拟。


就像官方所说:在Linux平台编译JDK一般问题最少,容易成功;macOS次之;Windows上则需要稍微多花点精力,问题可能也多一些。


究其本质原因,还是因为Windows毕竟不是一个Unix-Like内核的系统,毕竟很多软件的原始编译都离不开Unix Toolkit,所以相对肯定要麻烦一些。


3、编译器/编译工具链


JDK底层源码(尤其JVM虚拟机部分)很多都是C++/C写的,所以相关编译器也跑不掉。


一图胜千言,各平台上的编译器支持如下表所示,按平台选择即可:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

4、其他工具


典型的比如:





  • Autoconf:软件源码包的自动配置工具



  • Make:编译构建工具



  • freetype:一个免费的渲染库,
    JDK图形化部分的代码可能会用它


好,环境盘点就到这里,接下来具体列一下我在编译JDK 8JDK 11时分别用到的软件详细版本信息:


编译JDK 8时:





  • 操作系统:macOS 10.11.6



  • boot JDK:JDK 1.8.0 (build 1.8.0_201-b09)



  • Xcode版本:8.2



  • 编译器:Version 8.0.0 (at /usr/bin/clang)


编译JDK 11时:





  • 操作系统:macOS 10.15.4



  • boot JDK:JDK 11.0.7 (build 11.0.7+8-LTS)



  • Xcode版本:11.5



  • 编译器:Version 11.0.3 (at /usr/bin/clang)


大家在编译时如果过程中有很多问题,大概率少软件没装,或者软件版本不匹配,不要轻易放弃,需要耐心自查一下。




下载JDK源码

下载JDK源码其实有两种方式。


方式一:通过Mercurial工具下载


Mercurial可以理解为和Git一样,是另外一种代码管理工具,安装好之后就有一个hg命令可用。



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

OpenJDK的源码已经提前托管到http://hg.openjdk.java.net/


因此,比如下载JDK 8,可直接hg clone一下就行,和git clone一样:


hg clone http://hg.openjdk.java.net/jdk8/jdk8

同理,下载JDK 11


hg clone http://hg.openjdk.java.net/jdk/jdk11

但是这种方式下载速度不是很快。


方式二:直接下载打包好的源码包



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

选择你想要的版本下载即可。




编译前的自动配置

源码包下载好,放到本地某个目录(建议路径纯英文,避免不必要的麻烦),解压之,然后进入源码根目录,执行:


sh configure


当然这里运行的是默认配置项。



这一步会进行一系列的自动配置工作,时间一般很快,最终如果能出现一下提示,那么很幸运,编译前的配置工作就完成了!


这里我给出我自己分别在配置JDK 11JDK 8时候完成时的样子:


配置JDK 8完成:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

配置JDK 11完成:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

注: 如果这一步出错,大概率是某个软件环境未装,或者即使装了,但版本不匹配,控制台打印日志里一般是会提醒的。


比如我在配置JDK 8的时候,就遇到了一个errof:GCC compiler is required的问题:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

明明系统里已经有编译器,但还是报这个错误。通过后来修改 jdk源码根目录/common/autoconf/generated-configure.sh文件,将相关的两行代码注释后就配置通过了



羊老姆上线:抄起键盘就编译JDK源码,结果上头了


羊老姆上线:抄起键盘就编译JDK源码,结果上头了

配置完成,接下来开始执行真正的编译动作了!




真正的编译动作

我们这里进行的是全量编译,直接在我们下载的JDK源码根目录下执行如下命令即可:


make all

这一步编译需要一点时间,耐心等待一下即可。编译过程如果有错误,会终止编译,如果能看到如下两个画面,那么则恭喜你,自己编译JDK源码就已经通过了,可以搞一杯咖啡庆祝一下了。


JDK 8编译完成:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

JDK 11编译完成:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

从两张图的对比可以看出,编译JDK 8JDK 11完成时在输出上还是有区别的。时间上的区别很大程度上来源于JDK 11的编译机配置要高不少。




验证成果

JDK源码编译完成之后肯定会产生和输出很多产物,这也是我们所迫不及待想看到的。


由于JDK 8JDK 11的源码包组织结构并不一样,所以输出东西的内容和位置也有区别。我们一一来盘点一下。


1、JDK 8的编译输出


编译完成,build目录下会生成一个macosx-x86_64-normal-server-release目录,所有的编译成果均位于其中。


首先,编译出来的Java可执行程序可以在如下目录里找到:


jdk源码根目录/build/macosx-x86_64-normal-server-release/jdk/bin


进入该目录后,可以输入./java -version命令验证:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

其次,编译生成的成品JDK套装,可以在目录


jdk源码根目录/build/macosx-x86_64-normal-server-release/images

下找到,如图所示:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

其中:





  • j2sdk-image:编译生成的JDK



  • j2re-image:编译生成的JRE


进入j2sdk-image目录会发现,里面的内容和我们平时从网络上下载的成品JDK内容一致。



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

2、JDK 11的编译输出



JDK 11的源码目录组织方式和JDK 8本身就有区别,编译生成的产物和上面编译JDK 8的输出有一定区别,但也不大。



JDK 11编译完成,同样在build目录下会生成一个macosx-x86_64-normal-server-release目录,所有的编译成果均位于其中。


同样编译出来的Java可执行程序可以在目录


JDK源码根目录/build/macosx-x86_64-normal-server-release/jdk/bin


下看到,进入该目录后,也可以输入./java -version命令验证:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

其次,编译生成的成品JDK 11套装,可以在目录


JDK源码根目录/build/macosx-x86_64-normal-server-release/images

下找到,如图所示:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

其中jdk目录就是编译生成的成品JDK 11套装。




使用自己编译的JDK

既然我们已经动手编译出了JDK成品,接下来我们得用上哇。


新建一个最最基本的Java工程,比如命名为JdkTest,目的是把我们自己编译出的JDK给用上。



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

我们点开Project Structure,选到SDKs选项,新添加上自己刚刚编译生成的JDK,并选为项目的JDK,看看是否能正常工作



羊老姆上线:抄起键盘就编译JDK源码,结果上头了


羊老姆上线:抄起键盘就编译JDK源码,结果上头了

点击确定之后,我们运行之:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

可以看到我们自己编译出的JDK已经用上了。




关联JDK源码并修改

我们继续在上一步JdkTest项目的Project Structure → SDKs里将JDK源码关联到自行下载的JDK源码路径上:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

这样方便我们对自己下载的JDK源码进行阅读、调试、修改、以及在源码里随意做笔记和加注释。


举个最简单的例子,比如我们打开System.out.println()这个函数的底层源码:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

我们随便给它修改一下,加两行简单的标记,像这样:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

为了使我们新加的代码行生效,我们必须要重新去JDK源码的根目录中再次执行 make images重新编译生成JDK方可生效:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

因为之前已经全量编译过了,所以再次make的时候增量编译一般很快。


重新编译之后,我们再次运行JdkTest项目,就可以看到改动的效果了:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了



多行注释的问题

记得之前搭建时,大家可能发现了一个问题:阅读源码嘛,给源代码做点注释或笔记很常见!但那时候有个问题就是做注释时不可改变代码的行结构(只能行尾注释,不能跨行注释),否则debug调试时会出现行号错位的问题。


原因很简单,因为我们虽然做了源代码目录的映射,但是实际支撑运行的JDK还是预先安装好的那个JDK环境,并不是根据我们修改后的源码来重新编译构建的,所以看到这里,解决这个问题就很简单,就像上面一样自行编译一下JDK即可。


实际在实验时,还有一个很典型的问题是,当添加了多行的中文注释后,再编译居然会报错!


比如,还是以上面例子中最简单的System.out.println()源码为例,我们添加几行中文注释:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

这时候我们去JDK源码目录下编译会发现满屏类似这样的报错:



错误: 编码 ascii 的不可映射字符




羊老姆上线:抄起键盘就编译JDK源码,结果上头了

顿时有点懵,毕竟仅仅是加了几行注释。对于我们来说,源码里写点多行的中文注释基本是刚需,然而编译竟会报错,这还能不能让人愉快的玩耍了... 当时后背有点发凉。


实不相瞒,就这个问题排查了一段时间,熬到了很晚。最终折腾了一番,通过如下这种方式解决了,顺便分享给小伙伴们,大家如果遇到了这个问题,可以参考着解决一下。


因为从控制台的报错可以很明显的看出,肯定是字符编码相关的问题导致的,而且都指向了ascii这种编码方式。


于是将JDK的源码从根目录导入了Vs Code,然后全目录查找encoding ascii相关的内容,看看有没有什么端倪,结果发现


jdk源码根目录/make/common/SetupJavaCompilers.gmk文件中有两处指定了ascii相关的编码方式:



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

于是尝试将这两处-encoding ascii的均替换成-encoding utf-8



羊老姆上线:抄起键盘就编译JDK源码,结果上头了

然后再次执行make images编译,编译顺利通过!




至此大功告成!


这样后面不管是阅读、调试还是定制JDK源码都非常方便了。




这次分享就到这里吧,小伙伴们下篇见!


每天进步一点点


慢一点才能更快























给个[在看],是对程序羊最大的支持



















推荐阅读
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • 解决Only fullscreen opaque activities can request orientation错误的方法
    本文介绍了在使用PictureSelectorLight第三方框架时遇到的Only fullscreen opaque activities can request orientation错误,并提供了一种有效的解决方案。 ... [详细]
  • 原文网址:https:www.cnblogs.comysoceanp7476379.html目录1、AOP什么?2、需求3、解决办法1:使用静态代理4 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • Maven Web项目创建时JSP文件常见错误及解决方案
    Maven Web项目创建时JSP文件常见错误及解决方案 ... [详细]
  • 为了在Hadoop 2.7.2中实现对Snappy压缩和解压功能的原生支持,本文详细介绍了如何重新编译Hadoop源代码,并优化其Native编译过程。通过这一优化,可以显著提升数据处理的效率和性能。此外,还探讨了编译过程中可能遇到的问题及其解决方案,为用户提供了一套完整的操作指南。 ... [详细]
  • 该问题可能由守护进程配置不当引起,例如未识别的JVM选项或内存分配不足。建议检查并调整JVM参数,确保为对象堆预留足够的内存空间(至少1572864KB)。此外,还可以优化应用程序的内存使用,减少不必要的内存消耗。 ... [详细]
  • Java中不同类型的常量池(字符串常量池、Class常量池和运行时常量池)的对比与关联分析
    在研究Java虚拟机的过程中,笔者发现存在多种类型的常量池,包括字符串常量池、Class常量池和运行时常量池。通过查阅CSDN、博客园等相关资料,对这些常量池的特性、用途及其相互关系进行了详细探讨。本文将深入分析这三种常量池的差异与联系,帮助读者更好地理解Java虚拟机的内部机制。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • Java测试服务器调试指南详细介绍了如何进行远程调试,并深入解析了Java Xdebug参数的使用方法。本文首先概述了Java内置的调试功能,重点介绍了JDB这一类似于GDB的强大调试工具。通过实例演示,读者可以掌握在测试环境中高效调试Java应用程序的技巧,包括配置远程调试环境和优化调试参数,以提高开发效率和代码质量。 ... [详细]
  • 在尝试为 Unity 编译一个简单的 Java 库时,运行 `ant jar` 命令后遇到了 Java I/O 异常。具体错误信息为“无法启动程序 ${aAPT},错误代码 2”,这通常表示指定的文件或目录不存在。此问题可能是由于环境配置不正确或路径设置有误导致的。建议检查相关路径和环境变量,确保所有依赖项都已正确安装和配置。 ... [详细]
  • 在CentOS 7上部署WebRTC网关Janus
    在CentOS 7上部署WebRTC网关Janus ... [详细]
  • Python与R语言在功能和应用场景上各有优势。尽管R语言在统计分析和数据可视化方面具有更强的专业性,但Python作为一种通用编程语言,适用于更广泛的领域,包括Web开发、自动化脚本和机器学习等。对于初学者而言,Python的学习曲线更为平缓,上手更加容易。此外,Python拥有庞大的社区支持和丰富的第三方库,使其在实际应用中更具灵活性和扩展性。 ... [详细]
author-avatar
mobiledu2502906557
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有