Nei*_*ett 14 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的工具.
Nei*_*ell 10
编写产生多个输出但其名称无法静态确定的规则可能有点棘手.通常的方法是找到名称是静态已知的输出,并且need
如果不存在,则创建一个伪文件以用作静态输出(根据ghc-make,.result
文件).在你的情况下,你有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 ."
Run Code Online (Sandbox Code Playgroud)
将它分成两个规则没有任何好处,因为你永远不依赖于.class
文件(并且不能真正,因为它们在名称上是不可预测的),并且如果任何源文件发生变化,那么module.jar
无论如何你总是会重建.此规则具有您提及的所有依赖项,如果您添加/重命名/删除任何.java
或.class
文件,则它将自动重新编译,因为getDirectoryFiles
跟踪调用.