-
tl;dr版本:有没有一种方法可以告诉ant/maven/gradle跟踪文件依赖关系,只重建过时的文件,即比依赖关系旧的文件?
-
下面的长版本:
我是如何在信用证中做到的++
我为C/C++使用make
很多年了。虽然它有时可能很麻烦,但它至少对我来说做了一件最重要的事情:它跟踪文件依赖关系,只有在任何依赖关系比文件本身新的情况下才重建文件。这很好,它大大减少了构建时间,尤其是在执行大量代码生成工具时。
我在项目中使用了大量的代码生成。然而,代码生成需要一些时间,生成的代码必须在之后进行编译,因此浪费了更多的时间。大多数生成的代码只依赖于少数文件,例如生成解析器时的语法规范。使用make
,我只需将依赖项设置为规范文件,只有在规范更改时才会重新生成解析器。在我的一些项目中,生成代码需要80-90%的时间来完成重建。因此,不必重新生成生成的代码可以将我的构建过程加快近10倍。
现在转到java
人们不会将make
用于java,所以即使我喜欢make,我也会为我的java项目使用常用的java构建工具。我尝试过的构建工具(ant、gradle、maven(似乎没有提供这样的依赖性跟踪。相反,它们依赖于被调用的应用程序或任务来完成这项工作(例如,ant copy
任务只复制过时的文件(。然而,我使用的代码生成程序根本不提供这样的检查。无论输入规范是否过时,它们总是执行完整的代码生成。
因此,我在java中的构建时间变得越来越长。它们太长了,以至于我把通常构建周期中的代码生成放到了一个单独的目标中,并且只在更改任何规范文件后手动执行这个目标。当然,这很容易出错,因为我有时会忘记它。我的构建过程现在感觉完全有缺陷。
最后,我的问题
-
有没有一种方法可以在我提到的任何构建工具(ant、gradle、maven(中执行依赖项跟踪并仅重建过时的文件,但我不知道?
-
如果没有,为什么?为什么java社区似乎不关心这个特性?尤其是在涉及大量代码生成的情况下,这样的功能非常重要,尤其是在所使用的代码生成工具本身不提供该功能的情况下。
-
如果没有,那么还有其他java构建工具有这样的跟踪吗?
一些以等级为中心的答案:
只有当任务的输入与上次运行相比发生了更改,或者其输出被删除或修改时,Gradle才会重新运行任务。这是通用功能,适用于任何任务,只要它声明其输入和输出即可。(内置任务类型开箱即用地声明其输入和输出。(此功能通常被称为增量构建-一种只执行任务子集的构建。
Gradle还(非常(实验性地支持增量Java编译。这是增量任务的一个示例,即仅根据执行一个子集工作的任务,输入与上一次运行相比发生了变化。实现增量任务需要了解任务的域(例如Java编译(。因此,该功能不如增量构建功能通用,并且需要任务实现者付出更多努力。
举一个具体的例子,如果代码生成任务声明了它的输入和输出(这很容易做到(,那么只有在语法文件发生更改或生成的文件被删除或修改时,它才会重新运行。(为了这个例子的目的,让我们假设可以有多个语法文件。(此外,您的任务实现可以询问Gradle自上次运行以来哪些语法文件发生了更改,并使用这些信息只重新生成文件的子集。显然,这需要你自己努力实现,而且可能不可能实现,这取决于你的任务所使用的底层工具的性质。
关于增量编译的更多内容:由于以下几个原因,增量编译在Java构建工具中不太普遍。首先,Java的编译速度比C++快得多。此外,代码库通常被模块化为许多较小的编译单元,只有当其中一个输入发生变化时(至少在Gradle中(,每个编译单元才会被重新编译。尽管如此,我相信随着时间的推移,会有更多的Java构建工具支持增量编译。有些已经在今天做了(例如Pants、sbt和IDE,如Eclipse和IntelliJ(,Gradle即将赶上。
Maven可以用于此。maven如何只编译修改后的java文件?是你问题的答案:
我只是好奇地想知道这一点,当我在没有做任何事情的情况下安装mvn时"clean",maven只编译修改后的java文件
问题是您重新生成了所有文件。然后您就无法跟踪未修改的文件(所有迭代的工具都会比较.class和.java之间上次修改的时间戳(。您能将代码生成限制为只生成真正修改过的文件吗?
如果不能,可以在另一个目录中生成文件,并编写一个脚本来检查和替换编译"区域"中的修改文件(通过比较内容(。之后,您可以运行mvn-install。