Author: | litaocheng |
---|---|
Mail: | [email protected] |
Revision: | 1 |
Date: | 2009.10.28 |
目录
reltool 是 Erlang 提供的 release 管理工具. 我们依据 Erlang/OTP 开发的 application, 最后需要发布,这时需要使用 reltool 帮我们生成最终的 release, 也称为 target system. 同时 reltool 可以分析 application 的依赖关系,帮助我们正确的发布应用.
reltool 包括一个基于 wx 的 GUI 前端(wxWidgets erlang bind), 其可以用来查看 application 的依赖关系,可以查看模块的依赖关系,可以查看源代码. reltool 也提供使用命令来生成自定义的发布包.
本文档主要介绍如何使用 reltool, reltool 为 Erlang/OTP 开发环境的一部分. 本文假设读者对Erlang相关开发比较熟悉,了解 Eralng/OTP 开发规范. Erlang/OTP 要求R13B02及以上版本.
可以通过下列相关文档了解更多 Erlang/OTP 开发相关信息
前面讲过, reltool 提供 GUI 和命令两种交互方式, 本章首先简单的介绍GUI界面相关内容, 重点是使用命令生成 release, 发布自己的应用. 之所以重点介绍命令方式,主要基于两个因素:
通过调用 reltool:start/0,1 启动 reltool, reltool 在启动时,首先扫描所有的 application 和 module, 分析其相互依赖关系.随后启动 system window.
system window 包含四个page window (tabs):
点击对应的tag, 可以切换page.
system window 如下图:
Librarie 窗口如下图
在 library 窗口, 我们设置 reltool 将要使用的代码. 本页面以 tree 的形式来组织内容, 你可以点击每行前面的标记折叠/展开对应内容.
Library directories, Escript files 都可以进行操作. 选择对应的项目,按住鼠标右键显示对应的菜单, 移动鼠标选择对应的菜单项,释放鼠标右键.
双击 lib 下某个 application, 可以显示对应的 application window.
通过 reltool GUI, 我们还可以查看很多 windows, 如 aplication 依赖图:
源代码窗口:
Avaiable 中显示的所有可用的 applications. 在 system page 中,我们可以设置全局的 application 包含规则, 即 incl_cond.
incl_cond 包含三种策略,我们在介绍命令方式创建release时,会详细介绍.
先说一下为自己的 application 生成 release 的步骤:
我们假设第1步,您已经完成.
生成 target system 的重点就是 config 的设置了, 让我们详细的描述一下 reltool 手册中各项 config 参数.
config 可以大体分为4种类型:
其中,很多配置信息在 sys, application, mod 三个等级中均会出现,其关系为: mod > app > sys, 即 mod 配置覆盖 app 配置, app 配置覆盖 sys 配置.
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.
erts
指定 erts application 信息, 具体的字段参考后面介绍的 app 配置.
escript
escript 脚本配置信息, 包含 escript 文件,以及对应的配置信息
app
target system 中包含的 app 信息. 比如所有的 release 都要包含 kernel, stdlib, 具体的app的相关配置,轻参考后面介绍的 app level 配置
mod_cond
设置 module 的包含策略. 其包含多种方式:
此处配置的 mod_cond 是 sys level 的配置, 控制所有的 app 中的 module 包含策略. 当然我们可以对这个信息, 在 app level 进行覆盖.
incl_cond 设置 applicaion 以及 escript 的包含策略.
其包含3种类型:
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种:
在生成 target system 时, 实际上主要有两个步骤:首先创建一个完整的文件候选列表,它包含尽可能多的文件; 随后调用各种相关的 filter 定义,对结果进行过滤, 最后声称最终的 target system.
一般情况下,我们的target system 要是一个完整的可执行的系统,因此我们许要设置 profile 为 embedded. (当然不设置 profile, 只是修改4个相关的 filter, 也可以达到我们想要的效果)
app_file
控制 app 的内容, 因为有各种各样的 filter, 因此最终的 target system 中包含的模块,可能与 app 文件定义的模块列表不一致, 本选项控制 app 的内容. 主要包含3种:
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, 默认 为 [].
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 - 同上
incl_cond
指示模块是否被包含,其覆盖 application 及 system 配置中的 incl_cond 信息.
其包含3个值:
debug_info
同 app 配置中 debug_info 描述.
最后是一个实例,我们为 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 应用.
下面为 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()