标准Sun javac可以进行增量编译吗?

标准Sun javac可以进行增量编译吗?,java,eclipse,compiler-construction,sun,incremental-compiler,Java,Eclipse,Compiler Construction,Sun,Incremental Compiler,最近我开始使用Eclipse的java编译器,因为它比标准javac快得多。我被告知它更快,因为它执行增量编译。但我仍然有点不确定,因为我找不到任何关于-eclispse和sun的编译器“增量特性”的权威文档。Sun的编译器总是编译每个源文件,Eclipse的编译器只编译更改过的文件和受此更改影响的文件,这是真的吗 编辑:我没有使用EclipseAutobuild特性,而是设置 -Dbuild.compiler=org.eclipse.jdt.core.JDTCompilerAdapter 对

最近我开始使用Eclipse的java编译器,因为它比标准javac快得多。我被告知它更快,因为它执行增量编译。但我仍然有点不确定,因为我找不到任何关于-eclispse和sun的编译器“增量特性”的权威文档。Sun的编译器总是编译每个源文件,Eclipse的编译器只编译更改过的文件和受此更改影响的文件,这是真的吗

编辑:我没有使用EclipseAutobuild特性,而是设置

-Dbuild.compiler=org.eclipse.jdt.core.JDTCompilerAdapter

对于我的蚂蚁构建

Eclipse确实做到了这一点。此外,如果您启用了该选项(默认情况下),它也会节省时间。看起来sun也没有这样做(这很容易测试,只需制作一个小项目,其中a是使用B类的主类,但B不使用a类。然后更改a并再次编译项目,查看
B.class
的时间戳是否已更改

这是许多编译器的工作方式(例如gcc)。您可以使用诸如ant和make之类的工具来只编译项目中已更改的部分。还要注意,这些工具并不完美,有时eclipse只是无法跟踪更改,您需要进行完整的重建

Sun的编译器总是编译每个源文件,Eclipse的编译器只编译更改过的文件和受此更改影响的文件,这是真的吗

我相信你在这两方面都是正确的

当然,您可以强制Eclipse重新编译所有内容

但等式的另一部分是,像Ant和Maven这样的Java构建工具只能编译已经更改的类,以及它们的依赖类树

编辑

在Ant中,增量编译可以通过两种方式完成:

  • 默认情况下,比较
    .java
    和相应的
    .class
    文件的时间戳,并且只告诉java编译器重新编译比相应的目标(.class)文件新的源(.java)文件,或者根本没有目标文件的源(.java)文件

  • 还考虑了类之间的依赖关系,它通过读取和分析嵌入在
    .class
    文件中的依赖关系信息来确定这些依赖关系。在确定哪些
    .class
    文件过期后,
    任务将删除这些文件,以便后续的
    任务将重新编译它们。但是,这并非完全是傻瓜式的。例如,对源代码的大量更改可能会导致
    任务可能正在分析过时的依赖关系。此外,某些类型的依赖关系(例如对静态常量的依赖关系)在
    .class
    文件格式中并不明显

    要理解为什么Ant
    不是傻瓜式的,请阅读的“限制”部分


Javac只编译在命令行上命名或是依赖项且过时的源文件。Eclipse可能有一种更细粒度的方法来决定这意味着什么。

重复我在这里听到的内容,并为像我这样的懒人使用:

您可以使用ant中的javac任务实现增量构建,但是您应该使用depend任务清除修改后的.java的.class文件,并且您不能在javac任务中未指定includes语句。(在javac任务中仅指定src路径并保留包括未指定的原因,javac将重新编译它找到的所有源。)

这是我的依赖项和javac任务。使用标准的Oracle java编译器,只编译我修改的.java文件。希望这有帮助

<depend srcdir="JavaSource" destdir="${target.classes}" cache="${dependencies.dir}" closure="yes">
    <classpath refid="compiler.classpath" />
    <include name="**/*.java"/>
</depend>

<javac destdir="${target.classes}" debug="true" debuglevel="${debug.features}" optimize="${optimize.flag}" fork="yes" deprecation="no" source="1.6" target="1.6" encoding="UTF-8" includeantruntime="no">
    <classpath refid="compiler.classpath"/>
    <src path="JavaSource"/>
    <include name="**/*.java" />   <!-- This enables the incremental build -->
</javac>


您能解释一下使用Ant进行部分编译是如何工作的吗?Ant是如何强制Sun的编译器只编译更改过的文件而忽略源代码树中的其他文件的?我想您回答了我最初的问题,但随着您提供的信息越来越多,我越来越困惑。如果我理解正确,我觉得Java C任务与您无关t previous clean是一个非常危险的操作,因为如果不更改依赖类的时间戳,它就不会编译这些依赖类。(有趣的是,我昨天才意识到我可能遇到了这个问题,对我来说,这完全是个谜。)如果依赖类没有更改,为什么需要编译它?因为它所依赖的类型或方法签名已经更改。或者因为它所依赖的编译时常量已经更改。ant可以做到这一点,但maven似乎不能做到这一点。你可以链接一些支持此答案的文档吗?我认为1)依赖项不是由纯javac编译的,2)Eclipse有它自己的、完全不同的编译器,而不仅仅是更细粒度的决定方式。我也不能证明,但这就是为什么我问:)。。。。当然,你可以证明这一点:只需设置我描述的条件,你自己就会看到。这是正确的:javac编译你告诉它要编译的文件,而不是“每个源文件”。它不会自行决定需要编译哪些文件,因此它不是OP所要求的增量。此外(正如EJP所说),当javac编译类A并找到A所依赖的其他.java文件时,它(取决于许多因素)也会编译它们。这与查找可能受A.java更改影响的文件不同,我认为这是人们感到困惑的地方。@gatkin你自相矛盾。为了澄清或重申,javac编译您告诉它的每个文件以及它能够检测到的任何过时的依赖项,它确实“决定”了这些依赖项@EJP我发表了评论,解释了我为什么投票给您。关于javac的功能,我们都说了同样的话。它没有做的是寻找过时的依赖项,就像Eclipse一样,这正是OP所要求的。尽管我认为你的回答是正确的,我也这么说了,但我认为最后一点值得一提