Maven编译器重新编译所有文件而不是修改

Posted

技术标签:

【中文标题】Maven编译器重新编译所有文件而不是修改【英文标题】:Maven compiler recompile all files instead modified 【发布时间】:2013-06-02 12:22:49 【问题描述】:

即使我只更改了一个类,Maven 也会重新编译所有这些类。我使用这个插件配置:

<plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.1</version>
      <configuration>
        <staleMillis>1</slateMillis>
        <useIncrementalCompilation>true</useIncrementalCompilation>
      </configuration>
    </plugin>
</plugins>

mvn compilemvn packagemvn install 会发生这种情况。

当然,如果您有 10-15 个文件,这不是问题。但是,我有一千多个源文件,这需要很多时间。

Maven 编译器插件是否有一些隐藏设置来仅重新编译修改过的文件?有什么解决方法吗?

【问题讨论】:

可能是坏消息:请参阅错误MCOMPILER-205。 托斯滕,请注意对您接受的答案的警告;这不是真/假混淆的情况。有关背景,请参阅我的答案。您可能需要重新考虑接受哪个答案。 看起来 Maven 开发人员试图开发一种不起作用的“改进”增量编译。当您设置 false 时,您将恢复到 javac 提供的标准增量编译,这就是这个问题所要求的。接受的答案是正确的,不需要警告资格。 【参考方案1】:

总结

虽然您可以告诉 Maven“只重新编译修改过的文件”,但这样做会导致错误的结果。默认行为不是错误,而是有意的设计决定。


useIncrementalCompilation 的真正作用

委婉地说,关于这个主题的文档并不是最佳的。以下是实际发生的情况(基于来自maven-compiler-plugin 3.3 的AbstractCompilerMojo source):

useIncrementalCompilation 设置为 false不推荐) 这只会编译比相应类文件更新的源文件,即自上次编译过程以来已更改的源文件。正如@Ivan 在对另一个答案的评论中指出的那样,这不会重新编译使用更改后的类的其他类,可能会使它们引用不再存在的方法,从而导致运行时出错。 useIncrementalCompilation 设置为 true默认) 为处理上述问题,在此模式下,编译器插件将确定是否 当前模块所依赖的所有 JAR 文件在当前构建运行中都已更改,或者 自上次编译以来添加、删除或更改了任何源文件。 如果是这种情况,编译器插件会有意重新编译所有源代码,打印Changes detected - recompiling the module!

因此,总而言之,useIncrementalCompilation 应始终保留默认值 true


为什么它不做其他事情

可以理解,有人可能会问:为什么插件不能确定哪些类会受到更改的影响,而只重新编译那些类?在MCOMPILER-205上的cmets中,Maven开发者Robert Scholte给出了brief rationale和后来的confirmed以下详细解释:

如果任何源文件已被更改或删除,所有文件都将被删除并重新编译。原因是使用默认的 java 编译器简单地重新编译所有内容非常快,可能比替代方案快得多,看起来类似于:

    检测所有更改的文件 分析所有源文件以映射类之间的所有关系 计算所有受影响的文件 重新编译受影响的文件

但是,正如 Robert 和 writes 一样,如果项目使用执行此分析的 Eclipse 编译器,则可能不需要重新编译所有内容。但对于今天的 Maven 用户来说,这是一个有争议的问题,因为 maven-compiler-plugin 尚未根据编译器的选择改变其行为。

【讨论】:

我认为您误读了开发人员的评论。一开始我摸不着头脑,但我认为他的意思是 javac 提供的 default 增量编译速度很快。我非常怀疑他的意思是每次进行更改时都重新编译 everything 更可取。您只需要一个包含 100 个以上源文件的项目即可证明这是无稽之谈。 @robert 我要求在链接问题中进行澄清,并用开发人员确认的详细解释更新了我的答案。当然,他们的假设(“可能比替代方案快得多”)可能会被证明是错误的。我很确定,如果你提交一个补丁和一个演示项目来证明这一点,Maven 团队会很乐意接受它。 @JensBannmann 我很乐意将您的 PR 与此信息合并。 @JensBannmann 资源文件夹也编译吗? Bcz 当我修改一个类然后再次编译它时资源文件夹哈希也在变化。【参考方案2】:

https://issues.apache.org/jira/browse/MCOMPILER-209

与保加利亚符号一起使用(是 否)

&lt;useIncrementalCompilation&gt;false&lt;/useIncrementalCompilation&gt; 表示正确,反之亦然

【讨论】:

请记住,使用此设置它会执行简单的增量编译,但它不是很有用,因为它不会重新编译依赖的类。因此,例如,如果您有 A 类调用 B 类的方法,并且您修改 B 中方法的签名,maven 将仅重新编译 B 并且编译将成功,但现在 A 引用了 B 中不存在的方法. 所以这个设置可以被认为是“useSmartIncrementalCompilation”,所以当我们将它设置为false时,我们只会得到我上面描述的基本(和危险)的一个。在 maven 3 中,“智能”似乎被打破了,而不是计算正确的依赖类,如果项目中的单个类被更改,它将所有类标记为依赖类,从而有效地使编译非增量。 亲爱的 wapgui,您的回答具有误导性,请参阅上面@Ivan 的 cmets。请在答案中添加警告。 不需要警告。这是正确的答案,因为它提供了默认的 javac 行为,这是所寻求的。当然,不言而喻,如果您正在构建一个版本,您可以从零开始,但对于增量开发,风险被理解并接受为公平的权衡。 @robert 恐怕我不同意。问题中没有任何内容表明“寻求默认的 javac 行为......”或“风险被理解和接受为公平的权衡”。答案中也没有注明,因此我建议在答案中添加警告。

以上是关于Maven编译器重新编译所有文件而不是修改的主要内容,如果未能解决你的问题,请参考以下文章

命令行 mvn 编译,但不是 IntelliJ

idea每次修改都要重新编译

如何避免每次重新编译所有文件?

快速静态常量变量更改导致重新编译

tomcat 每次启动编译文件classes 为啥还用ANT进行重新编译? 和maven有啥区别

我在keil里,工程编译好之后,啥都不改,再编译一次,又要重新一个文件一个文件编译是怎么回事?