JDK 构建、调试环境#

本书的操作环境如下:

  • 操作系统: Ubuntu 22.04.4 LTS (kernel: 6.8.0-40-generic)

  • CPU Arch: x86_64 (Intel(R) Xeon(R) CPU E3-1225 v5)

Git repo#

cd /home/labile/opensource/
git clone https://github.com/openjdk/jdk/
git checkout tags/jdk-21+35 -b jdk-21+35

以下假设 JDK 源码绝对路径为: /home/labile/opensource/jdk

构建 OpenJDK#

参考:https://openjdk.org/groups/build/doc/building.html

构建的依赖#

sudo apt install openjdk-21-jdk
sudo apt-get install libasound2-dev
sudo apt-get install libcups2-dev
sudo apt-get install libfontconfig1-dev

构建过程要用到 Java。好奇的人会思考这是个鸡生蛋蛋生鸡的问题。

其实构建依赖的 Java 的版本,一般是允许比构建的目标版本低的。所以好像问题解决了。

构建配置#

hsdis 工具分析 JVM 编译生成的代码(可选)#

如需要分析 JVM 编译生成的代码,可以通过 -XX:+PrintAssembly java 参数让 JVM 以汇编为格式,输出 JIT 编译后的程序到日志文件。使用说明见: https://wiki.openjdk.org/display/HotSpot/PrintAssembly 。 -XX:+PrintAssembly 基于 hsdis 技术,需要 jdk 在构建期就支持 hsdis。 另外,其实 JDK 自带的 jhsdb 也可以实时反编译 JIT 生成的机器指令。所以 hsdis 有时不是必须的。但如果你希望得到注释比较丰富(如函数 call 地址后显示函数名),可读性高,可用 jitwatch GUI 分析的汇编代码,那么支持 hsdis 是必须的。

因为会使用 hsdis 工具分析 JVM 内部数据,所以 ./configure 要加上 --enable-hsdis-bundling  --with-hsdis=binutils --with-binutils-src=/home/labile/opensource/jdk/external-libs/binutils/binutils-2.37

参数 --enable-hsdis-bundling 让 JDK 内置 hsdis 实现,就不需要后面自己 copy .so 文件了。参考:

  • https://mail.openjdk.org/pipermail/core-libs-dev/2022-February/086176.html

  • https://git.openjdk.java.net/jdk/pull/7578

由于 license 问题,要自己下载 binutils 源码:

mkdir /home/labile/opensource/jdk/external-libs/
cd /home/labile/opensource/jdk/external-libs/
curl -L -O https://ftp.gnu.org/gnu/binutils/binutils-2.37.tar.gz
tar -xvf binutils-2.37.tar.gz

configure jdk build#

bash ./configure --with-debug-level=slowdebug --with-native-debug-symbols=internal --with-jvm-variants=server --with-target-bits=64 --enable-hsdis-bundling  --with-hsdis=binutils --with-binutils-src=/home/labile/opensource/jdk/external-libs/binutils/binutils-2.37 --with-conf-name=linux-x86_64-server-slowdebug-hsdis

--with-debug-level 的定义如下:

See the definition here:

###############################################################################
# Set the debug level
#    release: no debug information, all optimizations, no asserts.
#    optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
#    fastdebug: debug information (-g), all optimizations, all asserts
#    slowdebug: debug information (-g), no optimizations, all asserts
AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL],

同一个 JDK git work dir 支持使用多个 build profile(conf-name) 配置,来让测试者可以快速切换。用 --with-conf-name= 指定 conf-name(配置名)。

输出:

====================================================
A new configuration has been successfully created in
/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis
using configure arguments '...'.

Configuration summary:
* Name:           linux-x86_64-server-slowdebug-hsdis
* Debug level:    slowdebug
* HS debug level: debug
* JVM variants:   server
* JVM features:   server: 'cds compiler1 compiler2 epsilongc g1gc jfr jni-check jvmci jvmti management parallelgc serialgc services shenandoahgc vm-structs zgc' 
* OpenJDK target: OS: linux, CPU architecture: x86, address length: 64
* Version string: 21-internal-adhoc.labile.jdk (21-internal)
* Source date:    1723623824 (2024-08-14T08:23:44Z)

Tools summary:
* Boot JDK:       openjdk version "21.0.4" 2024-07-16 OpenJDK Runtime Environment (build 21.0.4+7-Ubuntu-1ubuntu222.04) OpenJDK 64-Bit Server VM (build 21.0.4+7-Ubuntu-1ubuntu222.04, mixed mode, sharing) (at /usr/lib/jvm/java-21-openjdk-amd64)
* Toolchain:      gcc (GNU Compiler Collection)
* C Compiler:     Version 11.4.0 (at /usr/bin/gcc)
* C++ Compiler:   Version 11.4.0 (at /usr/bin/g++)

由于 jdk 支持多配置 build profile 并存,配置 profile 在 jdk 中正式名是 Configuration NameCONF_NAME

从上面输出可见,CONF_NAME 命名为: linux-x86_64-server-slowdebug-hsdis

这个名字也会在目录中看到:`./build/linux-x86_64-server-slowdebug-hsdis

构建#

cd /home/labile/opensource/jdk
/usr/bin/gmake CONF_NAME=linux-x86_64-server-slowdebug-hsdis LOG=info,cmdlines jdk

测试构建结果#

./build/linux-x86_64-server-slowdebug-hsdis/jdk/bin/java 

IDE#

很多高手都不用 GUI ,用 vim 等等。但我还不是高手,所以我用 VSCode 来帮助我浏览代码与调试代码。其实 OpenJDK 源码库中,已经有如何使用 VSCode 的说明:IDE support in the JDK

make vscode-project CONF=linux-x86_64-server-slowdebug

这个命令生成了:

./build/linux-x86_64-server-slowdebug-hsdis/jdk.code-workspace

这个 VSCode worksplace 配置文件。其内容大体如下:

{
	"folders": [
		{
			"name": "Source root",
			"path": "/home/labile/opensource/jdk"
		},
		{
			"name": "Build artifacts",
			"path": "/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis
		}
	],
	"extensions": {
		"recommendations": [
			"ms-vscode.cpptools"
		]
	},
	"settings": {
		// Configure cpptools IntelliSense
		"C_Cpp.intelliSenseCachePath": "/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis.vscode",
		"C_Cpp.default.compileCommands": "/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis/compile_commands.json",
		"C_Cpp.default.cppStandard": "c++14",
		"C_Cpp.default.compilerPath": "/usr/bin/g++ ",

		// Additional conventions
		"files.associations": {
			"*.gmk": "makefile"
		},

		// Having these enabled slow down task execution
		"typescript.tsc.autoDetect": "off",
		"gulp.autoDetect": "off",
		"npm.autoDetect": "off",
		"grunt.autoDetect": "off",
		"jake.autoDetect": "off",

		// Certain types of files are not relevant for the file browser
		"files.exclude": {
			"**/.git": true,
			"**/.hg": true,
			"**/.DS_Store": true,
		},

		// Files that may be interesting to browse manually, but avoided during searches
		"search.exclude": {
			"**/*.class": true,
			"**/*.jsa": true,
			"**/*.vardeps": true,
			"**/*.o": true,
			"**/*.obj": true,
			"**/*.d": true,
			"**/*.d.*": true,
			"**/*_batch*": true,
			"**/*.marker": true,
			"**/compile-commands/": true,
			"**/objs": true,
			"**/launcher-objs": true,
			"**/*.cmdline": true,
			"**/*.log": true,
			".vscode": true,
			".clangd": true
		},

		// Trailing whitespace should never be used in this project
		"files.trimTrailingWhitespace": true,
		"java.project.sourcePaths": [
			"src/java.base/linux/classes",
			"src/java.base/share/classes"
		],
		"makefile.configureOnOpen": false,
		"debug.disassemblyView.showSourceCode": true
	}
}

其中 "C_Cpp.default.compileCommands": "/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis/compile_commands.json"下面将会提到。

然后用 vscode 重新打开这个文件:

To use ./build/linux-x86_64-server-slowdebug-hsdis/jdk.code-workspace, choose File -> Open Workspace... in Visual Studio Code。

编译数据库#

编译数据库(Compilation Database) 可以让 IDE 知道跨文件和目录的代码之间的关系。用这个关系就可以方便地在 IDE 实现代码跳转功能。

make compile-commands CONF=linux-x86_64-server-slowdebug-hsdis

这会生成 ./build/linux-x86_64-server-slowdebug-hsdis/compile_commands.json 文件。下面是其中一行采样内容:

{ "directory": "/home/labile/opensource/jdk/make", "file": "/home/labile/opensource/jdk/src/java.management/share/native/libmanagement/MemoryManagerImpl.c", "command": "/usr/bin/gcc -I/home/labile/opensource/jdk/build/support/modules_include/java.base -I/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis/support/modules_include/java.base/linux -I/home/labile/opensource/jdk/src/java.base/share/native/libjava -I/home/labile/opensource/jdk/src/java.base/unix/native/libjava -I/home/labile/opensource/jdk/src/hotspot/share/include -I/home/labile/opensource/jdk/src/hotspot/os/posix/include -pipe -fstack-protector -DLIBC=gnu -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DLINUX -DDEBUG -fstack-protector-all --param ssp-buffer-size=1 -g -gdwarf-4 -std=c11 -fno-strict-aliasing -Wall -Wextra -Wformat=2 -Wpointer-arith -Wsign-compare -Wunused-function -Wundef -Wunused-value -Wreturn-type -Wtrampolines -m64 -D_LITTLE_ENDIAN -DARCH='\"amd64\"' -Damd64 -D_LP64=1 -fno-omit-frame-pointer -fno-delete-null-pointer-checks -fno-lifetime-dse -fPIC -fvisibility=hidden -I/home/labile/opensource/jdk/src/java.management/share/native/libmanagement -I/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis/support/headers/java.management -g -gdwarf-4 -Wno-unused-parameter -Wno-unused -Werror -O0 -c -o /home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis/support/native/java.management/libmanagement/MemoryManagerImpl.o /home/labile/opensource/jdk/src/java.management/share/native/libmanagement/MemoryManagerImpl.c -frandom-seed=\"MemoryManagerImpl.c\"" },

VSCode 的 clangd 插件,用到分析这个文件。