haskell - 带 Shake 的多输入、多输出编译器

标签 haskell shake-build-system

我正在尝试使用 Shake构建 Java 代码,由于 javac 编译器的不寻常性质,我有点卡住了。通常,对于大型项目的每个模块,都会使用该模块的所有源文件作为输入来调用编译器,并一次性生成所有输出文件。随后,我们通常会将编译器生成的 .class 文件组装成 JAR(基本上只是 ZIP)。

例如,一个典型的Java模块项目的安排如下:

  • 一个src包含多个 .java 文件的目录,其中一些文件在树中嵌套了很多层。
  • 一个bin包含编译器输出的目录。通常,此输出遵循相同的目录结构和文件名,即 .class替换每个 .java 文件,但映射不一定一定是一对一的:单个 .java 文件可以生成零到多个 .class 文件!

因此,我想在 Shake 中定义的规则如下:

1) 如果 src 下有任何文件比 bin 下的任何文件新然后删除bin的所有内容并重新创建:

javac -d bin <recursive list of .java files under src>

我知道这个规则似乎有点过分,但是如果不调用编译器,我们就无法知道即使单个输入文件中的微小变化也会导致输出变化的程度。

2) 如果 bin 下有任何文件比module.jar更新然后重新创建module.jar与:

jar cf module.jar -C bin .

非常感谢!

PS 类似“只使用 Ant/Maven/Gradle/”的回复将不受欢迎!我知道这些工具提供开箱即用的 Java 编译,但它们更难组合和聚合。这就是为什么我想尝试使用基于 Haskell/Shake 的工具。

最佳答案

编写产生多个名称无法静态确定的输出的规则可能有点棘手。通常的方法是找到一个名称静态已知且始终需要的输出,或者如果不存在,则创建一个假文件用作静态输出(按照 ghc-make, the .result file )。在你的情况下,你有 module.jar 作为最终输出,所以我会写:

"module.jar" *> \out -> do
    javas <- getDirectoryFiles "" ["src//*.java"]
    need javas
    liftIO $ removeFiles "" ["bin//*"]
    liftIO $ createDirectory "bin"
    () <- cmd "javac -d bin" javas
    classes <- getDirectoryFiles "" ["bin//*.class"]
    need classes
    cmd "jar cf" [out] "-C bin ."

将其分成两个规则没有任何优势,因为您从不依赖于 .class 文件(并且不能真正依赖,因为它们的名称是不可预测的),并且如果有任何来源文件更改,那么无论如何你总是会重建 module.jar 。该规则具有您提到的所有依赖项,此外,如果您添加/重命名/删除任何 .java.class 文件,那么它将自动重新编译,如 getDirectoryFiles 调用已被跟踪。

关于haskell - 带 Shake 的多输入、多输出编译器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17287080/

相关文章:

haskell - 定义可存储实例时如何找到对齐值

haskell - 无法从实例声明的父类(super class)中推断出(半群(可选 a))

parsing - Happy 运算符优先级错误

haskell - 如何将 PHONY 目标声明为 shake 的默认操作?

docker - 如何定义抖动规则来构建 docker 镜像?

haskell - 这如何 getRight::要么 a b -> 也许 b 工作?

haskell - Haskell 中的惯用向量代数

haskell - 摇一摇: Signal whether anything had to be rebuilt at all

haskell - 如果文件的一部分发生更改则运行操作

haskell - 使用 shake 为一组文件定义规则,在构建时未知