如何在leiningen的Clojure代码之后编译Java代码

如何在leiningen的Clojure代码之后编译Java代码,java,clojure,compilation,leiningen,gen-class,Java,Clojure,Compilation,Leiningen,Gen Class,在我的Leiningen项目中: (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/lega

在我的Leiningen项目中:

(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"]
  )
我正在使用gen类生成Java类:

(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))
我想在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"));
    }
}
启动
lein compile
会引发以下错误:

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
在我看来,在编译Java代码期间(这里:
TestGenClassTest
),类不可用。我通常做的是

  • 注释掉使用gen类生成的类的那些部分(此处
    TestGenClass
  • 运行
    lein compile
    (生成类文件)
  • 然后再把注释掉的代码放进去
  • 然后再次运行
    lein compile
  • 我确信有一种更好的方法,可以使所有手动步骤变得多余。

    让我再次向您介绍,尤其是这一部分:


    默认情况下,Leiningen正在执行
    javac
    ,然后执行
    compile
    。您可以实现的功能还包括
    compile
    ->
    javac
    ->
    compile

    要添加预编译步骤。运行预编译…然后就可以开始了

  • 将您的接口放入一个单独的文件路径
    src/main/pre/interface/clojure

  • 将以下内容添加到
    :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] } })
    

  • 然后,您可以使用profile precomp compile运行
    lein,然后
    lein test
    应该可以运行这里是一个示例项目。clj来自clojure代码依赖于Java代码的项目,AOT进行编译,以便可以对Java代码进行上游测试。这里我们有三层编译依赖关系:Java→ Clojure→ Java及其所有功能:

    (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
    
    上游java测试代码在编译和运行时会找到它所需要的一切。(本示例所来自的项目中的上游java层恰好是java测试代码,但这里没有特定于测试代码的内容,当您希望java代码使用gen类生成的clojure代码时,该技术应该通用)

    原始问题的代码只是缺少这里显示的概要文件和别名部分,它们告诉leiningen在clojure编译之后如何编译Java。这是必要的,因为默认情况下,在leiningen的当前版本中,leiningen在编译clojure之前编译Java;它不会尝试跨语言对源文件的编译进行排序

    因此,在这个解决方案中,我们通过使用别名,将另一个编译步骤添加为单独的leiningen任务。有了这个配置,我们只需要发布
    leinjava测试
    ,它首先编译clojure,然后是上游java层。瞧


    另外,我们甚至可以覆盖lein的编译任务,而不是添加新任务,但这对我来说并不值得…

    那么,首先使用javac编译接口
    com.stackoverflow.clojure.TestGenClassInterface
    (如果需要)然后编译实现接口的clojure部分的配置文件会是什么样子呢(
    com.stackoverflow.clojure.TestGenClass
    )然后编译Java主程序?是两个附加配置文件,还是一个配置文件?是使用path语句调用正确的编译器吗?不,据我所知,正确的编译器不会从path语句自动推断出来。