14

私はShakeを使用して Java コードをビルドする実験を行っていますが、javac コンパイラの異常な性質のために少し行き詰っています。一般に、大規模なプロジェクトの各モジュールでは、そのモジュールのすべてのソース ファイルを入力としてコンパイラが呼び出され、1 回のパスですべての出力ファイルが生成されます。その後、通常、コンパイラによって生成された .class ファイルを取得し、それらを JAR (基本的には単なる ZIP) にアセンブルします。

たとえば、典型的な Java モジュール プロジェクトは次のように配置されます。

  • 複数の .java ファイルを含むsrcディレクトリ。そのうちのいくつかは、ツリー内の何層にもネストされています。
  • コンパイラからの出力を含むbinディレクトリ。通常、この出力は同じディレクトリ構造とファイル名に従い、.class各 .java ファイルが置き換えられますが、マッピングは必ずしも 1 対 1 であるとは限りません。

したがって、シェイクで定義したいルールは次のとおりです。

1)下のファイルが下のどのファイルよりsrc新しい場合は、すべての内容を消去し、次のように再作成します。binbin

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 ベースのツールを試してみたい理由です。

4

1 に答える 1

10

名前を静的に決定できない複数の出力を生成するルールを記述するのは、少し注意が必要です。通常のアプローチは、名前が静的に知られている出力を見つけるneedか、存在しない場合は、静的出力として使用する偽のファイルを作成することです ( ghc-make によると、.resultfile )。あなたの場合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ファイルに依存することは決してないため(そして、名前が予測できないため、実際には依存できないため)、2つのルールに分割する利点はありません。また、ソースファイルが変更された場合は、module.jarとにかく常に再構築します。このルールには、言及したすべての依存関係があり、さらに、ファイル.javaまたはファイルを追加/名前変更/削除すると、呼び出しが追跡さ.classれるため、自動的に再コンパイルされます。getDirectoryFiles

于 2013-06-25T06:44:34.447 に答える