Leiningen 不会从 uberjar 中排除命名空间

Posted

技术标签:

【中文标题】Leiningen 不会从 uberjar 中排除命名空间【英文标题】:Leiningen wont exclude namespaces from uberjar 【发布时间】:2021-12-20 22:33:27 【问题描述】:

我有一个项目,我希望代码的某些部分能够在本地环境中运行,而其他部分依赖于仅在远程环境中运行的库。例如

src/app/core.clj <- can run anywhere
src/app/sandbox/remote_only.clj <- depnds on libs that only function in remote environ

src/app/core.clj 在哪里

(ns app.core
  (:gen-class))
(defn -main [] (println "Hello, World!"))

src/app/sandbox/remote_only.clj

(ns app.sandbox.remote-only
  (:require
    [uncomplicate.commons.core :refer [with-release]]
    [uncomplicate.neanderthal
     [native :refer [dv dge]]
     [core :refer [mv mv!]]]))

我希望能够uberjar 并在我的本地计算机上运行位于core.clj 中的代码,而不需要拉入remote_only.clj,这将导致程序在本地失败。根据文档,Leiningen 应该能够使用配置文件和 uberjar 排除来完成此操作,例如:

(defproject app "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.10.1"]]
  :profiles :uberjar :main app.core
                       :init-ns app.core
                       :aot :all
             :remote :init-ns app.sandbox.remote_only
                      :dependencies [[uncomplicate/neanderthal "0.43.1"]] ; these deps will fail locally
  :uberjar-exclusions [#".*sandbox.*"]
  :repl-options :init-ns app.core)

在这里编译 uberjar 会导致:

❯ lein uberjar
Compiling app.core
Compiling app.sandbox.remote-only
Syntax error macroexpanding at (remote_only.clj:1:1).
Execution error (FileNotFoundException) at app.sandbox.remote-only/loading (remote_only.clj:1).
Could not locate uncomplicate/commons/core__init.class, uncomplicate/commons/core.clj or uncomplicate/commons/core.cljc on classpath.

因此,它明确地试图编译被明确排除的类。

我认为可以通过从:aot 编译中删除:all 标记来避免此类问题。例如:

(defproject app "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.10.1"]]
  :profiles :uberjar :main app.core
                       :init-ns app.core
                       :aot [app.core]
             :remote :init-ns app.sandbox.remote_only
                      :dependencies [[uncomplicate/neanderthal "0.43.1"]] ; these deps will fail locally
  :uberjar-exclusions [#".*sandbox.*"]
  :repl-options :init-ns app.core)

导致其他问题:

❯ lein uberjar
Compiling app.core
Created /Users/warrenronsiek/Projects/app/target/app-0.1.0-SNAPSHOT.jar
Created /Users/warrenronsiek/Projects/app/target/app-0.1.0-SNAPSHOT-standalone.jar
~/Projects/app                                                                                                                                                                                              5s 15:47:37
❯ java -jar ./target/app-0.1.0-SNAPSHOT.jar 
Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var

我尝试过各种:exclusions:jar-exclusions 和正则表达式。这个问题的变体已被多次询问(1,2)没有任何效果。

如何让 Leiningen 编译 uberjars 并忽略指定的文件?

【问题讨论】:

【参考方案1】:

我还没有尝试过这种带有“排除”功能的特殊设置。

一种解决方法是为应用的“本地”和“远程”部分创建子项目,然后可以由更高级别的“总”项目使用。

app
  app-local
  app-remote

这 3 个中的每一个都是一个单独的 Lein 项目。 app-localapp-remote 可以单独开发。然后使用的***app 项目将两个子项目作为依赖项(因此仅适用于远程/完整环境)。

Lein 功能checkouts 允许您同时开发所有 3 个 repos,这是一个巨大的帮助。它比使用lein install 的替代方法快得多,后者速度慢、需要手动操作、重复且容易出错。


附:您是否尝试过使用lein jar 而不是lein uberjar

【讨论】:

【参考方案2】:

您将:aot :all 更改为:aot [app.core] 是正确的,但是当您尝试运行JAR 时,您运行的是 版本而不是整个应用程序版本:

java -jar ./target/app-0.1.0-SNAPSHOT.jar 

这不包括 Clojure 或任何依赖项。你想要:

java -jar ./target/app-0.1.0-SNAPSHOT-standalone.jar 

【讨论】:

以上是关于Leiningen 不会从 uberjar 中排除命名空间的主要内容,如果未能解决你的问题,请参考以下文章

使用 ProGuard 混淆 clojure uberjars

leiningen - 如何为本地 jar 添加依赖项?

Java 和 Clojure 与 Leiningen

如何排除打包为应用程序的 uber jar 的 jar 文件

SonarQube MSBuild Scanner 不会从分析中排除文件

用leiningen来运行和打包clojure项目