なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

leiningenで作るuberjarがmavenでできたらいいと思ったら出来なかった話

Leiningenでuberjarを作る

Clojureの日本語ガイドにあるように -> Part7: どのようにして Heroku へデプロイするか Leiningenから lein uberjar と打てばいわゆるFAT Jarができる。これは依存ライブラリを全て含んでいるのでJavaさえあれば実行できる。

Mavenからそれはできないか

似たようなものはできた。以下、設定したproject.clj

  • 肝心な部分は maven-shade-plugin
    • こいつが依存ライブラリとコンパイル済みのClojureからできたクラスファイルをjarに入れてくれる
  • ManifestResourceTransformerMaven側でManifest.mfを書き換えて、実行するメインクラスを定めてくれる
  • finalName
    • これを ${project.artifactId}-${project.version}-standalone で設定すると、leiningenがデフォルトで出力するuberjarの名前になるハズ

実行は lein pom してから mvn clojure:compile package

(defproject uber "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :uberjar-name "uber-clj.jar"
  :min-lein-version "2.5.3"
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :pom-plugins [[com.theoryinpractise/clojure-maven-plugin "1.3.8"
                 {:configuration ([:mainClass "uber.core"]
                                  [:sourceDirectories [:sourceDirectory "src/main/clj"]])}]
                [org.apache.maven.plugins/maven-shade-plugin "2.4.3"
                 [:executions [:execution ([:phase "package"]
                                           [:goals [:goal "shade"]]
                                           [:configuration
                                            [:transformers
                                             [:transformer
                                              {:implementation "org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer"}]
                                             [:transformer
                                              {:implementation "org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer"}]
                                             [:transformer
                                              {:implementation "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"}
                                              [:mainClass "uber.core"]]
                                             ]
                                            ;[:finalName "${project.artifactId}-${project.version}-standalone"]
                                            [:finalName "uber-clj"]
                                            [:filters
                                             [:filter
                                              [:includes
                                               [:include "**/*.js"]
                                               [:include "**/*.class"]
                                               [:include "**/*.xml"]]]]])]]]]
  :source-paths ["src/main/clj"]
  :test-paths ["src/test/clj"]
  :resource-paths ["resources"]
  :profiles
  {:dev {:env {:dev true }}
   :uberjar {:aot :all
             :main uber.core}})

動かない理由

ただし、この方法で作ったjarは動かない。それにはどうやらClojureのAOTコンパイルが関係しているらしい。

ClojureのAOTコンパイルは、タイムスタンプによってAOTコンパイル済みか判定する。maven-shade-pluginはこれをおかしくさせてしまうようだ。 むーん、maven-shade-pluginにプルリクする?

追記

簡単なスクリプト程度だと、Mavenから動かしても動くバイナリができるようだ。ringなどのライブラリを混ぜると動かない感じになる。