2015-08-29 5 views
6

Ich versuche zu verstehen, "Lieningen" Verhalten bei der Erstellung eines uberjar. Im Anschluss ist das minimale Beispiel, die das Verhalten reproduziert:Warum `lein uberjar` Variablen bewertet, die mit` def` definiert sind?

(ns my-stuff.core 
    (:gen-class)) 

(def some-var (throw (Exception. "boom!"))) 

(defn -main [& args] 
    (println some-var)) 

Wenn diese mit lein run ausgeführt wird mit einer Ausnahme deutlich ausfällt. Ich verstehe jedoch nicht, warum die Ausführung von lein uberjar auch mit einer Ausnahme von der Variablendefinition fehlschlägt? Warum versucht lein uberjar versucht, den Variablenwert auszuwerten? Ist dies spezifisch für uberjar Aufgabe oder fehle ich etwas wesentlicher über Clojure oder Leiningen?

Antwort

10

Um Ihren Namespace für das Uberjar zu kompilieren (wenn AOT aktiviert ist), muss der Clojure-Compiler Ihren Namespace laden. Dies ruft immer alle Top-Level-Nebenwirkungen hervor.

Der beste Weg, dies zu handhaben ist, nie Nebenwirkungen in Top-Level-Code (innerhalb oder außerhalb einer def Form), und haben Initialisierungsfunktionen, um alle Start-up-Nebenwirkungen benötigt zu realisieren.

kann Eine Abhilfe einen kleinen Namensraum zu machen, die Selbstbeobachtung den Rest des Codes zur Laufzeit laden verwendet, aber nicht beim Kompilieren - eine Funktion wie folgt verwendet:

(defn -main 
    [] 
    (require 'my.primary.ns) 
    ((resolve 'my.primary.ns/start))) 

wenn das Namespace kompiliert wird, die jvm kann -main finden und ausführen, obwohl kein anderer Code kompiliert wurde. Die Laufzeit require bewirkt, dass der Clojure-Compiler den Rest des Codes nur zur Laufzeit lädt, und resolve wird benötigt, damit -main sauber kompiliert wird - es gibt die referenzierte Var zurück, die dann beim Aufruf die Funktion aufruft.