为什么java(maven)在编译期间关心文件时间戳?

时间:2012-07-05 21:04:59

标签: java maven timestamp javac non-deterministic

我有一个项目,我已经工作了几天,我终于得到它干净地编译。但是,同一个远程分支的git clone(在同一台机器上,在同一个终端实例中编译)会导致编译错误。另一台机器上的新克隆具有相同的错误。我认为这是一个问题,我的工作目录有一些额外的未跟踪文件,但我删除了所有未跟踪的文件到diff说除了.git文件夹中包含的内容之外的目录是相同的。我甚至用tree检查了权限,并将结果文件与meld进行了比较 - 它们基本相同,尽管一些源文件的执行权限略有不同。

错误来自我在maven-compiler-plugin中排除的文件。这个应该本质上意味着文件名永远不会传递给javac,虽然我不确切知道它是如何工作的。我清楚地意识到,如果编译器内部的代码出错,编译器就会从某个地方获取文件。在我的计算机上的一个目录中工作,没有错误,它编译完美。在repo的其他克隆(根据diff再次相同),它会在此(排除的)文件中出错。

其他实验表明,在远程分支的新git clone上,本地目录的cp -R或本地目录的git clone编译失败。但是,如果我使用--archive选项执行了cp,则生成的目录中的编译成功。我将其缩小到--preserve=timestamps标志(由于--archive-dR --preserve=all相同而启用)。如果你没有完全理解,我会再说一遍。

当我正常复制目录时,它拒绝正确编译。只有在保留时间戳的情况下,它才会与原始目录的行为相同。

我不明白这一点 - 为什么java编译器(或maven)关心时间戳?

1 个答案:

答案 0 :(得分:1)

问题最终成为一个Maven编译器插件问题,结合我试图做一些有点误导的事情。

简而言之,编译器插件会传递您要编译的每个文件的列表以及指向源目录的链接。

文件列表非常好,因为这是javac知道要编译哪些内容的方式。但是,源目录也被传递的事实并不理想。当您将文件(或模式)放入maven编译器插件的<excludes>标记时,它将不再显示在传递给javac的文件列表中。但是,它很可能会驻留在您的源目录中(maven传递给javac)。这意味着即使您排除了javac,javac仍然可以编译这些文件。如果其中一个文件是另一个文件的依赖项,则可能发生这种情况这里预期的行为是抛出一个错误 - 相反,它编译被排除的文件并继续它的快乐方式。

在我的情况下(正如我在评论中所解释的那样)我遇到了问题,因为明确排除了一个文件(原因:maven处理类路径的方式中无关的错误意味着文件无法由maven正确编译)仍在尝试即使我试图提供该类的预编译版本,也要编译。

在这种情况下,如果我复制了没有保留时间戳的文件,它认为最近修改了源文件,并且该类的预编译版本已过期。因此javac试图编译排除的文件。只有当我保留时间戳(显示文件未在几个月内修改)时,javac才会意识到它应该使用提供的.class文件。