前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK源码编译与版号控制 发布于 20

JDK源码编译与版号控制 发布于 20

作者头像
DioxideCN
发布2023-10-21 11:39:09
4040
发布2023-10-21 11:39:09
举报

引言

JDK(Java Development Kit)作为Java的核心开发工具包,其包含了许多Java开发者们日常所需的工具,比如编译器、运行时环境以及各种基础的类库。然而,对于大多数开发者来说,JDK可能只是一个黑盒工具。所有编写的Java代码最终都会被JDK转化为可执行的程序,但是JDK内部的工作原理可能对于大部分开发者来说仍然理解困难。更何况,如果想对JDK进行一些定制或者修改,那么不了解JDK的编译过程就无法开始。

深入探索JDK的源码,并尝试自己编译JDK似乎是更有效的了解Java的途径之一。在本章中,我将详细介绍我在Linux、MacOS和Windows平台上编译JDK17u的过程和遇到的问题。希望通过这篇文章,能够为那些对JDK内部机制感兴趣的开发者们提供一些帮助。

Liunx平台

准备工作

在不具备一台Linux主机的情况下,最好的选择就是使用虚拟机来编译JDK。以运行在VMware 16上的Ubuntu 18.04.6 LTS操作系统为例,准备以下的编译环境:

下载JDK16或更高版本,这里以jdk-17_linux-x64_bin为例

代码语言:javascript
复制
	wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz

解压并移动这个jdk到指定的目录中(需要建立/usr/lib/jvm/目录)

代码语言:javascript
复制
	tar -xvf jdk-17_linux-x64_bin.tar.gz
	sudo mv jdk-17.0.7 /usr/lib/jvm/

设置Java环境变量 为了让系统能够找到 JDK,需要设置 JAVA_HOME 环境变量,并将其添加到 PATH 变量中。可以通过vi ~/.bashrc来编辑 ~/.bashrc~/.profile 文件来实现。打开文件并在文件末尾添加以下内容:

代码语言:javascript
复制
	export JAVA_HOME=/usr/lib/jvm/jdk-17.0.7
	export PATH=$JAVA_HOME/bin:$PATH

编辑完成按下ESC后键入:wq来保存环境变量配置文件,最后需要应用这个文件让这些更改生效:

代码语言:javascript
复制
	source ~/.bashrc

通过java -version来查看是否配置成功:

代码语言:javascript
复制
	dioxidecn@dioxidecn-virtual-machine:~$ java -version
	java version "17.0.7" 2023-04-18 LTS
	Java(TM) SE Runtime Environment (build 17.0.7+8-LTS-224)
	Java HotSpot(TM) 64-Bit Server VM (build 17.0.7+8-LTS-224, mixed mode, sharing)

克隆JDK17u的源码,如果没有git环境则需要手动下载

代码语言:javascript
复制
	git clone git@github.com:openjdk/jdk17u.git
	或
	git clone https://github.com/openjdk/jdk17u.git

使用yum工具安装编译工具,这些工具都将辅助后面的configure来构建预编译环境

代码语言:javascript
复制
	sudo yum install libXtst-devel libXt-devel libXrender-devel
	sudo yum install cups-devel
	sudo yum install freetype-devel
	sudo yum install alsa-lib-devel

通过configure文件构建预编译环境

代码语言:javascript
复制
	sudo bash configure \
		--with-target-bits=64 \
		--with-debug-level=release
		--disable-warnings-as-errors

构建编译环境的过程会花上2-5分钟左右,当出现如下的提示则说明构建成功(如果之前构建过环境则每次执行的构建方法都会进行覆盖。之前的图片丢失了,这里的图片中以已jdk11为boot-jdk,对jdk12u源码进行构建)

Cygwin-build
Cygwin-build

当编译环境构建完成后使用make allmake images来编译JDK,这个过程会耗费10分钟到1小时不等。当出现以下结果则说明编译成功(之前的图片丢失了,这里的图片中以已jdk12u为例进行编译):

Cygwin-success
Cygwin-success

编译验证

至此,Linux环境下的JDK17就已经编译完成了。编译完成的Java文件被存放在了/jdk17u/build/linux-x86_64-server-release/jdk/bin中。使用如下的命令来验证这个编译完成的Java的可行性:

代码语言:javascript
复制
cd /home/dioxidecn/openjdk/jdk12/build/linux-x86_64-server-release/jdk/bin
java -version

当正确输出JDK和JVM版本信息说明编译成功(之前的图片丢失了,这里的图片中以已jdk12u的编译结果为例):

代码语言:javascript
复制
dioxidecn@dioxidecn-virtual-machine:~/openjdk/jdk12/build/linux-x86_64-server-release/jdk/bin$ java -version
openjdk version "11.0.19" 2023-04-18  
OpenJDK Runtime Environment (build 11.0.19+7-post-Ubuntu-0ubuntu118.04.1)  
OpenJDK 64-Bit Server VM (build 11.0.19+7-post-Ubuntu-0ubuntu118.04.1, mixed mode, sharing)

macOS平台

准备工作

这里只以M1系列ARM架构的macOS(Ventura 13.3.1)为例。在macOS上编译JDK是非常简单的,在开始编译前需要安装Xcode Command Line Tools(下文简称XCLT,如果是从App Store安装的Xcode则默认会携带XCLT):

如果未安装通过以下的命令进行安装:

代码语言:javascript
复制
	xcode-select --install

通过Homebrew安装autoconf、automake、libtool、pkg-config和freetype:

代码语言:javascript
复制
	brew install autoconf automake libtool pkg-config freetype

编译JDK17u需要借助boot-jdk,因此在mac上需要准备一个JDK16及以上版本的Java环境(这里以oracle arm64 jdk-17.0.4.1为例)Java环境的配置参考Linux平台的前4点

如果使用的是国行的mac则需要此步,否则在后期编译过程中会发生如下的错误:

代码语言:javascript
复制
	OpenJDK17:Target CPU mismatch. We are building for x86_64 but CL is for ""; expected "x64"

打开源码中的make/autoconf/toolchain.m4文件,找到字串Target CPU mismatch,将AC_MSG_ERROR改成AC_MSG_RESULT即可

通过configure文件构建预编译环境

代码语言:javascript
复制
	bash configure \
		--openjdk-target=aarch64-apple-darwin \
		--disable-warnings-as-errors \
		--with-boot-jdk="/Users/dioxide/Environment/jdk-17.0.4.1.jdk/Contents/Home"
  • --openjdk-target 定义了目标编译的JDK使用环境,这里指代的是macOS
  • --disable-warnings-as-errors 将warnings不作为errors来检查,如果不启用这项可能导致一些较老的C/C++语法出现warnings警告后被转为errors错误从而导致异常的终止环境的构建
  • --with-boot-jdk 编译时需要的JDK

构建编译环境的过程会花上2-5分钟左右,当出现如下的提示则说明构建成功(如果之前构建过环境则每次执行的构建方法都会进行覆盖)

Cygwin-build
Cygwin-build

当出现报错时检查构建步骤是否按要求进行或是否有遗漏。在回复中提供完整的报错信息可以让读者们共同为你解决问题。

当编译环境构建完成后使用make allmake images来编译JDK,这个过程会耗费10分钟到30分钟不等(差量编译速度会更快)。当出现以下结果则说明编译成功:

Cygwin-success
Cygwin-success

如果遇到无法解决的异常或工具丢失问题,可以先尝试配置环境变量如若异常仍然存在再尝试重新安装整个Xcode

编译验证

至此,macOS环境下的JDK17就已经编译完成了。编译完成的Java文件被存放在了/jdk17u/build/macosx-aarch64-server-release/jdk/bin中。使用如下的命令来验证这个编译完成的Java的可行性:

代码语言:javascript
复制
cd /Users/dioxide/Environment/jdk17u/build/macosx-aarch64-server-release/jdk/bin
java -version

当正确输出JDK和JVM版本信息说明编译成功(这里做了版本和版号的修改请读者忽略):

代码语言:javascript
复制
dioxide@DioxidedeMacBook-Pro bin % java -version  
openjdk version "17.0.7-standard" 2023-04-18  
OpenJDK Runtime Environment (build 17.0.70) (Haldir JDK.Haldir-JDK)  
OpenJDK 64-Bit Server VM (build 17.0.70) (Haldir JDK.Haldir-JDK, mixed mode)

Windows平台

准备工作

不同于Linux和macOS平台,Windows平台编译JDK源码需要安装Cygwin,同时需要注意保持环境的一致性。这使得JDK在Windows平台上的编译操作更加复杂。先安装Cygwin和相应的软件包:

  1. 在Cygwin官网下载setup-x86_64.exe程序并双击打开
Cygwin
Cygwin

2. 在下载源中选择从“互联网下载”。根目录自行选择,后面cygwin的虚拟操作系统都会在这个目录下 3. 本地软件包自行选择,并使用“系统代理设置”。在可用的下载站点中选择`https://mirrors.163.com`后等待进入“选择程序包”

Cygwin-2
Cygwin-2

4. 在“选择程序包”的查看中选择“类别”,并结合“搜索”按如下的清单进行程序包安装:

类别

软件包名

版本

描述

Devel

autoconf

15-1

Wrapper script for autoconf commands

Devel

binutils

2.40-1

GNU assembler, linker, and similar utilities

Devel, Unmaintained

clang

8.0.1-1

C/C++ compiler frontend based on LLVM

Utils

cpio

2.13-13

A backup and archiving utility

Web

lynx

2.8.9-13

A text-based Web browser

Interpreters, Text

m4

1.4.19-1

GNU implementation of the traditional Unix marco processor

Devel

make

4.4.1-2

The GNU version of 'make' utility

Devel

mingw64-x86_64-gcc-core

11.3.0-1

GCC for Win64 toolchain (C, OpenMP)

Devel

mingw64-x86_64-gcc-g++

11.3.0-1

GCC for Win64 toolchain (C++)

System

procps-ng

4.0.3-1

System and process monitoring utilities

Archive

unzip

6.0-18

Info-ZIP decompression utility

Editors

vim

8.2.4372-1

Vi IMproved - enhanced vi editor

Archive

zip

3.0-13

Info-ZIP compression utility

安装完成后打开cygwin的终端,除了通过桌面快捷方式,还可以通过以下的DOS命令来打开cygwin终端:

代码语言:javascript
复制
	@echo off
	setlocal enableextensions
	set TERM=
	cd /d "C:\cygwin64\bin" && .\bash --login -i

其中的C:\cygwin64为第二步中指定的目录位置,这个目录下存放了Cygwin.bat的启动程序也可以通过它来打开cygwin终端

在cygwin环境下通过git(需要提前安装)来克隆jdk17u的源码。或在Windows中克隆完成后复制到C:\cygwin64\home的用户目录中

如果使用的是国行的Windows系统则需要此步,否则在后期编译过程中会发生如下的错误:

代码语言:javascript
复制
	OpenJDK17:Target CPU mismatch. We are building for x86_64 but CL is for ""; expected "x64"

打开源码中的make/autoconf/toolchain.m4文件,找到字串Target CPU mismatch,将AC_MSG_ERROR改成AC_MSG_RESULT即可

通过configure文件构建预编译环境

代码语言:javascript
复制
	bash configure \
		--openjdk-target=x86_64-w64-mingw32 \
		--disable-warnings-as-errors \
		--enable-debug \
		--with-boot-jdk="/cygdrive/c/Program Files/Java/jdk-17.0.3.1"
  • --openjdk-target 定义了目标编译的JDK使用环境,这里指代的是Windows
  • --disable-warnings-as-errors 将warnings不作为errors来检查,如果不启用这项可能导致一些较老的C/C++语法出现warnings警告后被转为errors错误从而导致异常的终止环境的构建
  • --enable-debug 启用Debug模式,这会使得JDK源码中一些C/C++的debug宏被激活从而输出一些Debug信息
  • --with-boot-jdk 编译时需要的JDK,值得注意的是这个JDK必须是Windows环境中的JDK,通过cygwin的/cygdrive/c可以定位到Windows环境中的C盘目录下(为什么需要boot-jdk会在后面几期中解释)

构建编译环境的过程会花上5分钟左右,当出现如下的提示则说明构建成功(如果之前构建过环境则每次执行的构建方法都会进行覆盖)

Cygwin-build
Cygwin-build

当出现报错时检查构建步骤是否按要求进行或是否有遗漏。在回复中提供完整的报错信息可以让读者们共同为你解决问题。

当编译环境构建完成后使用make allmake images来编译JDK,这个过程会耗费20分钟到2小时不等(主要取决于CPU的性能)编译期间CPU多核的负载会达到100%是正常现象。当出现以下的结果则说明编译成功:

Cygwin-success
Cygwin-success

编译验证

至此,Windows环境下的JDK17就已经编译完成了。编译完成的Java文件被存放在了jdk17u\build\windows-x86_64-server-fastdebug\jdk中。使用如下的命令来验证这个编译完成的Java的可行性:

代码语言:javascript
复制
# 在windows环境中执行
cd C:\cygwin64\home\DioxideCN\jdk17u\build\windows-x86_64-server-fastdebug\jdk\bin
java -version

当正确输出JDK和JVM版本信息说明编译成功(这里做了版本和版号的修改请读者忽略):

代码语言:javascript
复制
openjdk version "17.0.7-standard" 2023-04-18
OpenJDK Runtime Environment (fastdebug build 17.0.70) (Haldir JDK.jdk17u)
OpenJDK 64-Bit Server VM (fastdebug build 17.0.70) (Haldir JDK.jdk17u, mixed mode)

版本控制与版号修改

在上面编译验证的结果中使用了版本修改。这些版本信息都被/src/java.base/share/classes/java/lang/VersionProps.java.template文件所使用,具体的代码如下:

代码语言:javascript
复制
private static final String launcher_name = "@@LAUNCHER_NAME@@"; 
// This field is read by HotSpot 
private static final String java_version = "@@VERSION_SHORT@@"; 
private static final String java_version_date = "@@VERSION_DATE@@"; 
public static void init(Map<String, String> props) { 
	props.put("java.version", java_version); 
	props.put("java.version.date", java_version_date); 
	props.put("java.runtime.version", java_runtime_version); 
	props.put("java.runtime.name", java_runtime_name); 
	if (!VENDOR_VERSION.isEmpty()) 
		props.put("java.vendor.version", VENDOR_VERSION); 
	props.put("java.class.version", CLASSFILE_MAJOR_MINOR); 
	props.put("java.specification.version", VERSION_SPECIFICATION); 
	props.put("java.specification.name", "Java Platform API Specification"); 
	props.put("java.specification.vendor", "Oracle Corporation"); 
	props.put("java.vendor", VENDOR); 
	props.put("java.vendor.url", VENDOR_URL); 
	props.put("java.vendor.url.bug", VENDOR_URL_BUG); 
}

这是一个模板类文件,通过@@来读取版本信息。在JDK17u的源码中这些更详细的版本号被定义在以下的文件中:

~\jdk17u\make\autoconf\jdk-version.m4

  • VERSION_OPT 字符串定义了JDK.jdk17u的信息
  • VERSION_STRING 字符串调用VERSION_OPT定义了完整的构建版本信息(fastdebug build 17.0.70) (Haldir JDK.jdk17u)
  • 修改这两个字符串以实现自定义的不同的构建版本信息VERSION_STRING="VERSION_BUILD){VERSION_OPT:+ (
  • 这个修改方法并不是推荐的,也没有详细的定义版本的资料和文章可供参考,仍需要进一步探究

~\jdk17u\make\conf\version-numbers.conf

  • 这个文件中似乎是定义了一些版号、构建日期等信息,我不推荐修改它们,但它们可能有其他的用途
代码语言:javascript
复制
	DEFAULT_VERSION_FEATURE=17 
	DEFAULT_VERSION_INTERIM=0 
	DEFAULT_VERSION_UPDATE=7 
	DEFAULT_VERSION_PATCH=0 
	DEFAULT_VERSION_EXTRA1=0 
	DEFAULT_VERSION_EXTRA2=0 
	DEFAULT_VERSION_EXTRA3=0 
	DEFAULT_VERSION_DATE=2023-04-18 
	DEFAULT_VERSION_CLASSFILE_MAJOR=61 # "`$EXPR 
	$DEFAULT_VERSION_FEATURE + 44`" 
	DEFAULT_VERSION_CLASSFILE_MINOR=0 
	DEFAULT_VERSION_DOCS_API_SINCE=11 
	DEFAULT_ACCEPTABLE_BOOT_VERSIONS="16 17" 
	DEFAULT_JDK_SOURCE_TARGET_VERSION=17 
	DEFAULT_PROMOTED_VERSION_PRE=

每次修改版本、版号信息后若需要它们生效都需要重新构建编译环境再通过make clean all来重新编译才能生效。如果不是作为发布版本或只是作为私用版本,我不推荐大费周章地去考虑版本修改问题。

参考文献

[1] Oracle. (2021). The Java® Virtual Machine Specification Java SE 17 Edition. Oracle Corporation. Retrieved May 16, 2023, from https://docs.oracle.com/javase/specs/jvms/se17/html/index.html

[2] OpenJDK. (2019). Building the JDK. Retrieved May 16, 2023, from https://github.com/openjdk/jdk17u/blob/master/doc/building.md

[3] Lindholm, T., Yellin, F., Bracha, G., & Buckley, A. (2015). The Java Virtual Machine Specification, Java SE 8 Edition (爱飞翔 & 周志明, Trans.). 机械工业出版社. (Original work published 2015)

[4] 花花子. (2020). JVM :从手动编译 JDK 开始. Retrieved May 17, 2023, from https://juejin.cn/post/6860088325307547661

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • Liunx平台
    • 准备工作
      • 编译验证
      • macOS平台
        • 准备工作
          • 编译验证
          • Windows平台
            • 准备工作
              • 编译验证
              • 版本控制与版号修改
              • 参考文献
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档