基础配置
Rebar3 的大部分配置都是通过修改项目根目录或 OTP 应用程序主目录下的 rebar.config 文件来完成的。在项目根目录中定义的值将应用于其中声明的所有应用程序,而 OTP 应用程序主目录内的特定配置文件将仅应用于该应用程序。该规则的少数例外情况是用于插件的全局配置和用于更改整体 Rebar3 行为的环境变量。
此页面记录了可以在 rebar.config 文件中使用的所有标准选项,以及可能影响 Rebar3 行为的环境变量。
环境配置
Rebar3 支持一些会影响工具整体行为的选项。这些选项定义为操作系统环境变量,如下所示
REBAR_PROFILE="term" # force a base profile
HEX_CDN="https://..." # change the Hex endpoint for a private one
QUIET=1 # only display errors
DEBUG=1 # show debug output
# "QUIET=1 DEBUG=1" displays both errors and warnings
DIAGNOSTIC=1 # show maintainers output
REBAR_COLOR="low" # reduces amount of color in output if supported
REBAR_CACHE_DIR # override where Rebar3 stores cache data
REBAR_GLOBAL_CONFIG_DIR # override where Rebar3 stores config data
REBAR_BASE_DIR # override where Rebar3 stores build output
REBAR_CONFIG="rebar3.config" # changes the name of rebar.config files
REBAR_GIT_CLONE_OPTIONS="" # pass additional options to all git clone operations
# for example, a cache across project can be set up
# with "--reference ~/.cache/repos.reference"
http_proxy # standard proxy ENV variable is respected
https_proxy # standard proxy ENV variable is respected
TERM # standard terminal definition value. TERM=dumb disables color
别名
别名允许从现有命令创建新命令,就像一个接一个地运行它们一样
{alias, [{check, [eunit, {ct, "--sys_config=config/app.config"}]}]}.
参数(与命令行一样)可以通过将 Provider 替换为 {Provider, Args} 来传递。
工件
工件是在成功编译(包括任何编译钩子)后需要存在的文件列表(除了 Erlang 模块之外)。这对于让 rebar3 确定某些非 Erlang 工件的依赖项是否成功构建非常有用。这可能很有用的示例包括识别为共享库构建的 C 代码、渲染的模板或 escript 是否正确生成。
如果发现依赖项已构建(意味着其 .app 文件的模块列表与其 .beam 文件匹配且所有工件都存在),则在后续运行 rebar3 时,不会在其上调用编译提供程序或其钩子。
{artifacts, [file:filename_all()]}.
路径相对于什么取决于它是在伞形项目的顶层定义还是在其他地方定义。例如,假设我们有一个项目 my_project,它包含一个位于 apps/my_app/ 下的应用程序 my_app,我们从中构建了一个 escript。然后,我们希望告诉 rebar3 不要考虑 my_project/rebar.config 中的配置,因为它是一个伞形项目的顶层 rebar.config。artifact 将相对于 profile_dir,默认情况下为 _build/default/
{escript_name, rebar3}.
{provider_hooks, [{post, [{compile, escriptize}]}]}.
{artifacts, ["bin/rebar3"]}.
如果它不是一个伞形项目,但 my_app 是顶层目录,则在 rebar.config 中定义的工件相对于应用程序的输出目录,在本例中为 _build/default/lib/my_app/,但我们也可以使用模板从 profile_dir 定义它
{escript_name, rebar3}.
{provider_hooks, [{post, [{compile, escriptize}]}]}.
{artifacts, ["{{profile_dir}}/bin/rebar3"]}.
所有可用的模板键都列在下表中。
| 模板键 | 描述 |
|---|---|
| profile_dir | 带有配置文件字符串追加的基本输出目录,默认值:_build/default/。 |
| base_dir | 基本输出目录,默认值:_build 或 REBAR_BASE_DIR 环境变量的值。 |
| out_dir | 应用程序的输出目录,默认值:_build/default/lib//。 |
另一个示例是在覆盖中使用工件,在本例中为 eleveldb
{overrides,
[{override, eleveldb, [{artifacts, ["priv/eleveldb.so"]},
...
]
}]}.
工件是在应用程序 eleveldb 上定义的,因此它相对于输出目录,这意味着上面使用的路径与我们使用 "{{out_dir}}/priv/eleveldb.so" 相同。
编译
编译选项可以使用 erl_opts 设置,可用选项列在 Erlang 编译模块的文档中。
{erl_opts, []}.
此外,还可以设置特定于平台的选项。这些选项对 OTP 版本与操作系统详细信息连接的结果运行正则表达式。
{erl_opts, [{platform_define,
"(linux|solaris|freebsd|darwin)",
'HAVE_SENDFILE'},
{platform_define, "(linux|freebsd)",
'BACKLOG', 128},
{platform_define, "^18",
'OTP_GREATER_THAN_18'},
{platform_define, "^R13",
'old_inets'}]
}.
版本字符串可能类似于 "22.0-x86_64-apple-darwin18.5.0-64",因此如果您想检查特定 OTP 版本(并避免与操作系统版本匹配),请记住在正则表达式前添加 ^。
一个单独的编译选项是声明在所有其他模块之前编译的模块
{erl_first_files, ["src/mymodule.erl", "src/mymodule.erl"]}.
还存在一些其他通用选项
{validate_app_modules, true}. % Make sure modules in .app match those found in code
{app_vars_file, undefined | Path}. % file containing elements to put in all generated app files
%% Paths the compiler outputs when reporting warnings or errors
%% relative (default), build (all paths are in _build, default prior
%% to 3.2.0, and absolute are valid options
{compiler_source_format, relative}.
其他与 Erlang 相关的编译器及其自己的配置选项也受支持
- Leex 编译器,使用
{xrl_opts, [...]} - SNMP MIB 编译器,使用
{mib_opts, [...]} - Yecc 编译器,使用
{yrl_opts, [...]}
Rebar3 编译选项
Rebar3 附带了一些特定于它的编译器选项。
启用/禁用递归编译
全局禁用或启用递归编译
{erlc_compiler,[{recursive,boolean()}]}.
禁用或启用 src_dirs 上的递归编译
{src_dirs, [{"src", [{recursive, true|false}]}]}
%% Or alternatively:
{erl_opts, [{src_dirs,[{string(),[{recursive,boolean()}]}]}]}.
禁用或启用 extra_src_dirs 上的递归编译
{extra_src_dirs, [{"test", [{recursive, true | false}]}]}
%% or
{erl_opts, [{extra_src_dirs,[{string(),[{recursive,boolean()}]}]}]}.
示例
所有三个选项可以组合以实现粒度,这应该为任何项目提供足够的灵活性。以下是一些示例。
全局禁用递归编译,但为一些目录启用它
{erlc_compiler,[{recursive,false}]},
{erl_opts,[{src_dirs,["src",{"other_src",[{recursive,true}]}]}]}.
禁用测试和其他目录上的递归编译
{erl_opts, [
{extra_src_dirs,[
{"test", [{recursive,boolean()}]},
{"other_dir", [{recursive,boolean()}]}]}
]
}.
自动补全
{completion,
[{aliases,["rebar", "r3"]},
{file, "/home/user/completion/_rebar3"},
{shell, bash}]}.
选项反映了命令参数中指定的选项。
通用测试
{ct_first_files, [...]}. % {erl_first_files, ...} but for CT
{ct_opts, [...]}. % same as options for ct:run_test(...)
{ct_readable, true | false}. % disable Rebar3 modifying CT output in the shell
ct_opts 的通用测试选项参考:https://erlang.org.cn/doc/man/ct.html#run_test-1
一个特殊选项允许使用 {ct_opts, [{sys_config, ["name.of.config"]}]} 加载一组默认的 sys.config 条目。但是,从命令行中,它指定为 --sys_config name.of.config。
选项通常存在于反映可以在命令参数中指定的选项。
覆盖率
使用 {cover_enabled, true} 在测试中启用代码覆盖率。然后,可以在测试后运行 cover 提供程序以显示报告。选项 {cover_opts, [verbose]} 可用于强制将覆盖率报告打印到终端,而不仅仅是打印到文件中。可以通过将 {cover_excl_mods, [Modules]} 添加到配置文件中,将特定模块从代码覆盖率中列入黑名单。可以使用 {cover_excl_apps, [AppNames]} 选项将应用程序整体列入黑名单。
Dialyzer
-type warning() :: dialyzer:warn_option().
{dialyzer, [{warnings, [warning()]},
{get_warnings, boolean()},
{plt_apps, top_level_deps | all_deps} % default: top_level_deps
{plt_extra_apps, [atom()]},
{plt_location, local | file:filename()},
{plt_prefix, string()},
{base_plt_apps, [atom(), ...]},
{base_plt_location, global | file:filename()},
{base_plt_prefix, string()}]}.
要查找所有可能的 dialyzer:warn_option(),请使用dialyzer 文档。
有关在模块中抑制警告的信息,请参阅 Dialyzer 文档的在源文件中请求或抑制警告部分。
分布式
多个提供程序和插件可能需要支持分布式 Erlang。通常,所有此类命令(例如 ct 和 shell)的配置都遵循以下配置值
{dist_node, [
{setcookie, 'atom-cookie'},
{name | sname, 'nodename'}
]}.
目录
目录存在以下选项;下面选择的值是默认值
%% directory for artifacts produced by Rebar3
{base_dir, "_build"}.
%% directory in '<base_dir>/<profile>/' where deps go
{deps_dir, "lib"}.
%% where Rebar3 operates from; defaults to the current working directory
{root_dir, "."}.
%% where checkout dependencies are to be located
{checkouts_dir, "_checkouts"}.
%% directory in '<base_dir>/<profile>/' where plugins go
{plugins_dir, "plugins"}.
%% directories where OTP applications for the project can be located
{project_app_dirs, ["apps/*", "lib/*", "."]}.
%% Directories where source files for an OTP application can be found
{src_dirs, ["src"]}.
%% Paths to miscellaneous Erlang files to compile for an app
%% without including them in its modules list
{extra_src_dirs, []}.
%% Paths the compiler outputs when reporting warnings or errors
%% relative (default), build (all paths are in _build, default prior
%% to 3.2.0, and absolute are valid options
{compiler_source_format, relative}.
此外,Rebar3 将其一些配置数据存储在 ~/.config/rebar3 中,并将一些数据缓存到 ~/.cache/rebar3 中。两者都可以通过指定 {global_rebar_dir, "./some/path"}. 来覆盖。
EDoc
所有受EDoc支持的选项都可以放在 {edoc_opts, [...]} 中。
Escript
完整详细信息请参见escriptize 命令。以下是一些示例配置值。
{escript_main_app, AppName}. % specify which app is the escript app
{escript_name, "FinalName"}. % name of final generated escript
{escript_incl_apps, [App]}. % apps (other than the main one and its deps) to be included
{escript_emu_args, "%%! -escript main Module\n"}. % emulator args
{escript_shebang, "#!/usr/bin/env escript\n"}. % executable line
{escript_comment, "%%\n"}. % comment at top of escript file
由于 escript 构建的结构,仅使用顶层 rebar.config 文件中的选项来构建 escript。
EUnit
{eunit_first_files, [...]}. % {erl_first_files, ...} but for CT
{eunit_opts, [...]}. % same as options for eunit:test(Tests, ...)
{eunit_tests, [...]}. % same as Tests argument in eunit:test(Tests, ...)
一个特殊选项允许使用 {eunit_opts, [{sys_config, ["name.of.config"]}]} 加载一组默认的 sys.config 条目。但是,从命令行中,它指定为 --sys_config name.of.config。
Eunit 选项参考:https://erlang.org.cn/doc/man/eunit.html#test-2
Hex 仓库和索引
从 Rebar3 版本 3.7.0 开始,可以同时使用多个 Hex 存储库(或索引)。存储库按顺序声明,从最高优先级到最低优先级。
在查找包时,将按顺序遍历存储库。一旦其中一个包符合描述,它就会被下载。每个找到的包的哈希值都保存在项目的锁定文件中,因此如果存储库的顺序发生变化,并且其中一些存储库最终包含相同名称和版本对的冲突包定义,则只会下载预期的包。
这允许使用相同的机制来镜像、私有存储库(由 hex.pm 提供)和自托管索引。
要发布或使用私有存储库,必须使用rebar3_hex插件进行身份验证,rebar3 hex auth。这将创建一个单独的配置文件 ~/.config/rebar3/hex.config 来存储密钥。
{hex, [
{repos, [
%% A self-hosted repository that allows publishing may look like this
#{name => <<"my_hexpm">>,
api_url => <<"https://:8080/api">>,
repo_url => <<"https://:8080/repo">>,
repo_public_key => <<"-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----">>
},
%% A mirror looks like a standard repo definition, but uses the same
%% public key as hex itself. Note that the API URL is not required
%% if all you do is fetch information
#{name => <<"jsDelivr">>,
repo_url => <<"https://cdn.jsdelivr.net.cn/hex">>,
...
},
%% If you are a paying hex.pm user with a private organisation, your
%% private repository can be declared as:
#{name => <<"hexpm:private_repo">>}
%% and authenticate with the hex plugin, rebar3 hex user auth
]}
]}.
%% The default Hex config is always implicitly present.
%% You could however replace it wholesale by using a 'replace' value,
%% which in this case would redirect to a local index with no signature
%% validation being done. Any repository can be replaced.
{hex, [
{repos, replace, [
#{name => <<"hexpm">>,
api_url => <<"https://:8080/api">>,
repo_url => <<"https://:8080/repo">>,
...
}
]}
]}.
最低 OTP 版本
可以指定 Erlang/OTP 的最低版本,如果使用较早的版本构建应用程序,则会导致构建失败。
{minimum_otp_vsn, "17.4"}.
覆盖
覆盖允许从更高级别的应用程序修改依赖项的配置。它们旨在允许快速修复和解决方法,尽管我们建议在可能的情况下进行永久性修复,使修复结果应用到目标应用程序的配置中。
覆盖有三种类型:添加、应用于应用程序的覆盖和应用于所有应用程序的覆盖。
{overrides, [{add, app_name(), [{atom(), any()}]},
{del, app_name(), [{atom(), any()}]},
{override, app_name(), [{atom(), any()}]},
{add, [{atom(), any()}]},
{del, [{atom(), any()}]},
{override, [{atom(), any()}]}]}.
这些应用于依赖项,并且依赖项本身也可以有自己的覆盖项,这些覆盖项按以下顺序应用:应用于所有应用程序的覆盖、应用于每个应用程序的覆盖、应用于每个应用程序的添加。
例如,这可以用来强制所有依赖项默认使用debug_info编译,并在使用生产配置文件时强制使用no_debug_info。
{overrides, [{override, [{erl_opts, [debug_info]}]}]}.
{profiles, [{prod, [{overrides, [{override, [{erl_opts,[no_debug_info]}]}]},
{relx, [{dev_mode, false},
{include_erts, true}]}]}
]}.
另一个例子可能是移除所有应用程序的编译器选项warnings_as_errors。
{overrides, [
%% For all apps:
{del, [{erl_opts, [warnings_as_errors]}]},
%% Or for just one app:
{del, one_app, [{erl_opts, [warnings_as_errors]}]}
]}.
请注意,覆盖不会作用于最终扁平化的选项,而是作用于您在项目rebar.config文件中看到的配置。这意味着,如果您想替换某个在配置文件中更改的配置的值,则必须覆盖该配置文件的条目。
🚧
伞形项目中所有应用程序的覆盖
在伞形项目中,在顶层 rebar.config 文件中指定的覆盖也将应用于 `apps/` 或 `lib/` 目录中的应用程序。相比之下,在应用程序级别的 `rebar.config` 文件中指定的覆盖仅适用于其依赖项。
钩子
钩子有两种类型:shell 钩子和提供程序钩子。它们都应用于相同类型的提供程序。
Shell 钩子
钩子提供了一种在可钩挂提供程序之前或之后运行任意 shell 命令的方法,可以选择先匹配系统类型以选择要运行的钩子。shell 钩子在提供程序钩子之后运行。
-type hook() :: {atom(), string()}
| {string(), atom(), string()}.
{pre_hooks, [hook()]}.
{post_hooks, [hook()]}.
{shell_hooks_env, [{string(), string()}].
使用pre_hooks通过 Rebar3 构建merl的示例
{pre_hooks, [{"(linux|darwin|solaris)", compile, "make -C \"$REBAR_DEPS_DIR/merl\" all -W test"},
{"(freebsd|netbsd|openbsd)", compile, "gmake -C \"$REBAR_DEPS_DIR/merl\" all"},
{"win32", compile, "make -C \"%REBAR_DEPS_DIR%/merl\" all -W test"},
{eunit, "erlc -I include/erlydtl_preparser.hrl -o test test/erlydtl_extension_testparser.yrl"},
{"(linux|darwin|solaris)", eunit, "make -C \"$REBAR_DEPS_DIR/merl\" test"},
{"(freebsd|netbsd|openbsd)", eunit, "gmake -C \"$REBAR_DEPS_DIR/merl\" test"},
{"win32", eunit, "make -C \"%REBAR_DEPS_DIR%/merl\" test"}
]}.
🚧
post_hooks 的行为
只有当其可钩挂提供程序成功时,才会调用
post_hooks条目。这意味着,如果您为eunit添加一个post_hooks条目,则只有在您的 EUnit 测试能够成功完成时才会调用它。
在 shell 钩子中,可以使用来自主机操作系统的环境变量和由shell_hooks_env条目定义的环境变量。从v3.23.0开始,rebar3导出的其他环境变量已记录在案,可用于 shell 钩子。下表描述了这些变量(除了REBAR_APP_DIRS和REBAR_SRC_DIRS之外的所有路径都是绝对路径)
| 名称 | 描述 | 默认值 |
|---|---|---|
REBAR_ROOT_DIR |
项目的根目录 | |
REBAR_BUILD_DIR |
配置文件的构建目录 | $REBAR_ROOT_DIR/_build/$REBAR_PROFILE |
REBAR_DEPS_DIR |
存储依赖项的目录 | $REBAR_BUILD_DIR/lib |
REBAR_CHECKOUTS_DIR |
搜索检出依赖项的目录 | $REBAR_ROOT_DIR/_checkouts |
REBAR_CHECKOUTS_OUT_DIR |
存储检出依赖项的目录 | $REBAR_BUILD_DIR/checkouts |
REBAR_PLUGINS_DIR |
存储插件的目录 | $REBAR_BUILD_DIR/plugins |
REBAR_GLOBAL_CONFIG_DIR |
搜索全局rebar.config的目录 |
$HOME/.config/rebar3 |
REBAR_GLOBAL_CACHE_DIR |
缓存目录 | $HOME/.cache/rebar3 |
REBAR_TEMPLATE_DIR |
搜索模板的目录 | $REBAR_GLOBAL_CONFIG_DIR/templates |
REBAR_APP_DIRS |
包含应用程序的相对路径的冒号分隔列表 | apps/*:lib/*:. |
REBAR_SRC_DIRS |
包含源代码(包括extra_src_dirs)的相对路径的冒号分隔列表 - 忽略recursive选项,路径按原样返回 |
src |
ERLANG_ARCH |
系统的字长 | rebar_api:wordsize()的返回值 |
ERLANG_TARGET |
系统的描述 | rebar_api:get_arch()的返回值 |
ERLANG_ROOT_DIR |
Erlang 安装的根目录 | code:root_dir()的返回值 |
ERLANG_ERTS_VER |
erts的版本 |
erlang:system_info(version)的返回值 |
ERL |
erl可执行文件的路径 |
$ERLANG_ROOT_DIR/bin/erl |
ERLC |
erlc可执行文件的路径 |
$ERLANG_ROOT_DIR/bin/erlc |
ERLANG_LIB_DIR_erl_interface |
erl_interface应用程序的路径(如果缺少,则不定义变量!) |
$ERLANG_ROOT_DIR/lib/erl_interface |
ERLANG_LIB_VER_erl_interface |
erl_interface应用程序的版本(如果缺少,则不定义变量!) |
提供程序钩子
提供程序也可以用作钩子。以下钩子在compile运行之前运行clean。要在命名空间中执行命令,可以使用元组作为第二个参数。提供程序钩子在 shell 钩子之前运行。
{provider_hooks, [{pre, [{compile, clean}]}
{post, [{compile, {erlydtl, compile}}]}]}
提供程序中的可挂钩点
只有特定的内置提供程序支持附加到它们的钩子。控制取决于提供程序是否对项目的应用程序(每个应用程序和依赖项)进行操作,或者是否预期它仅在整个项目上运行。
提供程序钩子在 shell 钩子之前运行。
| 钩子 | 之前和之后 |
|---|---|
| clean | 每个应用程序和依赖项,以及/或者在所有顶层应用程序编译之前和之后* |
| ct | 整个运行过程 |
| compile | 每个应用程序和依赖项,以及/或者在所有顶层应用程序编译之前和之后* |
| edoc | 整个运行过程 |
| escriptize | 整个运行过程 |
| eunit | 整个运行过程 |
| release | 整个运行过程 |
| tar | 整个运行过程 |
| erlc_compile | 应用程序的 beam 文件的编译 |
| app_compile | 从应用程序的 .app.src 构建 .app 文件 |
* 这些钩子默认情况下会为每个应用程序运行,因为依赖项可以在其自己的上下文中指定自己的钩子。区别在于,在某些情况下(伞形应用程序),可以在多个级别定义钩子(省略覆盖)
- 应用程序根目录下的 rebar.config 文件
- 每个顶层应用程序(在 `apps/` 或 `libs/` 中)的 rebar.config
- 每个依赖项的 rebar.config
默认情况下,当没有伞形应用程序时,顶层 rebar.config 中定义的钩子被认为是顶层应用程序的一部分。这允许钩子在库稍后发布时继续为依赖项工作。
但是,如果钩子是在具有伞形应用程序的项目的根目录下的 rebar.config 中定义的,则这些钩子将在任务为所有顶层应用程序运行之前/之后运行。
为了在伞形项目中保留每个应用程序的行为,必须在每个应用程序的 rebar.config 中定义钩子。
Relx
参见发布
插件
参见插件。对于作为依赖项使用时使项目构建所需的插件,使用{plugins, [Dep]},对于提供项目用作依赖项时构建不需要的实用程序的插件,使用{project_plugins, [...]}。
Shell
如果找到relx条目,则rebar3 shell REPL 会自动启动应用程序,但可以通过{shell, [{apps, [App]}]}显式指定 shell 要启动的应用程序。
其他选项包括
| 选项 | 值 | 描述 |
|---|---|---|
| apps | [app1, app2, …] | 要由 shell 启动的应用程序。覆盖relx条目的值 |
| config | “path/to/a/file.config” | 加载应用程序要由 shell 启动的.config文件(例如sys.config)。 |
| script_file | “path/to/a/file.escript” | 在为节点启动应用程序之前评估给定的 escript。 |
| app_reload_blacklist | [app1, app2, …] | 调用诸如r3:compile()之类的命令时不应重新加载的应用程序。在处理诸如ranch之类的应用程序时很有用,这些应用程序在两次重新加载后会崩溃。 |
XRef
{xref_warnings,false}.
{xref_extra_paths,[]}.
{xref_checks,[undefined_function_calls,undefined_functions,locals_not_used,
exports_not_used,deprecated_function_calls,
deprecated_functions]}.
{xref_queries,[{"(xc - uc) || (xu - x - b - (\"mod\":\".*foo\"/\"4\"))", []}]}.
{xref_ignores, [Module, {Module, Fun}, {Module, Fun, Arity}]}.
您还可以使用模块中的-ignore_xref(_).属性忽略某些模块或函数的xref警告。这对于忽略为您提供不需要的警告(例如undefined_function_calls和exports_not_used)的函数很有用,如下所示
-ignore_xref({other, call, 0}). % ignore warnings for calls to "external" module function
-ignore_xref([{other, call, 0}]). % equivalent to the previous declaration
-ignore_xref({function,0}). % ignore warnings for locally exported function not used in the analysis scope
-ignore_xref([{function,0}]). % equivalent to the previous declaration
-ignore_xref(function/0). % equivalent to the previous declaration
-ignore_xref([function/0]). % equivalent to the previous declaration
-ignore_xref(module). % ignore warnings related to a given module
-ignore_xref([module]). % equivalent to previous declaration