Leiningenを使わず、clojureのREPL環境にてcompile
関数を利用することでクラスファイルを生成し、それをjarファイルにまとめ、しかもjava -jar jar
ファイル名のような形で実行できるようにしたいと考えています。
javaについては言語の理解はありますが、それを支えるエコシステム(java
, jar
コマンド等)に関しては経験がなくて、リファレンスを見ながら試行錯誤している状態です。
このため、本件はclojureに関するミスがあってのことなのか、javaとそれに関するツールの使い方の問題であるかの切り分けが自分ではできませんでした。
ディレクトリ構成:
- 作業ディレクトリ(ルート)の下にサブディレクトリとして以下の名前のディレクトリを配置
- classes
- test1
- ルート直下にclojure-1.8.0.jar(clojureランタイム)を配置
- test1ディレクトリの直下に core.clj を配置
core.clj:
(ns test1.core
(:gen-class))
(defn -main
[greetee]
(println (str "Hello " greetee "!")))
REPL環境でコンパイル:
$ java -cp ./clojure-1.8.0.jar clojure.main
user=> (compile 'test1.core)
test1.core
JARにまとめない形で実行してみる:
$ java -cp ./classes:./clojure-1.8.0.jar test1.core Fred
Hello Fred!
JARファイルを作成:
$ jar cfe test1.jar test1.core classes
$ jar tf test1.jar
META-INF/
META-INF/MANIFEST.MF
classes/
classes/test1/
classes/test1/core$fn__5.class
classes/test1/core$loading__5569__auto____3.class
classes/test1/core$_main.class
classes/test1/core.class
classes/test1/core__init.class
$ jar xf test1.jar META-INF/MANIFEST.MF
$ cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 1.8.0_40 (Oracle Corporation)
Main-Class: test1.core
作成されたJARファイルを指定して実行してみる:
java -cp .\clojure-1.8.0.jar -jar test1.jar Fred
エラー: メイン・クラスtest1.coreが見つからなかったかロードできませんでした
なぜメインクラスがロードできないでエラーとなるのか、半日近くかけて分からないなりに調べてみたのですが自分では埒があきませんでした。原因の分かる方がいらしたらご教示お願いします。
追記(7/11 15:04)
Katsumiさんの答えに従って以下のようにjarコマンドを実行し直すと、エラー情報が変わりました。一歩前進だと思いますが、やはりこのエラーがなにを言っているのか、全く分からない状態です。
$ jar cfe test1.jar test1.core -C classes test1
$ jar tf test1.jar
test1/
test1/core$fn__5.class
test1/core$loading__5569__auto____3.class
test1/core$_main.class
test1/core.class
test1/core__init.class
$ java -cp ./clojure-1.8.0.jar -jar test1.jar Fred
Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var
at test1.core.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: clojure.lang.Var
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more
追記(7/11 15:28)
以下のようにすると、実行そのものはできるようになりました。
>java -cp .\clojure-1.8.0.jar;.\test1.jar test1.core Fred
Hello Fred!
Java Platform, Standard Editionツール・リファレンスを見てみると以下のように書いてありました。どうやらjarオプションを使うときには、指定するjarファイルに依存関係が全て入ってないと駄目なのか??という程度には推測できるようになりました。
-jar filename
JARファイルにカプセル化されたプログラムを実行します。filename引数は、アプリケーションの開始位置として機能するpublic static void main(String[]
args)メソッドによってクラスを定義する、Main-Class:classnameの形式の行を含むマニフェストのあるJARファイルの名前です。-jarオプションを使用すると、指定したJARファイルがすべてのユーザー・クラスのソースになり、他のクラス・パスの設定は無視されます。