在CalcFX with SceneBuilder Event中,已完成可執行的abcl-javafx ASDF系統。本文示範如何使用ABCL contrib提供的asdf-jar將系統打包成JAR,再從JAR載入系統並確認資源可正常讀取。
專案結構如下:
abcl-javafx/
├── abcl-javafx.asd
├── package.lisp
├── constants.lisp
├── utils.lisp
├── main.lisp
├── pack-asdf.lisp
├── run-jar.lisp
├── run-system.lisp
├── scenes/
│ └── calcFX.lisp
└── res/
├── CalcFX.fxml
├── calcfx.css
├── style.css
└── icon32x32.png
系統定義檔abcl-javafx.asd如下:
(defsystem "abcl-javafx"
:description "Create GUI Application with ABCL and JavaFX"
:version "0.0.1"
:author "lagagain <lagagain@email.com>"
:licence "MIT"
:depends-on (#:jss)
:serial t
:components ((:file "package")
(:file "constants")
(:file "utils")
(:module "scenes"
:components
((:file "calcFX")))
(:file "main")
(:module "res"
:components
((:static-file "style.css")
(:static-file "CalcFX.fxml")
(:static-file "calcfx.css")
(:static-file "icon32x32.png")))))
在utils.lisp中,get-system-resource使用asdf/system:system-relative-pathname取得系統資源路徑。系統從JAR載入時,路徑已經是jar:file: URI,可以直接使用;從一般檔案系統載入時,則透過java.io.File.toURI()轉成JavaFX可用的URI:
(defun get-system-resource (resource-path)
(let ((p (namestring (asdf/system:system-relative-pathname
:abcl-javafx
resource-path))))
(if (uiop:string-prefix-p "jar:file:" p)
p
(chain (new "java.io.File" p)
"toURI"
"toString"))))
打包前先使用提供的run-system.lisp測試ASDF系統:
(require "asdf")
(require :abcl-contrib)
(push #P"./" asdf:*central-registry*)
(asdf:load-system "abcl-javafx")
在專案根目錄執行:
abcl --noinform --load run-system.lisp
先確認視窗能正常顯示,再關閉程式。
asdf-jar不是CLHS的標準功能,而是ABCL contrib提供的ASDF擴充:
(require :abcl-contrib)
(require :abcl-asdf)
(asdf:make :asdf-jar) ;; 載入 asdf-jar 功能
專案將打包流程放在pack-asdf.lisp,內容如下:
(require :abcl-contrib)
(require :asdf)
(require :abcl-asdf)
(asdf:make :asdf-jar)
(push #P"./" asdf:*central-registry*)
(asdf-jar:package :abcl-javafx
:verbose t
:out "."
:fasls t
:recursive nil)
在專案根目錄執行:
abcl --noinform --load pack-asdf.lisp --eval '(quit)'
:out設定輸出位置,設定成"."表示把輸出JAR放在目前目錄;也可以指定輸出資料夾,例如:
(asdf-jar:package :abcl-javafx
:verbose t
:out "dist"
:fasls t
:recursive nil)
完成後應該會得到類似abcl-javafx-0.0.1.jar的檔案。實際檔名可能依系統名稱和版本號略有不同,以命令列輸出的檔名為準。
打包後可以用jar -tf查看JAR內的檔案:
jar -tf abcl-javafx-0.0.1.jar
我得到的結果如下:
abcl-javafx/
abcl-javafx/scenes/
abcl-javafx/scenes/calcFX.abcl
abcl-javafx/abcl-javafx.asd
abcl-javafx/main.lisp
abcl-javafx/constants.lisp
abcl-javafx/utils.abcl
abcl-javafx/package.abcl
abcl-javafx/package.lisp
abcl-javafx/res/
abcl-javafx/res/calcfx.css
abcl-javafx/utils.lisp
abcl-javafx/constants.abcl
abcl-javafx/res/style.css
abcl-javafx/res/CalcFX.fxml
abcl-javafx/res/icon32x32.png
abcl-javafx/scenes/calcFX.lisp
abcl-javafx/main.abcl
通常可以看到ASDF系統描述、Lisp原始檔、編譯後的.abcl檔案,以及被宣告為:static-file的資源。
打包完成後,可以讓ABCL載入JAR中的ASDF系統。專案的run-jar.lisp將JAR內的系統路徑加入asdf:*central-registry*,再呼叫asdf:load-system:
(require :asdf)
(require :abcl-contrib)
(push "jar:file:./abcl-javafx-0.0.1.jar!/abcl-javafx/" asdf:*central-registry*)
(asdf:load-system :abcl-javafx)
執行載入腳本:
abcl --noinform --load run-jar.lisp
載入後應能啟動CalcFX,並從JAR讀取FXML、CSS和圖示。至此已完成ASDF系統的JAR打包與載入驗證;不過要直接提供給一般使用者,使用jlink或jpackage,建立包含執行環境的應用程式,再進行分發可能更好。