使用 Gradle ABI实现编译规避? | Foojay

22-12-15 banq

这篇文章解释了基于 ABI 的编译对一般工作流程意味着什么。剧透:利用编译避免是任何构建的最佳性能增强之一。

什么是应用程序二进制接口?
应用程序二进制接口 (ABI) 是编译软件生成的定义内部和外部交互的接口。ABI 表示消费者在编译时可见的内容。
编译项目时,其任何依赖项的 ABI 中是否存在更改决定了编译是否是最新的或是否需要重新编译。
这些 ABI 包含有关消费者项目可见的依赖项的所有公共信息,例如:

  • 任何具有参数类型和返回语句的公共方法
  • 任何公共属性和字段
  • 用于针对 ABI 进行编译的任何依赖项。

当一个人访问源代码中的库时,他们会使用该库的 API。当机器访问已编译的二进制文件时,它会使用 ABI。

为什么 ABI 与构建性能相关?
现代构建系统在编译代码时会考虑 ABI 兼容性,以避免在编译对代码库的增量更改时尽可能多地进行编译。
对内部实现细节的更改是ABI 兼容的:它们不会更改公共接口。在实践中,项目的内部实现细节比公共组件更频繁地发生变化。
当公开信息没有变化时,任何下游项目都不需要重新编译。跳过这些额外的工作会对大型项目的构建性能产生巨大影响,无论是在本地还是在 CI 上。
对公共接口的更改是 ABI 不兼容的,因为它们更改了公共接口。ABI 不兼容的更改需要重新编译所有下游依赖项。必须重新编译 ABI 不兼容更改下游的所有依赖项会大大增加构建时间。

什么是编译规避?
当发生与 ABI 兼容的更改时,Gradle 会优化构建。我们称这种优化编译规避或避免
要了解其工作原理,请想象两个项目。:app取决于:lib. 以下是我们通常可以做的一些与:libABI 兼容并且不会导致:app(或任何依赖于:app)需要重新编译的事情:

  • 对方法体进行任何更改
  • 添加、删除或更改私有方法、字段或内部类
  • 重命名参数
  • 更改评论
  • 更改类路径中的 jar 或目录的名称
  • 添加、删除或更改资源

当 ABI 兼容的更改发生在 中:lib,并且运行依赖于其类的“:app”中的任务时,Gradle 不会重新编译项目:app或任何依赖于:app. 在大型多项目构建中,这可以节省大量时间。

规避编译与增量编译有何不同?
并非所有更改都符合上述要求。在某些情况下,您将需要更改 的公共 ABI :lib,这会导致需要编译:app. 幸运的是,使用了另一个称为增量编译的开箱即用功能。这将智能地重新编译:lib其中有更改的类,因此下游:app仍然比完整编译更快地编译。
增量编译与避免编译不同,但却是互补的。

“规避/避免编译”是指避免为给定项目完全调用编译器。

另一方面,“增量编译”确实意味着调用编译器,但是在这样做时试图减少需要重新编译的代码量。这是通过跟踪类之间的引用作为正常编译的一部分来促进的,并且只重新编译受给定更改影响的事物。

  • 通过增量编译,我们查看与查看项目的编译避免相比发生变化的所有类。
  • 编译避免在依赖项目中起作用,而不仅仅是在像增量编译这样的项目内部。也就是说,增量编译优化了项目中各个类的编译。
  • 增量编译发生在单个项目中,但编译避免着眼于多个项目之间的关系。增量编译仍然可以跨项目节省时间,因为它减少了需要重新编译的数量。


我是在使用增量编译还是避免编译?
总之,如果您进行 ABI 兼容的更改,那么您正在使用增量编译和编译避免:在您进行更改的源上对编译任务进行增量编译,并对下游项目进行编译避免。
或者,如果您的更改与 ABI 不兼容,则您只能从增量编译中受益。

ABI JAR 怎么样?
一些构建系统生成 ABI JAR 以实现编译避免。有时称为标头 JAR,它们具有没有内部细节的整体接口。
ABI JAR 仅包含公共方法、字段、常量和嵌套类型,删除了所有方法体,可用于评估是否有任何更改表明需要重新编译。
使用 Gradle,我们不需要 ABI JAR,因为当有编译器任务时,我们对其输入进行规范化并生成 ABI 的唯一哈希值。Gradle 然后使用此散列来检查是否有任何更改。

不同语言的注释
Groovy 有一个可选的实验特性
Kotlin 具有由JetBrains作为Kotlin Gradle 插件的一部分开发的[url=https://kotlinlang.org/docs/gradle-compilation-and-caches.htmla-new-approach-to-incremental-compilation]实验性功能[/url]。

我该如何使用它?
Gradle 自动使用避免编译。多年来,在使用 Gradle 构建的 Java 项目中默认启用了增量编译和避免编译。因此,下次您害怕在编辑后重新编译代码时,请放心,Gradle 会自动为您提供性能提升。