本篇文章主要介绍在MacOS
系统和Ubuntu
系统上如何编译OpenJDK
项目代码,并使用IDE
工具JetBrains CLion
(下文简称CLion
)来运行/调试OpenJDK
。
文中仅包含两种操作系统的特定版本(MacOS 10.15
和Ubuntu 16.04
)下的方法,不同版本下可能会略有差异。希望对读者有一定的参考价值。
总体来说,编译OpenJDK11
在两种系统上都没有太大的阻碍,难度低于OpenJDK8
。编译OpenJDK8
在Ubuntu
上比较简单,在MacOS
上比较繁琐复杂。
编译调试OpenJDK的基本步骤
完成编译并实现调试OpenJDK
流程可以分为以下几个步骤:
- 获取
OpenJDK
项目源代码 - 下载一个合适版本的
JDK
作为BootJDK
- 下载所需工具链,包括编译器、调试器、构建工具等
- 下载所需依赖库
Running Configure
(配置)Running Make
(构建)- 导入
CLion
并进行Run/Debug
配置
其中3-6步对于不同操作系统和不同OpenJDK
版本差异较大,其余步骤差异较小,所以本文的行文顺序是先将1-2、7三部分以及一些前置知识做详细介绍。在之后的具体场景(不同操作系统 + 不同OpenJDK
版本)中针对对这些部分只做差异点的特殊说明。
开始之前
如何获取 OpenJDK 源代码?
编译调试的第一步当然是获取到OpenJDK
的源代码,获取方式主要有以下三种:
1. 通过OpenJDK
官方的Mercurial
仓库下载
OpenJDK
官方使用Mercurial
来进行版本控制。Mercurial
仓库地址:http://hg.openjdk.java.net/,主要项目地址:
项目 | 地址 |
---|---|
jdk | http://hg.openjdk.java.net/jdk/jdk |
jdk8u | http://hg.openjdk.java.net/jdk8u/jdk8u/ |
jdk11u | https://hg.openjdk.java.net/jdk-updates/jdk11u/ |
通过这种方式下载源代码,需要先安装Mercurial
工具,并使用hg clone <url>
下载源代码。比如下载 jdk8u
使用如下命令:
1 | hg clone http://hg.openjdk.java.net/jdk8u/jdk8u/ |
这种方式下载比较慢,而且会有中断的情况,不推荐使用。
2. 通过镜像Git
仓库下载
OpenJDK官方在GitHub
上有JDK项目的仓库镜像,主页地址:https://github.com/openjdk,主要项目地址:
项目 | 地址 |
---|---|
jdk | https://github.com/openjdk/jdk |
jdk11u | https://github.com/openjdk/jdk11u |
jdk12u | https://github.com/openjdk/jdk12u |
但在官方git
仓库中没有看到 jdk11
以下的版本。
除此之外还有一些非官方的镜像Git
仓库。比如AdoptOpenJDK
项目,主页地址:https://github.com/AdoptOpenJDK/,主要项目地址:
项目 | 地址 |
---|---|
jdk | https://github.com/AdoptOpenJDK/openjdk-jdk |
jdk8u | https://github.com/AdoptOpenJDK/openjdk-jdk8u |
jdk11u | https://github.com/AdoptOpenJDK/openjdk-jdk11u |
使用这种方式需要安装git
工具,并使用git clone <url>
下载源代码。比如下载jdk8u
使用如下命令:
1 | git clone https://github.com/AdoptOpenJDK/openjdk-jdk8u |
git
工具使用方便,并且比从官方Mercurial
仓库下载要快很多,推荐使用。
3. 下载Mercurial
仓库或者Git
仓库 打包文件
除此之外,OpenJDK
官方的Mercurial
仓库还提供了直接下载压缩包的入口,入口在各个项目页面左侧bz2
,zip
,gz
三个链接,点击即可下载。如下图所示:
同样在GitHub
上的每个项目都可以下载ZIP
格式的打包文件。如下图所示:
显然这种方式的缺点是缺少版本控制的能力,如果对项目代码进行了改动想要恢复是做不到的,也不能够方便地获取最新代码改动,但是相比前两种方式更下载更快,也不要任何额外工具。
如何下载JDK?
让人觉得矛盾的是,编译JDK之前我们需要一个已经编译好的JDK
作为Boot JDK
。一般需要的JDK
版本是编译版本前一版本的JDK
,比如编译JDK8
需要JDK7
,编译JDK11
需要JDK10
。
有几种途径可以下载JDK
:
- 在Oracle官网下载
Oracle JDK
。下载需要登录账号 - 下载
OpenJDK
- 在https://jdk.java.net/可以找到
Oracle
提供的基于OpenJDK
的参考实现。但大部分只有Linux
版本 - 也可以使用其他组织预编译好的
OpenJDK
。比如AdoptOpenJDK,但是没有jdk8
以下版本
- 在https://jdk.java.net/可以找到
- 在
Linux
系统下,还可以通过软件包管理器(比如Ubuntu
下的apt
,Centos
下的yum
)下载安装JDK
JSON Compilation Database
CLion
对CMake
构建的项目支持很友好,但OpenJDK
项目是基于Make
构建的,对于使用Make
构建的项目,CLion
仍然可以通过Compilation Database
来导入项目,而不用将其修改为CMake
项目。同时也能通过Compilation Database
实现代码的分析、跳转等功能,这对于我们进行代码调试很有帮助。
有关于Compilation Database
的介绍可以参考这几篇文章:
Clang
官方的Compilation Database
介绍页面:JSON Compilation Database Format Specification — Clang 11 documentation- 这篇文章介绍了在不同场景下生成
Compilation database
的各种工具:Compilation database — Sarcasm notebook CLion
的帮助页面简要介绍了Compilation Database
,以及在CLion
的使用:Compilation Database - Help | CLion
对于基于Make
构建的OpenJDK
项目来说,有一些工具可以生成Compilation Database
,比如下面几个:
- https://github.com/rizsotto/Bear
- https://github.com/rizsotto/scan-build
- https://github.com/nickdiego/compiledb
通常默认生成的Compilation Database
是一个compile_commands.json
文件。
除此之外,在OpenJDK 11u
及之后版本中,OpenJDK
官方提供了对于IDE
的支持,可以使用make compile-commands
命令生成Compilation Database
,不需要使用额外的工具,具体命令可以查看看源代码目录下的\doc\ide.md
如何将OpenJDK项目导入CLion中并运行/调试
读者可以选择先跳过本小节,然后在完成前面几个步骤之后再来根据本小节进行导入调试。
对于如何在CLion
中管理基于Make
构建的项目,CLion
的官方帮助文档中有详细的介绍:
Managing Makefile Projects。
参考上述文档,本小节简要介绍了如何在CLion
中导入OpenJDK
项目并运行/调试的方法。请注意小节中所展示的图示是基于Ubuntu 16.04
系统 + CLion 2020.1.1
环境下的,操作步骤基本也适用于MacOS 系统
下同版本的CLion
。
下载安装
CLion
,并安装Makefile Support
插件。建议使用最新版本,比较老的版本是不支持Make
构建的项目的。导入项目。打开
CLion
,选择Open Or Import
,选择项目目录中的compile_commands.json
文件,弹出框选择Open as Project
,等待文件索引完成。compile_commands.json
的生成方法及生成位置根据不同的OpenJDK
版本略有不同,具体位置请看下文具体场景的介绍。创建自定义
Build Target
。点击File
菜单栏,Settings | Build, Execution, Deployment | Custom Build Targets
,点击+
新建一个Target
。Name
:Target
的名字,之后在创建Run/Debug
配置的时候会看到这个名字点击
Build
或者Clean
右边的三点,弹出框中点击+
新建两个External Tool
配置如下:1
2
3
4
5
6
7
8
9
10
11
12
13# 第一个配置如下,用来指定构建指令
# Program 和 Arguments 共同构成了所要执行的命令 "make all"
Name: make
Program: make
Arguments: all
Working directory: {项目的根目录}
# 第二个配置如下,用来清理构建输出
# Program 和 Arguments 共同构成了所要执行的命令 "make clean"
Name: make clean
Program: make
Arguments: clean
Working directory: {项目的根目录}ToolChain
选择Default
;Build
选择make
(上面创建的第一个External Tool
);Clean
选择make clean
(上面创建的第二个External Tool
)其中两个
External Tool
配置中make
的参数可以根据需要改变。一般情况用于Build
的配置与执行构建时make
的target
保持一致即可。
创建自定义的
Run/Debug configuration
。点击Run
菜单栏,Edit Configurations
, 点击+
,选择Custom Build Application
,配置如下:1
2
3
4
5
6
7
8
9# Executable 和 Program arguments 可以根据需要调试的信息自行选择
# NameL:Configure 的名称
Name: linux-x86_64-normal-server-slowdebug
# Target:选择上一步创建的 “Custom Build Target”
Target: linux-x86_64-normal-server-slowdebug
# Executable:程序执行入口,也就是需要调试的程序
Executable: 这里我们调试`java`,选择`{source_root}/build/{build_name}/jdk/bin/java`。
# Program arguments: 与 “Executable” 配合使用,指定其参数
Program arguments: 这里我们选择`-version`,简单打印一下`java`版本。如果不想每次运行/调试前都执行
Build
操作(在这里就是Make
构建过程,比较耗时),可以在编辑页下方Before launch
框中删除Build
条目。点击
Run
/Debug
开始运行/调试。- 如果使用的调试器是
gdb
(Ubuntu
下默认),调试的时候可能会发现gdb
报错:Signal: SIGSEGV (Segmentation fault)
。解决办法是,创建用户家目录创建.gdbinit
,内容如下:1
2handle SIGSEGV pass noprint nostop
handle SIGBUS pass noprint nostop - 如果使用的调试器是
lldb
(MacOS
下默认),调试的时候可能会发现lldb
报错:SIGSEGV (signal SIGSEGV)
。解决办法是,在用户家目录创建.lldbinit
,内容如下:1
break set -n main -C "process handle --pass true --stop false SIGSEGV" -C "process handle --pass true --stop false SIGBUS"
- 如果使用的调试器是
配合
File Watchers
插件自动更新Compilation Database
(可选)如果修改了项目代码,需要重新生成
Compilation Database
,一般情况需要重新构建才可以。如果不想每次都重新手动构建,可以使用
Files Watcher
插件来实现监听变更自动重新生成。详见:https://www.jetbrains.com/help/clion/managing-makefile-projects.html#filewatcher-plugin
Ubuntu 16.04 环境
OpenJDK 8
1. 下载OpenJDK8源代码
我们这里选择从AdoptOpenJDK
的GitHub
仓库下载源代码。
1 | # 首先需要安装git工具(如果没有的话) |
2. 安装工具链及依赖
1 | # 首先需要下载安装 JDK7 作为 BootJDK |
3. 配置及构建
1 | # 首先进入 OpenJDK8 源码目录 |
configure
参数说明:
参数 | 含义 |
---|---|
–with-debug-level | 调试信息的级别,可选值有release ,fastdebug ,slowdebug |
–disable-zip-debug-info | 禁止压缩调试信息,设置为true有助于调试 |
–with-target-bits | 选择32位或者64位,根据操作系统选择 |
–with-boot-jdk | BootJDK 的位置 |
–with-freetype-include –with-freetype-lib |
指定freetype 依赖位置,如果提示找不到freetype ,需要配置这两个参数 |
参数的更多说明及更多参数请参考:OpenJDK 8 Build README - Configure
我们可以使用两种工具来生成Compilation Database
使用Bear工具
1 | # 下载Bear工具 |
使用compiledb工具
1 | # 需要保证有python环境 |
更多make
的target
请参考OpenJDK 8 Build README - Make
如果没有报错,完成之后应该可以在./build/linux-x86_64-normal-server-slowdebug/jdk
目录下找到编译之后的JDK
,验证一下是否成功
1 | ~: cd build/linux-x86_64-normal-server-slowdebug/jdk/bin/ |
同时项目根目录下应该同时有一个compile_commands.json
文件,并且不为空。
4. 导入CLion并调试
步骤参见上文
OpenJDK 11
1. 下载OpenJDK11源代码
1 | # 首先需要安装git工具(如果没有的话) |
2. 安装工具链及依赖
1 | # 需要下载安装 JDK10 作为 BootJDK |
3. 配置及构建
1 | # 配置 |
如果不成功,一般可能是缺少部分依赖,根据脚本给出的提示安装相应依赖即可。
configure
参数说明:
参数 | 含义 |
---|---|
–with-debug-level | 调试信息的级别,可选值有release ,fastdebug ,slowdebug |
–with-native-debug-symbols | 指定如何构建debug symbol ,可选值有none ,internal , external , zipped ,设置为internal 可以更好地调试 |
–with-target-bits | 选择32位或者64位,根据操作系统选择 |
–with-boot-jdk | bootjdk 位置 |
–with-freetype-include –with-freetype-lib |
指定freetype 依赖位置。如果提示找不到freetype ,需要配置这两个参数 |
参数的更多说明及更多参数请参考:OpenJDK 11 Build README - Configure
1 | # 生成Compilation Database |
更多make
的target
请参考OpenJDK 11 Build README - Make
完成之后应该可以在./build/linux-x86_64-normal-server-slowdebug/jdk
目录下找到编译之后的jdk,验证一下是否成功
1 | ~: cd build/linux-x86_64-normal-server-slowdebug/jdk/bin/ |
同时在/build/linux-x86_64-normal-server-slowdebug/
目录下会有compile_commands.json
文件,并且不为空。
4. 导入CLion并调试
大致步骤与前文介绍相同。
需要注意的是在选择/build/linux-x86_64-normal-server-slowdebug/
目录下的compile_commands.json
文件导入项目之后需要更改项目的根目录为源码的根目录
(这里也就是openjdk-11u
目录)。点击菜单Tools | Compilation Database | Change Project Root
,选择源码根目录
(openjdk-11u
),等待重新索引完成。
MacOS 10.15 环境
OpenJDK 8
MacOS 10.15.5
环境下构建OpenJDK
与Linux
下步骤相似,但是由于OpenJDK 8
版本较老,其中一些依赖在MacOS 10.15.5
版本中已经无法找到,导致在配置构建过程中会出现各种问题,本文给出了一种比较简单方便的办法。
1. 下载OpenJDK8源代码
我们选择从AdoptOpenJDK
的github
仓库下载源代码
1 | git clone git@github.com:AdoptOpenJDK/openjdk-jdk8u.git |
2. 安装工具链及依赖
- 首先需要下载安装
jdk7
作为bootjdk
,方法见文章开头。 - 安装
HomeBrew
。Homebrew
是一款MacOS
系统上的软件包管理系统。1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
- 安装
Xcode
。可以直接在App Store
搜索安装,也可以在https://developer.apple.com/download/more/下载离线安装包安装。可以使用xcodebuild
命令验证是否安装成功,正确输出版本号则表明正确安装。如果是离线安装的话,可能会报1
xcodebuild -version
xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance
错误,这是因为xcodebuild
找不到新安装的Xcode
,只需要执行下面这个命令即可。1
2
3
4
5
6sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/
```
4. 安装编译工具
```bash
# 安装构建工具
brew install make - 安装所需依赖
1
2# 安装freetype
brew install freetype
3. 配置及构建
3.1 修改代码
如果不对代码进行修改,在执行configure
的时候,会报各种错误。网上也有很多针对每种错误来修改源文件来解决报错的方法, 这里给出一种更为方便的方法。GitHub
上的stooke/jdk8u-xcode10这个项目,提供了对openjdk8
的代码进行修改的patch
文件,对代码修改之后,就可以正常地configure
。
1 | git clone git@github.com:stooke/jdk8u-xcode10.git |
这个项目本身提供了脚本来完成下载源码、下载依赖、代码修改、配置、编译、测试等工作,但我们这里只使用其中的修改代码这部分。原项目中的README
可能已经过时了,通过查看其源代码中的build8.sh
文件,能够大概了解其中的执行逻辑,据此我将其中的修改OpenJDK8
代码的部分抽取出来,简化如下:
新建一个shell
脚本patch.sh
,内容如下:
1 |
|
然后执行这个脚本:
1 | bash patsh.sh |
3.2 配置
1 | sh ./configure MAKE=/usr/bin/make --with-toolchain-type=clang --with-debug-level=slowdebug --disable-zip-debug-info --with-target-bits=64 --with-boot-jdk=/Users/jiajiawang/Software/jdk/jdk1.7.0_80.jdk/Contents/Home/ --with-freetype-include=/usr/local/Cellar/freetype/2.10.2/include/freetype2 --with-freetype-lib=/usr/local/Cellar/freetype/2.10.2/lib/ |
MAKE=/usr/bin/make
是可选的,如果下文使用Bear
来生成Compilation Database
,可以不加这个参数。
configure
部分参数说明如下:
参数 | 含义 |
---|---|
–with-toolchain-type | 使用的工具链类型,取值有gcc ,clang 等,可以使用--help 来查看所有可选值 |
–with-debug-level | 调试信息的级别,可选值有release ,fastdebug ,slowdebug |
–disable-zip-debug-info | 禁止压缩调试信息,设置为true可以更好地调试 |
–with-target-bits | 选择32位或者64位,根据操作系统选择 |
–with-boot-jdk | bootjdk 位置 |
–with-freetype-include –with-freetype-lib |
指定freetype 依赖位置,在执行configure 时如果找不到freetype ,需要指定这两个参数 |
参数的更多说明及更多参数请参考:OpenJDK 8 Build README - Configure
3.3 构建
同样我们仍然可以使用bear
或者compiledb
来生成Compilation Database
,但是使用bear
过程中遇到一些问题比较繁琐,推荐使用compiledb
。
使用compiledb
1 | # 1. 请先确保安装了Python及pip |
使用compiledb
可能会存在的问题是生成的compile_commands.json
文件中所有项的directory
项都是项目的根目录,导致一个头文件无法找到,导入CLion
时报错,代码定义及跳转无效。原因是在MacOS
平台,编译构建使用的可能是gmake
,而compiledb
对gmake
切换路径的操作无法捕捉到,导致路径全部都是根目录。解决办法就是显示指定使用make
而不是gmake
,指定方法就是上一小节中在Configure
时指定的MAKE=/usr/bin/make
参数。
使用bear
上面我们使用compiledb
工具来生成Compilation Database
,同样也可以使用bear
工具来生成:
1 | # 1. 首先需要关闭SIP,否则生成的 Compilation Database 可能会是空的 |
如果遇到执行命令遇到报错/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/stdio.h:107:15: fatal error: 'stdio.h' file not found
可以尝试执行如下命令:
1 | sudo mount -uw / |
更多make
的target
请参考OpenJDK 8 Build README - Make
如果没有报错,完成之后应该可以在./build/macosx-x86_64-normal-server-slowdebug/jdk
目录下找到编译之后的JDK
,验证一下是否成功
1 | ~: cd build/macosx-x86_64-normal-server-slowdebug/jdk/bin/ |
同时项目根目录下应该同时有一个compile_commands.json
文件,并且不为空。
4. 导入CLion并调试
需要注意在创建Custom Build Targets
时,新建的用于Build
的External Tool
中make
的参数中也要加上COMPILER_WARNINGS_FATAL=false
OpenJDK 11
1. 下载OpenJDK11源代码
1 | git clone git@github.com:AdoptOpenJDK/openjdk-jdk11u.git |
2. 安装工具链及依赖
首先需要下载安装
jdk10
作为bootjdk
,方法见文章开头。安装
HomeBrew
。Homebrew
是一款MacOS
系统上的软件包管理系统。1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
安装
Xcode
。可以直接在App Store
搜索Xcode
安装,也可以在https://developer.apple.com/download/more/下载离线安装包安装。可以使用xcodebuild
命令验证是否安装成功,正确输出版本号则表明正确安装。1
xcodebuild -version
如果是离线安装的话,可能会报
xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance
错误,这是因为xcodebuild
找不到新安装的Xcode
,只需要执行下面这个命令即可。1
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/
安装编译工具
1
2brew install autoconf
brew install make安装所需依赖
1
2# 安装freetype
brew install freetype3. 配置及编译
1
2# 配置
sh ./configure --with-debug-level=slowdebug --with-native-debug-symbols=internal --with-target-bits=64 --with-boot-jdk=/Users/jiajiawang/Software/jdk/jdk-10.0.2+13/Contents/Homeconfigure
参数说明:
参数 | 含义 |
---|---|
–with-debug-level | 调试信息的级别,可选值有release ,fastdebug ,slowdebug |
–with-native-debug-symbols | 指定如何构建debug symbol ,可选值有none ,internal , external , zipped ,设置为internal 可以更好地调试 |
–with-target-bits | 选择32位或者64位,根据操作系统选择 |
–with-boot-jdk | bootjdk 位置 |
–with-freetype-include –with-freetype-lib |
指定freetype 依赖位置,在执行configure 时如果找不到freetype ,需要指定这两个参数 |
参数的更多说明及更多参数请参考:OpenJDK 11 Build README - Configure
1 | # 生成Compilation Database |
完成之后,应该在/build/linux-x86_64-normal-server-slowdebug/
目录下会有compile_commands.json
文件。
更多make
的target
请参考OpenJDK 11 Build README - Make
完成之后应该可以在./build/macosx-x86_64-normal-server-slowdebug/jdk
目录下找到编译之后的jdk,验证一下是否成功
1 | ~: cd build/macosx-x86_64-normal-server-slowdebug/jdk/bin/ |
同时在./build/macosx-x86_64-normal-server-slowdebug/
目录下会有compile_commands.json
文件,并且不为空。
4. 导入CLion并调试
大致步骤与前文介绍相同。
需要注意的是在选择/build/macosx-x86_64-normal-server-slowdebug/
目录下的compile_commands.json
文件导入项目之后需要更改项目的根目录为源码的根目录
(这里也就是openjdk-11u
目录)。点击菜单Tools | Compilation Database | Change Project Root
,将项目的根目录设置为源码根目录
(openjdk-11u
),等待重新索引完成。
参考
- OpenJDK
- OpenJDK 8 Build README
- OpenJDK 11 Build README
- rizsotto/Bear: Bear is a tool that generates a compilation database for clang tooling
- nickdiego/compiledb: Tool for generating Clang’s JSON Compilation Database files for make-based build systems.
- Managing Makefile Projects
- Dealing with Makefile Projects in CLion: Status Update
- Tips & Tricks: Develop OpenJDK in CLion with Pleasure
- Debugging OpenJDK - DZone DevOps
- Compilation database — Sarcasm notebook
- More Software Downloads - Apple Developer
- stooke/jdk8u-xcode10: How to compile JDK 8u with Xcode 9, 10 or 11 on macOS.