2014-11-21 37 views
3

我在向代碼寫入代碼時發現,編寫代碼的時候,編譯過程中兩次執行文件的主體。是否有一個原因?這是特定的leiningen?我不能用(compile ...)來重現這一點。用leiningen評估clojure文件的時間和次數?

簡體版:

(ns foo.core 
    (:require foo.bar)) 

;; empty 

(ns foo.bar) 

(println "hello") 

$雷音編譯:所有

編譯foo.core

hello

編譯foo.bar

hello

進一步的測試表明,命名空間編譯過程中其本身上重新加載:

(ns foo.bar) 

(declare wasd) 
(println wasd) 
(def wasd 2) 

$雷音乾淨

$雷音編譯:全部

編譯foo.core

#<Unbound Unbound: #'foo.bar/wasd>

運行或啓動時編譯foo.bar

2

在更復雜的情況下,我必須編譯期間這種情況的發生,再一次時間來自lein的回報。我不知道爲什麼。這一切都與clojure 1.6和leiningen 2.5.0。

回答

5

Leiningen根據名稱空間與對方之間的關係,對項目結構一無所知。因此,在編譯項目時,lein只需啓動JVM,並強制每個命名空間一次加載一個。這意味着,正如您注意到的那樣,名稱空間將被重新加載,從而導致您注意到的雙重評估行爲。

相比之下,(clojure.core/compile)只需加載目標資源clojure.core/*compile-files*界限。這將導致目標資源和它需要的所有資源被加載並編譯到類文件。但是,它將而不是遍歷整個項目結構編譯所有資源,如Leiningen的編譯操作一樣。

+0

我不明白。爲什麼「強制每次加載一個名稱空間」意味着「名稱空間將被重新加載」? – Mars 2014-11-22 06:51:12

+0

如果命名空間A需要B,爲了加載A,必須首先加載B.因此,如果您首先加載A然後加載B,則加載A將加載B,然後您將導致B被重新加載。 – arrdem 2014-11-22 08:01:55

+0

這似乎是正確的。檢查[編譯任務]的源代碼(https://github.com/technomancy/leiningen/blob/master/src/leiningen/compile.clj),它只是依次在每個文件上調用'clojure.core/compile' 。我認爲背後有更多的「大腦」。 – metatheorem 2014-11-22 13:34:06

1

您在編譯期間看到println輸出的原因是因爲println在命名空間評估過程中被調用。你應該有一個-main FN或其他一些入口點,用於調用println的程序。

(defn -main [& _] 
    (println "Won't see on compile.") 
    (println "lein run -- is printing from -main")) 

我想是因爲你想與println引用wasd變量之前的值分配給它的項目是扔一個未綁定的異常。該變量已被聲明,但在println fn嘗試獲取該值之前未分配該變量。

+2

該示例的要點是第二次變量已被綁定。它被用來證明命名空間被加載了兩次。預計最初的不受約束。 – noisesmith 2014-11-21 14:26:38