Lein 使用协议编译项目
Lein compile project with protocols
我有一个包含以下 ns 的项目:
- processor.bus <- 总线操作的通用协议
- processor.core <- 主要 class 到 运行
- processor.pubsub <- 具体总线方法
在 processor.pubsub 我有以下内容:
(ns processor.pubsub
(:gen-class))
(defrecord PubsubBus [client])
; + other stuff related to this implementation
在 processor.bus 我有:
(ns tiptop.processor.bus
(:gen-class)
(:import [processor.pubsub PubsubBus]))
(defprotocol SendToBus
(send-line! [self json]))
(extend-type PubsubBus
SendToBus
....)
Lein 没有按正确顺序编译命名空间的问题。我收到以下错误:
$ lein compile
Compiling user
Compiling processor.auth
Compiling processor.bus
java.lang.ClassNotFoundException: processor.pubsub.PubsubBus, compiling:(bus.clj:1:1)
Exception in thread "main" java.lang.ClassNotFoundException: processor.pubsub.PubsubBus, compiling:(bus.clj:1:1)
请注意,它会尝试按字母顺序(auth -> bus -> pubsub)编译我的 ns,而不是依赖顺序。
当然我可以在pubsub.clj之前预编译,比如:
$ lein compile processor.pubsub
$ lein compile processor.bus
$ lein compile
但它似乎不太适合我。如果我有更多这样的依赖名称空间怎么办?
我如何告诉 Lein 它应该以什么顺序编译我的命名空间?或者我可能在 project.clj
中缺少要配置的内容?如果重要的话我有 :aot :all
Leiningen 不会做任何事情来确定名称空间依赖性 - 它只是编译您告诉它的名称空间。它是 Clojure 编译器,它通过 require
(和过时的 use
)内置函数处理名称空间依赖性。
在这种情况下,您需要先 :require
定义生成的 class 的命名空间,然后才能将其导入。否则,您将依赖导入的 class 作为其他操作的副作用出现在 class 路径上(加载在 REPL 中定义它的命名空间,之前的 lein compile
命令等)。在命名空间定义中添加显式 :require
可确保 class 在导入之前定义:
(ns processor.bus
(:gen-class)
(:require [processor.pubsub])
(:import [processor.pubsub PubsubBus]))
一些其他注意事项:
- 我怀疑
:gen-class
在这些名称空间声明中是否按照您的想法行事。它不会导致为这些命名空间中定义的协议和记录写入 class 个文件;这就是 Leiningen project.clj
中 :aot
键的作用。此处使用的 :gen-class
标志将导致生成名为 processor.bus
和 processor.pubsub
的 classes。
- 在定义协议的同一个命名空间中,通过
extend-type
指定的具体记录类型的协议实现细节很少见。 extend-type
的典型用例是扩展您的协议以使用您无法控制的类型,例如 Clojure 内置的或第三方库中定义的类型。当协议和记录在同一个项目中定义时,更常见的是将协议实现内联定义为 defrecord
主体的一部分。
我有一个包含以下 ns 的项目:
- processor.bus <- 总线操作的通用协议
- processor.core <- 主要 class 到 运行
- processor.pubsub <- 具体总线方法
在 processor.pubsub 我有以下内容:
(ns processor.pubsub
(:gen-class))
(defrecord PubsubBus [client])
; + other stuff related to this implementation
在 processor.bus 我有:
(ns tiptop.processor.bus
(:gen-class)
(:import [processor.pubsub PubsubBus]))
(defprotocol SendToBus
(send-line! [self json]))
(extend-type PubsubBus
SendToBus
....)
Lein 没有按正确顺序编译命名空间的问题。我收到以下错误:
$ lein compile
Compiling user
Compiling processor.auth
Compiling processor.bus
java.lang.ClassNotFoundException: processor.pubsub.PubsubBus, compiling:(bus.clj:1:1)
Exception in thread "main" java.lang.ClassNotFoundException: processor.pubsub.PubsubBus, compiling:(bus.clj:1:1)
请注意,它会尝试按字母顺序(auth -> bus -> pubsub)编译我的 ns,而不是依赖顺序。
当然我可以在pubsub.clj之前预编译,比如:
$ lein compile processor.pubsub
$ lein compile processor.bus
$ lein compile
但它似乎不太适合我。如果我有更多这样的依赖名称空间怎么办?
我如何告诉 Lein 它应该以什么顺序编译我的命名空间?或者我可能在 project.clj
中缺少要配置的内容?如果重要的话我有 :aot :all
Leiningen 不会做任何事情来确定名称空间依赖性 - 它只是编译您告诉它的名称空间。它是 Clojure 编译器,它通过 require
(和过时的 use
)内置函数处理名称空间依赖性。
在这种情况下,您需要先 :require
定义生成的 class 的命名空间,然后才能将其导入。否则,您将依赖导入的 class 作为其他操作的副作用出现在 class 路径上(加载在 REPL 中定义它的命名空间,之前的 lein compile
命令等)。在命名空间定义中添加显式 :require
可确保 class 在导入之前定义:
(ns processor.bus
(:gen-class)
(:require [processor.pubsub])
(:import [processor.pubsub PubsubBus]))
一些其他注意事项:
- 我怀疑
:gen-class
在这些名称空间声明中是否按照您的想法行事。它不会导致为这些命名空间中定义的协议和记录写入 class 个文件;这就是 Leiningenproject.clj
中:aot
键的作用。此处使用的:gen-class
标志将导致生成名为processor.bus
和processor.pubsub
的 classes。 - 在定义协议的同一个命名空间中,通过
extend-type
指定的具体记录类型的协议实现细节很少见。extend-type
的典型用例是扩展您的协议以使用您无法控制的类型,例如 Clojure 内置的或第三方库中定义的类型。当协议和记录在同一个项目中定义时,更常见的是将协议实现内联定义为defrecord
主体的一部分。