說明,最近比較忙,沒有太多時間更新blog,請各位朋友諒解.
尋找俺的朋友,可以gtalk : litaocheng[at]gmail.com 或者 twitter : @litaocheng
這篇文章,應該是我寫的最久的一篇,請各位多實踐.
reltool使用指南
Author: | litaocheng |
---|---|
Mail: | [email protected] |
Revision: | 1 |
Date: | 2009.10.28 |
目錄
1 概述
reltool 是 Erlang 提供的 release 管理工具. 我們依據 Erlang/OTP 開發的 application, 最後需要發佈,這時需要使用 reltool 幫我們生成最終的 release, 也稱爲 target system. 同時 reltool 可以分析 application 的依賴關係,幫助我們正確的發佈應用.
reltool 包括一個基於 wx 的 GUI 前端(wxWidgets erlang bind), 其可以用來查看 application 的依賴關係,可以查看模塊的依賴關係,可以查看源代碼. reltool 也提供使用命令來生成自定義的發佈包.
1.1 適用範圍和目的
本文檔主要介紹如何使用 reltool, reltool 爲 Erlang/OTP 開發環境的一部分. 本文假設讀者對Erlang相關開發比較熟悉,瞭解 Eralng/OTP 開發規範. Erlang/OTP 要求R13B02及以上版本.
1.2 瞭解更多內容
可以通過下列相關文檔瞭解更多 Erlang/OTP 開發相關信息
- reltool 參考手冊
- reltool user guide
- Erlang/OTP System Principles
- Erlang/OTP Design Principles
- 圖書 Programming Erlang: Software for a concurrent World (2007)
2 使用
前面講過, reltool 提供 GUI 和命令兩種交互方式, 本章首先簡單的介紹GUI界面相關內容, 重點是使用命令生成 release, 發佈自己的應用. 之所以重點介紹命令方式,主要基於兩個因素:
- 命令方式是基礎, GUI 只是提供了一個界面封裝, 本質還是調用的相關的命令
- GUI 目前功能還不是很完整,很多操作不支持
2.1 GUI 相關
2.1.1 System Window
通過調用 reltool:start/0,1 啓動 reltool, reltool 在啓動時,首先掃描所有的 application 和 module, 分析其相互依賴關係.隨後啓動 system window.
system window 包含四個page window (tabs):
- Libraries
- System settings
- Applications
- Releases
點擊對應的tag, 可以切換page.
system window 如下圖:
Librarie 窗口如下圖
在 library 窗口, 我們設置 reltool 將要使用的代碼. 本頁面以 tree 的形式來組織內容, 你可以點擊每行前面的標記摺疊/展開對應內容.
Library directories, Escript files 都可以進行操作. 選擇對應的項目,按住鼠標右鍵顯示對應的菜單, 移動鼠標選擇對應的菜單項,釋放鼠標右鍵.
雙擊 lib 下某個 application, 可以顯示對應的 application window.
通過 reltool GUI, 我們還可以查看很多 windows, 如 aplication 依賴圖:
源代碼窗口:
2.1.2 System Settings
Avaiable 中顯示的所有可用的 applications. 在 system page 中,我們可以設置全局的 application 包含規則, 即 incl_cond.
incl_cond 包含三種策略,我們在介紹命令方式創建release時,會詳細介紹.
3 用命令生成relase(target system)
先說一下爲自己的 application 生成 release 的步驟:
- 依據 Erlang/OTP 項目完成, 測試通過
- 定義 reltool 使用的關於最終 release 的各種配置參數 Config
- reltool:start_server(Config) 啓動 reltool
- reltool:get_target_spec/1 獲取根據 Config 產生的用來創建 target system 的一系列"動作"(Spec)
- reltool:eval_target_spec/3 根據 Spec 生成 target system
- 書寫輔助的腳本,用來生成最終的安裝包(可以爲tar包,或者zip等)
我們假設第1步,您已經完成.
生成 target system 的重點就是 config 的設置了, 讓我們詳細的描述一下 reltool 手冊中各項 config 參數.
config 可以大體分爲4種類型:
- 基本配置
- sys 配置
- app 配置
- mod 配置
其中,很多配置信息在 sys, application, mod 三個等級中均會出現,其關係爲: mod > app > sys, 即 mod 配置覆蓋 app 配置, app 配置覆蓋 sys 配置.
3.1 基本配置
-
root_dir
Reltool 根據當前開發環境產生 target system, 因此 config 信息中勢必包含 erlang root_dir 信息.
root_dir 指明 erlang 的當前安裝目錄(比如在 ubuntu 9.04 下, 默認爲 /usr/local/lib/erlang).本選項可以不用指定, reltool 會自動設置 root_dir.
-
lib_dirs
除卻 $ERL_LIB 外, 指定附加的 library 目錄. 主要用來指定非 Erlang/OTP 正式發佈版本中的 application 或 library.如第三方 library, 或我們自己的 application.
3.2 sys 配置
-
erts
指定 erts application 信息, 具體的字段參考後面介紹的 app 配置.
-
escript
escript 腳本配置信息, 包含 escript 文件,以及對應的配置信息
-
app
target system 中包含的 app 信息. 比如所有的 release 都要包含 kernel, stdlib, 具體的app的相關配置,輕參考後面介紹的 app level 配置
-
mod_cond
設置 module 的包含策略. 其包含多種方式:
- all - 表示如果某個 app 被包含,那麼其包含的所有模塊全部被包含. 假設 app 名爲 demoapp, all 不僅包含 demoapp/ebin 下的所有模塊, 同時 demoapp.app 中 modules 字段描述的所有模塊也將被包括(默認)
- ebin - 表示 ebin 目錄下所有的模塊,以及相關的模塊會被包含
- app - 表示 .app 描述文件,以及相關的模塊會被包含
- derived - 表示被其他包含的模塊用到的相關模塊會被包含
此處配置的 mod_cond 是 sys level 的配置, 控制所有的 app 中的 module 包含策略. 當然我們可以對這個信息, 在 app level 進行覆蓋.
-
incl_cond 設置 applicaion 以及 escript 的包含策略.
其包含3種類型:
- derived - 表示 包含 沒有明確設置 incl_cond, 同時被其他 application 直接或間接引用的application. (默認)
- include - 表示 包含 所有沒有明確設置 incl_cond 的application
- exclude - 表示 排除 排除沒有明確設置 incl_cond 的application
include 和 exclude 意義相反. 一個是包含沒有設置 incl_cond 的 apps, 一個是排除沒有設置 incl_cond 的 apps.
一般我們使用默認的 derived 選項,這樣保證所有相關的 application 均被包含, 不會出現 target system 中,某個模塊沒有定義的錯誤.我們可以通過前面 reltool GUI 部分介紹的 application 依賴關係圖 來了解 application 的交互相關信息.
-
boot_rel
指定 target system 中默認啓動項 (rel), 一個target system 中可能包含很多的 release(通過 rel 來指定)
-
rel
指定 rel 內容 (Release specific configuration), 每個 rel 定義會被映射成 rel, script 和 boot 文件,請參考 Erlang/OTP Design Principles Release
-
relocable
指定 target system 中erl 執行時自動檢測路徑相關信息({relocable, true}), 還是硬編碼指定路徑啓動({relocable, false}). 如果 relocable 爲 false, 那麼 target system 必須首先通過 reltool:install/2 進行安裝, 如果 relocable 爲 true, target system 移動到其他目錄時,仍然可以方便的運行. {relocable, true} (默認)
-
profile 指定 tareget system 的類型, 此選項主要影響:incl_sys_filters, excl_sys_filters, incl_app_filters 和 excl_app_filters. 不同的 profile 類型, 以上4個 filters 不同.
主要包含3種:
- development - 開發測試模式(默認)
- embedded - 嵌入式完整模式
- standalone - 單獨模式,不攜帶相關的可執行文件
在生成 target system 時, 實際上主要有兩個步驟:首先創建一個完整的文件候選列表,它包含儘可能多的文件; 隨後調用各種相關的 filter 定義,對結果進行過濾, 最後聲稱最終的 target system.
一般情況下,我們的target system 要是一個完整的可執行的系統,因此我們許要設置 profile 爲 embedded. (當然不設置 profile, 只是修改4個相關的 filter, 也可以達到我們想要的效果)
-
app_file
控制 app 的內容, 因爲有各種各樣的 filter, 因此最終的 target system 中包含的模塊,可能與 app 文件定義的模塊列表不一致, 本選項控制 app 的內容. 主要包含3種:
- keep - 將 app 直接拷貝到 target system 中(默認)
- strip - 依據 app 文件產生 target system 中的 app 文件, 並將未被包含的模塊從 app 文件中移出
- all - 依據 app 文件產生 tarege system 中的 app 文件, 同時所有的模塊將添加到 app 文件中, 如果某個應用沒有 app 文件,那麼會自動創建一個 app 文件.
-
debug_info
是否去除 beam 文件中的調試信息: keep 表示保持; strip 表示去除
-
incl_sys_filters
指定一個正則表達式列表,用來表示哪些系統文件可以出現在 target system 中. 如果某個系統文件想被包括, 那麼其必須滿足 incl_sys_filters 中的某個正則表達式, 同時不能滿足 excl_sys_filters 中的任何表達式.
比如:
{incl_sys_filters,["^bin","^erts","^lib","^releases"]},
表示 $ERL_ROOT 目錄下的 bin, erts, lib, releases 目錄均要包含.
incl_app_filters, excl_app_filters 同 sys 相關的 filters 含義大致相同,只是用來控制 application 的包含規則.
-
excl_sys_filters
指定一個正則表達式列表,表示哪些系統文件不可以出現在 target system 中. 默認 爲 [].
-
incl_app_filters
指定一個正則表達式列表,表示 application 中的哪些文件可以被包含. 如果某個文件想被包含,至少要滿足正則表達式列表中的一個表達式. 默認爲 [".*"], 如果設置爲 [], 那麼 application 中的任何文件都不會被包含.
-
excl_app_filters
指定一個正則表達式列表,表示 application 的哪些文件不可以出現在 target system 中. 默認 爲 [].
-
incl_archive_filters
指定 application 中哪些一級子目錄包含在壓縮包中(與包含正常的目錄對應), 通過一個正則表達式列表指定要包含在壓縮包中的一級子目錄. 默認爲 [".*"]
-
excl_archive_filters
指定一個正則表達式列表,指定 application 的哪些一級目錄不包含在壓縮包中. 如果某個目錄,匹配任何一個正則表達式,則不會包含在壓縮包中. 默認爲 ["^include$", "^priv$"]
-
archive_opts
創建壓縮包對應的參數,在 zip:create/3 中使用, 請參考 zip module, 默認 爲 [].
3.3 app 配置
-
vsn
指定要包含的 application 的版本, 因爲在系統中,可能存在同一應用的多個版本. 如果忽略,則使用最新版本.
-
mod
模塊相關的配置信息. 必須包含一個模塊名稱,以及其他可選的模塊配置(參照後面 mod 配置)
-
mod_cond - 同 sys level 的同名配置含義相同
-
incl_cond - 同上
-
debug_info - 同上
-
incl_app_filters - 同上
-
excl_app_filters - 同上
-
incl_archive_filters - 同上
-
excl_archive_filters - 同上
-
archive_opts - 同上
3.4 mod 配置
-
incl_cond
指示模塊是否被包含,其覆蓋 application 及 system 配置中的 incl_cond 信息.
其包含3個值:
- include - 表示本模塊將被包含
- exclude - 表示本模塊不被包含
- derived - 表示如果其他被包含的模塊引用本模塊,則本模塊被也被包含.
-
debug_info
同 app 配置中 debug_info 描述.
4 例子
最後是一個實例,我們爲 erlips (erlang ip service) 生成 target system.
config (erlips.config)如下:
{sys, [ {lib_dirs,["/home/litaocheng/erlang"]}, {boot_rel, "erlips"}, {rel, "erlips", "0.1", [kernel, stdlib, sasl, mochiweb, erlips]}, {relocatable, true}, {profile, embedded}, {app_file, keep}, {debug_info, strip}, {mod_cond, all}, {incl_cond, derived}, {incl_app_filters, ["^include", "^priv", "^ebin", "^src"]}, {excl_app_filters, []}, {incl_archive_filters,[]}, {excl_archive_filters,[".*"]}, {app, kernel, [{incl_cond, include}]}, {app, stdlib, [{incl_cond, include}]}, {app, sasl, [{incl_cond, include}]}, {app, erlips, [{incl_cond, include}, {incl_app_filters, [".*"]}, {excl_app_filters, ["^log", "^var", "^release"]}]}, {app, mochiweb, [{incl_cond, include}]}, {app, runtime_tools, [{incl_cond, include}]} ] }.
我們爲一個名叫 erlips 的 application 生成 target system.
隨後執行:
> {ok, Server} = reltool:start_server([{config, "erlips.config"}]). > {ok, Spec} = reltool:get_target_spec(Server). > RelDir = "target_dir". > file:make_dir(RelDir). > ok = reltool:eval_target_spec(Spec, code:root_dir(), RelDir). > zip:zip(RelDir ++ ".zip", [RelDir]). % 創建zip包
將生成的 zip 包拷貝到沒有安裝 Erlang 環境的電腦中, 解壓 zip 包, 隨後運行:
./bin/erl
則自動啓動 erlips 應用.
5 config type定義
下面爲 reltool 中各相關 config 的 type 定義(參考 reltool):
options() = [option()] option() = {config, config() | file()} | {trap_exit, bool()} | {wx_debug, term()} config() = {sys, [sys()]} sys() = {root_dir, root_dir()} | {lib_dirs, [lib_dir()]} | {profile, profile()} | {erts, app()} | {escript, escript_file(), [escript()]} | {app, app_name(), [app()]} | {mod_cond, mod_cond()} | {incl_cond, incl_cond()} | {boot_rel, boot_rel()} | {rel, rel_name(), rel_vsn(), [rel_app()]} | {relocatable, relocatable()} | {app_file, app_file()} | {debug_info, debug_info()} | {incl_sys_filters, incl_sys_filters()} | {excl_sys_filters, excl_sys_filters()} | {incl_app_filters, incl_app_filters()} | {excl_app_filters, excl_app_filters()} | {incl_archive_filters, incl_archive_filters()} | {excl_archive_filters, excl_archive_filters()} | {archive_opts, [archive_opt()]} app() = {vsn, app_vsn()} | {mod, mod_name(), mod()} | {mod_cond, mod_cond()} | {incl_cond, incl_cond()} | {debug_info, debug_info()} | {app_file, app_file()} | {incl_sys_filters, incl_sys_filters()} | {excl_sys_filters, excl_sys_filters()} | {incl_app_filters, incl_app_filters()} | {excl_app_filters, excl_app_filters()} | {incl_archive_filters, incl_archive_filters()} | {excl_archive_filters, excl_archive_filters()} | {archive_opts, [archive_opt()]} mod() = {vsn, app_vsn()} | {incl_cond, incl_cond()} | {debug_info, debug_info()} rel_app() = app_name() | {app_name(), app_type()} | {app_name(), [incl_app()]} | {app_name(), app_type(), [incl_app()]} app_name() = atom() app_type() = permanent | transient | temporary | load | none app_vsn() = string() archive_opt = zip_create_opt() boot_rel() = rel_name() app_file() = keep | strip | all debug_info() = keep | strip dir() = string() escript() = {incl_cond, incl_cond()} escript_file() = file() excl_app_filters() = regexps() excl_archive_filters() = regexps() excl_sys_filters() = regexps() file() = string() incl_app() = app_name() incl_app_filters() = regexps() incl_archive_filters() = regexps() incl_cond() = include | exclude | derived incl_sys_filters() = regexps() lib_dir() = dir() mod_cond() = all | app | ebin | derived | none mod_name() = atom() profile() = development | embedded | standalone re_regexp() = string() reason() = string() regexps() = [re_regexp()] | {add, [re_regexp()]} | {del, [re_regexp()]} rel_file() = term() rel_name() = string() rel_vsn() = string() relocatable = boolean() root_dir() = dir() script_file() = term() server() = server_pid() | options() server_pid() = pid() target_dir() = file()