Как скомпилировать код Java после кода Clojure в leiningen

В моем проекте Leiningen:

(defproject com.stackru.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.stackru.clojure.testGenClass]
  :source-paths      ["src/main/clojure"]
  :java-source-paths ["src/main/java"]
  :test-paths        ["src/test/clojure"]
  :java-test-paths   ["src/test/java"]
  )

Я генерирую Java-классы с помощью gen-class:

(ns com.stackru.clojure.testGenClass
  (:gen-class
     :name com.stackru.clojure.TestGenClass
     :implements [com.stackru.clojure.TestGenClassInterface]
     :prefix "java-"))

(def ^:private pre "START: ")

(defn java-addToString [this text post]
  (str pre text post))

который я хочу использовать в Java:

package com.stackru.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/stackru/clojure/TestGenClassTest.java:9: error: cannot find symbol
        TestGenClassInterface gc = new TestGenClass();
                                       ^
  symbol:   class TestGenClass
  location: class TestGenClassTest
1 error

Мне кажется, что во время компиляции Java-кода (здесь: TestGenClassTest) Класс недоступен. То, что я обычно делал, это

  1. закомментирование тех частей, которые используют сгенерированный классом gen-класса (здесь TestGenClass)
  2. бежать lein compile (создать файл класса)
  3. затем снова взяв закомментированный код
  4. и беги lein compile снова.

Я уверен, что есть лучший способ, который делает все ручные шаги избыточными.

3 ответа

Вы хотите добавить шаг предварительной компиляции. Запустите прекомпиляцию... тогда все готово.

  1. Поместите ваш интерфейс в отдельный путь к файлу src/main/pre/interface/clojure

  2. добавить ниже к :profiles

    (defproject com.stackru.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] } })
    

Тогда вы можете запустить lein with-profile precomp compile после которого lein test должно сработать

Вот пример project.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. закрытый код).

В исходном коде вопроса просто отсутствуют показанные здесь части профиля и псевдонима, которые сообщают leiningen, как компилировать Java после компиляции clojure. Это необходимо, потому что по умолчанию в текущих версиях leiningen leiningen компилирует Java прежде, чем компилирует clojure; он не пытается упорядочить компиляцию исходных файлов на разных языках.

Таким образом, в этом решении мы добавляем еще один этап компиляции как отдельную задачу leiningen, используя псевдоним. Имея эту конфигурацию, нам нужно только выдать lein java-tests который сначала компилирует clojure, а затем слой Java верхнего уровня. Вуаля.

PS Может быть, мы даже можем переопределить задачу компиляции lein, а не добавить новую задачу, но это не стоило мне играть...

Позвольте мне еще раз отослать вас к проектам Polyglot (Clojure, Java) с Leiningen, и особенно к этой части: чередование шагов компиляции.

По умолчанию Лейнинген исполняет javac а потом compile, Чего вы также можете достичь compile -> javac -> compile,

Другие вопросы по тегам