Reputation: 4631
In my Leiningen project:
(defproject com.stackoverflow.clojure/tests "0.1.0-SNAPSHOT"
:description "Tests of Clojure test-framework."
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[instaparse "1.3.4"]]
:aot [com.stackoverflow.clojure.testGenClass]
:source-paths ["src/main/clojure"]
:java-source-paths ["src/main/java"]
:test-paths ["src/test/clojure"]
:java-test-paths ["src/test/java"]
)
I'm generating Java-classes with gen-class:
(ns com.stackoverflow.clojure.testGenClass
(:gen-class
:name com.stackoverflow.clojure.TestGenClass
:implements [com.stackoverflow.clojure.TestGenClassInterface]
:prefix "java-"))
(def ^:private pre "START: ")
(defn java-addToString [this text post]
(str pre text post))
which I want to use in Java:
package com.stackoverflow.clojure;
public class TestGenClassTest {
private TestGenClassTest() {
}
public static void main(String[] args) {
TestGenClassInterface gc = new TestGenClass();
System.out.println(gc.addToString("Called from Java!", " :END"));
}
}
Starting lein compile
throws the following error:
Compiling 4 source files to /home/eddy/workspace/TestSkripts/target/classes
/home/eddy/workspace/TestSkripts/src/main/java/com/stackoverflow/clojure/TestGenClassTest.java:9: error: cannot find symbol
TestGenClassInterface gc = new TestGenClass();
^
symbol: class TestGenClass
location: class TestGenClassTest
1 error
It seems to me, that during compilation of the Java-code (here: TestGenClassTest
) the Class is not available. What I usually did is
TestGenClass
)lein compile
(to generate the class-file)lein compile
again.I' sure there is a better way, that makes all manual steps redundat.
Upvotes: 6
Views: 2022
Reputation: 13686
Here is a sample project.clj from a project where the clojure code relies on Java code, and AOT compiles so that it is available to upstream tests Java code. So here we have three layers of compilation dependencies: Java → Clojure → Java and it all works:
(defproject myproject "0.1.0-SNAPSHOT"
:min-lein-version "2.0.0"
:source-paths ["src/clojure"]/
:java-source-paths ["src/java"]
:javac-options ["-target" "1.8" "-source" "1.8"]
:dependencies [[org.clojure/clojure "1.8.0"]]
:aot [the class that java-test needs]
:profiles {:java-tests-compile
{:java-source-paths ["src/java-test"]}}
:aliases {
"java-tests" ["do" "compile," "with-profile" "java-tests-compile" "javac," "run" "-m" "myorg.myProject.java-test-code"]
"all-tests" ["do" "test," "java-tests"]
})
; https://github.com/technomancy/leiningen/issues/847#issuecomment-289943710
The upstream java tests code finds all it needs when it compiles and runs. (The upstream java layer in the project where this sample comes from just happens to be java tests code, but there's nothing here that is specific to tests code, the technique should work generically, when you want Java code to use your gen-class generated clojure code).
The original question's code is just missing the profile and alias parts shown here, that tell leiningen how to compile the Java, after clojure compilation. This is needed because by default, in the current versions of leiningen, leiningen compiles Java before it compiles clojure; it does not attempt to order the compilation of source files across languages.
So in this solution, we add another compilation step as a separate leiningen task, through the use of an alias. Having this configuration, we only need to issue lein java-tests
which first compiles clojure, then the upper-stream Java layer. Voila.
P.S. maybe we can even override lein's compile task rather than add a new task, but that was not worth the play for me...
Upvotes: 0
Reputation: 2053
You want to add a pre-compilation step. Run the pre-compile ...then you're good to go.
Put your interface into a seperate file path src/main/pre/interface/clojure
add the below to :profiles
(defproject com.stackoverflow.clojure/tests "0.1.0-SNAPSHOT"
:description "Tests of Clojure test-framework."
:url "http://example.com/FIXME"
:dependencies [[org.clojure/clojure "1.6.0"]
[instaparse "1.3.4"]]
:source-paths ["src/main/clojure"]
:java-source-paths ["src/main/java"]
:test-paths ["src/test/clojure"]
:java-test-paths ["src/test/java"]
:profiles { :precomp { :source-paths ["src/main/pre/interface/clojure"]
:aot [parser.ast] } })
Then you can run lein with-profile precomp compile
after which lein test
should work
Upvotes: 1
Reputation: 20245
Let me refer you again to Polyglot (Clojure, Java) Projects With Leiningen, and particularly this part: Interleaving Compilation Steps.
Be default, Leiningen is executing javac
and then compile
. What you can achieve also compile
-> javac
-> compile
.
Upvotes: 0