Make javac run in a subprocess. Fixes #809.
If we're not making javac run in a subprocess, libraries the project depends on which leiningen has another version of will clash. This is because leiningen append its standalone to java's bootclasspath, which makes the ToolProvider add these classpaths automatically into the java compiler it returns. By starting a subprocess without leiningen added to the bootclasspath, we avoid this library clashing. UI changes as a result of this patch: Whenever javac fails, the task one wanted to run will be responsible for aborting Leiningen, whereas javac did this itself when it discovered that the compilation failed. As we're running in a subprocess, an abort message such as Uberjar aborting because jar/compilation failed: Subprocess failed will appear, though this will only be appended to the javac error message and the "Compilation of Java sources (lein javac) failed." message. This commit also adds the overhead of starting a subprocess when one have to compile java sources, but it will not start one if no .class-files are outdated/not existing. Not tested on Windows.
This commit is contained in:
parent
b4558ec274
commit
377a98f45e
1 changed files with 32 additions and 12 deletions
|
@ -1,7 +1,10 @@
|
||||||
(ns leiningen.javac
|
(ns leiningen.javac
|
||||||
"Compile Java source files."
|
"Compile Java source files."
|
||||||
(:require [leiningen.classpath :as classpath]
|
(:require [leiningen.classpath :as classpath]
|
||||||
[leiningen.core.main :as main]
|
[leiningen.core
|
||||||
|
[main :as main]
|
||||||
|
[eval :as eval]
|
||||||
|
[project :as project]]
|
||||||
[clojure.java.io :as io])
|
[clojure.java.io :as io])
|
||||||
(:import java.io.File
|
(:import java.io.File
|
||||||
javax.tools.ToolProvider))
|
javax.tools.ToolProvider))
|
||||||
|
@ -66,24 +69,41 @@
|
||||||
"-d" (:compile-path project)]
|
"-d" (:compile-path project)]
|
||||||
files)))
|
files)))
|
||||||
|
|
||||||
|
;; Pure java projects will not have Clojure on the classpath. As such, we need
|
||||||
|
;; to put it there ourselves for compiling.
|
||||||
|
(def subprocess-profile
|
||||||
|
{:dependencies [['org.clojure/clojure (clojure-version)]]
|
||||||
|
:eval-in :subprocess})
|
||||||
|
|
||||||
;; We can't really control what is printed here. We're just going to
|
;; We can't really control what is printed here. We're just going to
|
||||||
;; allow `.run` to attach in, out, and err to the standard streams. This
|
;; allow `.run` to attach in, out, and err to the standard streams. This
|
||||||
;; should have the effect of compile errors being printed. javac doesn't
|
;; should have the effect of compile errors being printed. javac doesn't
|
||||||
;; actually output any compilation info unless it has to (for an error)
|
;; actually output any compilation info unless it has to (for an error)
|
||||||
;; or you make it do so with `-verbose`.
|
;; or you make it do so with `-verbose`.
|
||||||
(defn- run-javac-task
|
(defn- run-javac-subprocess
|
||||||
"Run javac to compile all source files in the project."
|
"Run javac to compile all source files in the project. The compilation is run
|
||||||
|
in a subprocess to avoid it from adding the leiningen standalone to the
|
||||||
|
classpath, as leiningen adds itself to the classpath through the
|
||||||
|
bootclasspath."
|
||||||
[project args]
|
[project args]
|
||||||
(let [compile-path (:compile-path project)
|
(let [compile-path (:compile-path project)
|
||||||
files (stale-java-sources (:java-source-paths project) compile-path)]
|
files (stale-java-sources (:java-source-paths project) compile-path)
|
||||||
|
javac-opts (vec (javac-options project files args))
|
||||||
|
form `(do (println "Compiling" ~(count files)
|
||||||
|
"source files to" ~compile-path)
|
||||||
|
(.mkdirs (io/file ~compile-path))
|
||||||
|
(when-not (zero? (.run (ToolProvider/getSystemJavaCompiler)
|
||||||
|
nil nil nil
|
||||||
|
(into-array String ~javac-opts)))
|
||||||
|
(.println System/err
|
||||||
|
"Compilation of Java sources(lein javac) failed.")
|
||||||
|
(System/exit 1)))] ; Ok here, as we're in a subprocess.
|
||||||
(when (seq files)
|
(when (seq files)
|
||||||
(if-let [compiler (ToolProvider/getSystemJavaCompiler)]
|
(if (ToolProvider/getSystemJavaCompiler)
|
||||||
(do
|
;; compiler will be available from subprocess if available from here
|
||||||
(main/info "Compiling" (count files) "source files to" compile-path)
|
(eval/eval-in
|
||||||
(.mkdirs (io/file compile-path))
|
(project/merge-profiles project [subprocess-profile])
|
||||||
(when-not (zero? (.run compiler nil nil nil
|
form)
|
||||||
(javac-options project files args)))
|
|
||||||
(main/abort "Compilation of Java sources (lein javac) failed.")))
|
|
||||||
(main/abort "lein-javac: system java compiler not found;"
|
(main/abort "lein-javac: system java compiler not found;"
|
||||||
"Be sure to use java from a JDK\nrather than a JRE by"
|
"Be sure to use java from a JDK\nrather than a JRE by"
|
||||||
"either modifying PATH or setting JAVA_CMD.")))))
|
"either modifying PATH or setting JAVA_CMD.")))))
|
||||||
|
@ -99,4 +119,4 @@ Like the compile and deps tasks, this should be invoked automatically when
|
||||||
needed and shouldn't ever need to be run by hand. By default it is called before
|
needed and shouldn't ever need to be run by hand. By default it is called before
|
||||||
compilation of Clojure source; change :prep-tasks to alter this."
|
compilation of Clojure source; change :prep-tasks to alter this."
|
||||||
[project & args]
|
[project & args]
|
||||||
(run-javac-task project args))
|
(run-javac-subprocess project args))
|
||||||
|
|
Loading…
Reference in a new issue