
3.2 GraalVM编译系统工具mx
因为项目本身的复杂性和定制化程度较高,GraalVM项目组并没有使用诸如Ant、Maven、Gradle等现有的主流Java编译系统,而使用自己基于Python开发的命令行编译系统工具mx[1]。
mx是一个通用的编译工具链,可以支持对任意Java项目的编译、测试、运行和升级。mx以套件(suite)的形式组织代码,在GraalVM中一个子项目就是一个套件,套件又由若干个项目(在Intellij中被视为模块)组成。一个套件的基本目录组织结构如代码清单3-1所示。
代码清单3-1 mx套件目录组织结构
[suite] ├── mx.[suite] │ ├── mx_[suite].py │ └── suite.py └── src └── [project.name] └── src └── [package.name] └── Code.java
代码清单3-1中的[suite]指套件名,用于指代实际的项目名。在[suite]根目录下的mx.[suite]目录中放置套件的配置文件,我们将其称为套件元数据目录。该目录中的suite.py文件定义了套件的组成内容,包括项目名称、版本信息、子项目构成以及第三方依赖等具体内容,类似于Maven中pom.xml文件的作用,其基本结构为:
suite={ "mxversion":, "name":, "version":, "release":, "url":, "groupId":, "developer":{}, "scm": "defaultLicense":, "versionConflictResolution":, "javac.lint.overrides":, "imports":{}, "libraries":{}, "projects":{}, "distributions":{}, }
以上各项配置属性说明如下。
1)mxversion指当前套件依赖的mx工具的版本。
2)name指套件名,与当前套件所在的mx.[suite]目录中的[suite]保持一致。
3)version指项目的版本号。
4)imports指当前套件依赖的其他套件。
5)libraries指当前套件依赖的外部类库,需要给出它们的下载地址和校验的SHA值。
6)projects指套件包含的项目(模块),这是套件最重要的一部分内容,定义了项目的组成内容。其中由若干个项目的定义组成。下边展示的就是substratevm套件定义中的一个项目:
"com.oracle.svm.util": { "subDir": "src", "sourceDirs": ["src"], "dependencies": [ "sdk:GRAAL_SDK", "compiler:GRAAL", ], "javaCompliance": "8+", "annotationProcessors": [ "compiler:GRAAL_PROCESSOR", ], "checkstyle": "com.oracle.svm.core", "workingSets": "SVM", },
对上述代码的主要内容说明如下。
① subDir指项目的目录对于套件根目录的相对地址,sourceDirs指项目的源码对于项目目录的相对地址。结合先前提到的套件的目录体系,[suite]/[subDir]/com.oracle.svm.util/[sourceDirs]/就是该项目的源码位置,代入实际的例子就是substratevm/src/com.oracle.svm.util/src/,也就是代码清单3-1中的src部分的结构。
② dependencies指当前项目依赖的内容。本例中形如sdk:GRAAL_SDK结构的值是指另一个套件sdk中的GRAAL_SDK产物(jar包),也可以是当前套件的其他项目,只需要直接写项目全名即可。
7)distributions指从当前套件的源码要编译出哪些jar包。
另一个Python文件mx_[suite].py定义了套件的编译过程,与suite.py共同定义了套件是什么,怎么编译的问题。图3-2展示了Substrate VM项目套件的元数据目录mx.substratevm,里面的mx_substratevm.py文件定义了编译Substrate VM的过程,suite.py定义了Substrate VM项目的具体组成结构、依赖的库文件等。

图3-2 substratevm目录结构
执行mx任务要指定一个主套件作为工作的入口,默认以当前目录为主套件,从当前目录里寻找套件元数据目录,当然也可以在其他任意位置通过mx的-p参数指定主套件的目录。mx的功能非常强大,是GraalVM开发者日常工作的必需品,对学习者来说,在基本了解mx的组织形式后,通常会在以下4个场景中用到mx。
1)为GraalVM项目生成IDE配置文件,以便在自己习惯的IDE中查看、编辑GraalVM代码,这部分内容会在3.3节介绍。
2)将GraalVM源码编译为成品,这是日常使用最多的方式,会在4.1.2节介绍。
3)作为持续集成工具执行代码规范检查和单元测试等操作。比如mx checkstyle可以启动checkstyle工具检查源码规范,mx eclipseformat可以自动按照Eclipse格式整理代码,mx gate则会启动CI测试。
4)项目升级。GraalVM项目的演进速度很快,项目主体升级后也往往需要更新的mx工具支持。如果mx工具不符合当前GraalVM项目的最低版本要求,在使用mx时会被提示需要对mx工具进行升级。一般只需执行mx update即可进行升级,但是如果用户修改过mx工具的代码,就需要按Git项目的管理方式更新项目。
其他mx功能不再一一介绍,读者可以通过执行mx help命令查看。