3
votes

I found while adding warnings to code that writes macros that the body of a file was being executed twice during compilation. Is there a reason for this? Is this specific to leiningen? I can not reproduce this with (compile ...).

Simplified version:

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

;; empty

(ns foo.bar)

(println "hello")

$ lein compile :all

Compiling foo.core

hello

Compiling foo.bar

hello

Further testing shows that the namespace is reloaded on top of itself during compile:

(ns foo.bar)

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

$ lein clean

$ lein compile :all

Compiling foo.core

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

Compiling foo.bar

2

In a more complicated case I have this happening during compile, and then once every time when run or started a repl from lein. I am not sure why. This is all with clojure 1.6 and leiningen 2.5.0.

2

2 Answers

5
votes

Leiningen knows nothing about the structure of your project in terms of how namespaces relate to each-other. Consequently, when compiling a project, lein simply boots a JVM and forces each namespace to be loaded one at a time. This means that, as you noticed, namespaces will be reloaded causing the double evaluation behaviour you are noticing.

In comparison, (clojure.core/compile) simply loads the targeted resource with clojure.core/*compile-files* bound. This will cause the targeted resource and all the resources it requires to be loaded and compiled to class-files. However, it will not traverse your entire project structure compiling all resources as Leiningen's compile operation does.

1
votes

The reason why you're seeing println output during compile time is because println is called during namespace evaluation. You should have a -main fn or some other entry point for your program that calls on println.

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

I think your project is throwing an Unbound Exception because you're trying to reference the wasd variable with println before a value is assigned to it. The variable was declared, but nothing was assigned to it before the println fn tried to get the value.