FSC每次都重新编译

时间:2010-09-27 12:20:25

标签: scala compilation scalac

FSC每次都重新编译我的.scala文件,即使没有必要 - 我可以编译两次而不需要在尝试之间编辑任何内容并重新编译它们! 例如,我有2个文件

Hello.scala

class Hello{
  print("hello")
}

和Tokens.scala:

abstract class Token(val str: String, val start: Int, val end: Int)
  {override def toString = getClass.getSimpleName + "(" + "[" + start + "-" + end + "]" + str + ")"}
class InputToken(str: String, start: Int, end: Int)
        extends Token(str, start, end)
 class ParsedToken(str: String, start: Int, end: Int, val invisible: Boolean)
        extends Token(str, start, end)

当我要求ant从头编译项目时,我看到以下输出:

ant compile
init:
    [mkdir] Created dir: D:\projects\Test\build\classes
    [mkdir] Created dir: D:\projects\Test\build\test\classes

compile:
      [fsc] Base directory is `D:\projects\Test`
      [fsc] Compiling source files: somepackage\Hello.scala, somepackage\Tokens.scala to D:\projects\Test\build\classes

BUILD SUCCESSFUL

我不会编辑任何内容并再次询问ant编译:

ant compile
init:
    [mkdir] Created dir: D:\projects\Test\build\classes
    [mkdir] Created dir: D:\projects\Test\build\test\classes

compile:
      [fsc] Base directory is `D:\projects\Test`
      [fsc] Compiling source files: somepackage\Tokens.scala to D:\projects\Test\build\classes

BUILD SUCCESSFUL

正如您所看到的,fsc在Hello.scala(无重新编译)的情况下表现得很聪明,在Tokens.scala的情况下表现为哑。我建议问题在某种程度上与继承有关,但这就是全部。

那有什么不对?

2 个答案:

答案 0 :(得分:5)

重新编译Tokens.scala,因为没有与其基本名称匹配的类文件。也就是说,它不会生成Tokens.class文件。在确定是否应该编译源文件时,fsc会查找具有相同基本名称的类文件,如果类文件不存在或者源文件的修改时间晚于类文件的修改时间,则将重建源文件。如果可以,我建议您查看Simple Build Tool,其连续编译模式准确跟踪source-> classfile映射,不会重新编译Tokens.scala

对于额外的笑声,请考虑如果您的源文件中包含class Tokens的其他源文件,编译器可能会执行的操作。

尽管scala允许任何源文件中的任意公共类/对象,但仍然有相当多的工具假设您将遵循java约定并且至少在文件中具有与源相同名称的一个类/对象文件基名。

答案 1 :(得分:4)

我不喜欢发布其他人写的东西,但我认为这个问题值得更严格地回答那些严格要求的问题。

因此,首先,fsc在默认情况下重新编译所有内容。它是ant,而不是fsc,它会离开Hello.scala,因为文件名与类名匹配。它没有离开Tokens.scala,因为没有编译Tokens的类 - 因此,在没有Tokens.class的情况下,它会重新编译Tokens.scala

这与Scala有关。 Scala在一个基本方面与Java的不同之处在于,由于JVM的技术限制,trait的更改需要重新编译使用它的每个类,对象或实例化。

现在,可以修复ant任务,从Scala 2.8开始做一个更聪明的事情。我是从Caoyuan的blogtrader.net获取此信息,这是Scala插件的Netbeans名声。您可以在构建目标上定义Scala任务,如下所示:

<scalac srcdir="${src.dir}"
        destdir="${build.classes.dir}"
        classpathref="build.classpath"
        force="yes"
        addparams="-make:transitive -dependencyfile ${build.dir}/.scala_dependencies"
        >
    <src path="${basedir}/src1"/> 
    <!--include name="compile/**/*.scala"/-->
    <!--exclude name="forget/**/*.scala"/-->
</scalac>

它告诉ant重新编译所有内容,因为ant根本不够聪明,无法确定需要重新编译的内容。它还告诉 Scala 构建一个包含编译依赖关系的文件,并使用传递依赖算法来确定需要重新编译的内容。

您还需要更改init目标以在构建类路径中包含构建目录,因为Scala需要重新编译其他类。它应该是这样的:

<path id="build.classpath">
    <pathelement location="${scala-library.jar}"/>
    <pathelement location="${scala-compiler.jar}"/>
    <pathelement location="${build.classes.dir}"/>
</path>

有关详细信息,请参阅Caoyuan的博客。