You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Leiningen编译的含JavaFX的Uberjar缺失运行时组件问题排查

问题:Clojure + JavaFX独立JAR运行报错:JavaFX runtime components missing

我有一个使用JavaFX 21.0.7的极简Clojure项目,仅包含一个文件,功能为显示带空面板的窗口,代码如下:

(ns choosechee.cheeboard.program
  (:gen-class
    :extends javafx.application.Application)
  (:import
    [javafx.application Application]
    [javafx.stage Stage]
    [javafx.scene Scene]
    [javafx.scene.layout Pane]))


(defn -main [& args]
  (Application/launch choosechee.cheeboard.program args))

(defn -start [this primaryStage]
  (doto primaryStage
    (.setScene (Scene. (Pane.) 300 250))
    (.show)))

项目配置文件project.clj内容:

(defproject choosechee.cheeboard "0.1.0-SNAPSHOT"
  :description "Placeholder"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.12.0"]
                 [org.openjfx/javafx-base "21.0.7"]
                 [org.openjfx/javafx-graphics "21.0.7"]
                 [org.openjfx/javafx-controls "21.0.7"]]
  :repl-options {:init-ns choosechee.cheeboard.program}
  :main choosechee.cheeboard.program
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

运行lein uberjar成功生成两个JAR包:choosechee.cheeboard-0.1.0-SNAPSHOT.jar和choosechee.cheeboard-0.1.0-SNAPSHOT-standalone.jar。我认为standalone包应包含JavaFX可独立运行,但执行时出现错误:

Error: JavaFX runtime components are missing, and are required to run this application

JAR包中似乎包含JavaFX类,不清楚缺失的运行时组件是什么,系统为Kubuntu 24.10,请问该如何解决?


解决方案
  • 问题根源:JavaFX依赖分为纯Java类(已打包进uberjar)和平台相关的本地原生库(如Linux下的.so文件)两类,原生库未被自动包含进uberjar,但JavaFX运行必须依赖这些组件。

  • 具体解决步骤:

    1. 添加平台专属JavaFX依赖
      JavaFX的Maven包需要指定对应平台的分类器,修改project.clj的:dependencies,替换原JavaFX依赖为Linux版本:

      :dependencies [[org.clojure/clojure "1.12.0"]
                     [org.openjfx/javafx-base "21.0.7" :classifier "linux"]
                     [org.openjfx/javafx-graphics "21.0.7" :classifier "linux"]
                     [org.openjfx/javafx-controls "21.0.7" :classifier "linux"]]
      

      若需跨平台,可通过Leiningen的profile区分:

      :profiles {:linux {:dependencies [[org.openjfx/javafx-base "21.0.7" :classifier "linux"]
                                        [org.openjfx/javafx-graphics "21.0.7" :classifier "linux"]
                                        [org.openjfx/javafx-controls "21.0.7" :classifier "linux"]]}
                 :uberjar {:aot :all}}
      

      打包时指定profile:lein with-profile linux uberjar

    2. 用插件处理原生库打包
      Leiningen默认不会将原生库放到uberjar的正确加载位置,添加插件自动处理:

      :plugins [[lein-native-deps "1.0.0"]]
      

      该插件会提取依赖中的原生库到uberjar的native目录,并在运行时自动加载。

    3. 手动指定模块路径运行
      若不想用插件,可手动指定JavaFX模块路径运行。找到本地Maven仓库中JavaFX原生库的所在目录,执行:

      java --module-path /path/to/javafx/libs --add-modules javafx.controls,javafx.graphics -jar choosechee.cheeboard-0.1.0-SNAPSHOT-standalone.jar
      
    4. 用jlink构建完全独立的JRE
      若需要无需额外依赖的可执行文件,使用jlink打包JRE、JavaFX模块和项目代码:

      • 确保安装JDK 21(包含jlink工具)
      • 生成编译后的类文件:lein compile
      • 执行jlink命令:
        jlink --module-path $JAVA_HOME/jmods:/path/to/javafx/jmods:target/classes \
              --add-modules choosechee.cheeboard,javafx.controls,javafx.graphics \
              --output target/jre \
              --launcher app=choosechee.cheeboard/choosechee.cheeboard.program
        
      • 之后直接运行target/jre/bin/app即可启动程序。

内容的提问来源于stack exchange,提问作者Choosechee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 05:54:55