Aktualisieren : Seit diese Antwort veröffentlicht wurde, haben sich einige der verfügbaren Tools geändert. Nach der ursprünglichen Antwort gibt es ein Update mit Informationen zum Erstellen des Beispiels mit aktuellen Tools.
Es ist nicht ganz so einfach wie das Kompilieren in ein Glas und das Aufrufen der internen Methoden. Es scheint jedoch ein paar Tricks zu geben, damit alles funktioniert. Hier ist ein Beispiel für eine einfache Clojure-Datei, die zu einem JAR kompiliert werden kann:
(ns com.domain.tiny
(:gen-class
:name com.domain.tiny
:methods [#^{:static true} [binomial [int int] double]]))
(defn binomial
"Calculate the binomial coefficient."
[n k]
(let [a (inc n)]
(loop [b 1
c 1]
(if (> b k)
c
(recur (inc b) (* (/ (- a b) b) c))))))
(defn -binomial
"A Java-callable wrapper around the 'binomial' function."
[n k]
(binomial n k))
(defn -main []
(println (str "(binomial 5 3): " (binomial 5 3)))
(println (str "(binomial 10042 111): " (binomial 10042 111)))
)
Wenn Sie es ausführen, sollten Sie Folgendes sehen:
(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...
Und hier ist ein Java-Programm, das die -binomial
Funktion in der aufruft tiny.jar
.
import com.domain.tiny;
public class Main {
public static void main(String[] args) {
System.out.println("(binomial 5 3): " + tiny.binomial(5, 3));
System.out.println("(binomial 10042, 111): " + tiny.binomial(10042, 111));
}
}
Die Ausgabe lautet:
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
Das erste Stück Magie ist die Verwendung des :methods
Schlüsselworts in der gen-class
Anweisung. Dies scheint erforderlich zu sein, damit Sie auf die Clojure-Funktion zugreifen können, ähnlich wie bei statischen Methoden in Java.
Die zweite Sache ist, eine Wrapper-Funktion zu erstellen, die von Java aufgerufen werden kann. Beachten Sie, dass die zweite Version von -binomial
einen Bindestrich vor sich hat.
Und natürlich muss sich das Clojure-Glas selbst auf dem Klassenpfad befinden. In diesem Beispiel wurde das Glas Clojure-1.1.0 verwendet.
Update : Diese Antwort wurde mit den folgenden Tools erneut getestet:
- Clojure 1.5.1
- Leiningen 2.1.3
- JDK 1.7.0 Update 25
Der Clojure-Teil
Erstellen Sie zunächst mit Leiningen ein Projekt und eine zugehörige Verzeichnisstruktur:
C:\projects>lein new com.domain.tiny
Wechseln Sie nun in das Projektverzeichnis.
C:\projects>cd com.domain.tiny
Öffnen Sie im Projektverzeichnis die project.clj
Datei und bearbeiten Sie sie so, dass der Inhalt wie unten gezeigt ist.
(defproject com.domain.tiny "0.1.0-SNAPSHOT"
:description "An example of stand alone Clojure-Java interop"
:url "http://clarkonium.net/2013/06/java-clojure-interop-an-update/"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]]
:aot :all
:main com.domain.tiny)
Stellen Sie nun sicher, dass alle Abhängigkeiten (Clojure) verfügbar sind.
C:\projects\com.domain.tiny>lein deps
Möglicherweise wird an dieser Stelle eine Meldung zum Herunterladen des Clojure-Glases angezeigt.
Bearbeiten Sie nun die Clojure-Datei C:\projects\com.domain.tiny\src\com\domain\tiny.clj
so, dass sie das in der ursprünglichen Antwort gezeigte Clojure-Programm enthält. (Diese Datei wurde erstellt, als Leiningen das Projekt erstellt hat.)
Ein Großteil der Magie liegt hier in der Namespace-Deklaration. Das :gen-class
weist das System an, eine Klasse com.domain.tiny
mit einer einzelnen statischen Methode namens zu erstellen. Diese binomial
Funktion verwendet zwei ganzzahlige Argumente und gibt ein Double zurück. Es gibt zwei ähnlich benannte Funktionen binomial
, eine traditionelle Clojure-Funktion -binomial
und einen Wrapper, auf den über Java zugegriffen werden kann. Beachten Sie den Bindestrich im Funktionsnamen -binomial
. Das Standardpräfix ist ein Bindestrich, kann jedoch bei Bedarf in einen anderen geändert werden. Die -main
Funktion ruft nur ein paar Mal die Binomialfunktion auf, um sicherzustellen, dass wir die richtigen Ergebnisse erhalten. Kompilieren Sie dazu die Klasse und führen Sie das Programm aus.
C:\projects\com.domain.tiny>lein run
Die Ausgabe sollte in der Originalantwort angezeigt werden.
Packen Sie es jetzt in ein Glas und stellen Sie es an einen geeigneten Ort. Kopieren Sie dort auch das Clojure-Glas.
C:\projects\com.domain.tiny>lein jar
Created C:\projects\com.domain.tiny\target\com.domain.tiny-0.1.0-SNAPSHOT.jar
C:\projects\com.domain.tiny>mkdir \target\lib
C:\projects\com.domain.tiny>copy target\com.domain.tiny-0.1.0-SNAPSHOT.jar target\lib\
1 file(s) copied.
C:\projects\com.domain.tiny>copy "C:<path to clojure jar>\clojure-1.5.1.jar" target\lib\
1 file(s) copied.
Der Java-Teil
Leiningen hat eine eingebaute Aufgabe, lein-javac
die bei der Java-Kompilierung helfen soll. Leider scheint es in Version 2.1.3 kaputt zu sein. Das installierte JDK kann nicht gefunden werden, und das Maven-Repository kann nicht gefunden werden. Die Pfade zu beiden haben eingebettete Leerzeichen in meinem System. Ich nehme an, das ist das Problem. Jede Java-IDE kann auch die Kompilierung und Verpackung übernehmen. Aber für diesen Beitrag gehen wir auf die alte Schule und machen es an der Kommandozeile.
Erstellen Sie zuerst die Datei Main.java
mit dem Inhalt der ursprünglichen Antwort.
Java-Teil kompilieren
javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java
Erstellen Sie nun eine Datei mit einigen Metainformationen, die Sie dem zu erstellenden JAR hinzufügen möchten. In Manifest.txt
den folgenden Text
Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main
Packen Sie jetzt alles in eine große JAR-Datei, einschließlich unseres Clojure-Programms und des Clojure-Jars.
C:\projects\com.domain.tiny\target>jar cfm Interop.jar Manifest.txt Main.class lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
So führen Sie das Programm aus:
C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
Die Ausgabe ist im Wesentlichen identisch mit der von Clojure allein, aber das Ergebnis wurde in ein Java-Double konvertiert.
Wie bereits erwähnt, wird sich eine Java-IDE wahrscheinlich um die chaotischen Kompilierungsargumente und die Verpackung kümmern.