依赖和配置文件
依赖永远按照prod模式对应的profile进行编译,不会有其他(当然不包括default)任何东西会被额外的套用上来,即使它们是为prod依赖项配置的,仍然会将其提取到其声明的配置文件的配置文件目录中。例如,顶层的依赖关系deps将放在_build/default/lib下,test将放在_build/test/lib下,并且两者都将在prod应用其配置文件配置的情况下进行编译。
在任何项目中,根据任务运行或运行任务的人员的角色,总会有一组所需的选项。
例如,在Erlang项目中,最常见的示例是仅针对测试运行所需的依赖项,例如模拟库或特定测试工具或框架。
rebar3使用配置文件的概念来满足这些要求。配置文件是一组配置设置,仅在这些特定上下文之一中使用,覆盖或补充常规配置。他们的目标是能够支持多个开发用例,同时保持可重复性,而无需外部工具或环境值来完成这项工作。
可以通过三种不同方式指定运行的配置文件:
rebar3 as <profile> <command>
或rebar3 as <profile1>,<profile2> <command>
任何这些形式(甚至是所有这些形式)都会让rebar3知道它应该作为特殊配置文件之一运行并相应地修改其配置。
可以在主rebar.config文件中指定配置文件配置:
{profiles, [{ProfileName1, [Options, ...]},
{ProfileName2, [Options, ...]}]}.
例如,meck仅为测试运行添加依赖关系的测试配置文件可以定义为:
{profiles, [{test, [{deps, [meck]}]}]}.
任何配置值都可以包含在配置文件中,包括插件,编译器选项,发行选项等。
更完整的示例如下所示:
{deps, [...]}.
{relx, [
...
]}.
{profiles, [
{prod, [
{erl_opts, [no_debug_info, warnings_as_errors]},
{relx, [{dev_mode, false}]}
]},
{native, [
{erl_opts, [{native, o3}]}
]},
{test, [
{deps, [meck]},
{erl_opts, [debug_info]}
]}
]}.
因此,这样一个项目有四个不同的模式:
这些可能在很多场景下结合在一起。以下是示例运行:
rebar3 ct
:将运行项目的常见测试套件。按顺序,应用的配置文件将是default,然后test,因为ct要求使用test配置文件。rebar3 as test ct
:将像以前一样运行。配置文件不会重复应用多次。rebar3 as native ct
:将以纯本地运行测试。配置文件的顺序是’default’,然后是’native’,最后是’test’(最后由命令运行指定)。rebar3 as test,native ct
:将与上述相同。在应用配置文件时,rebar3首先将它们全部展开,然后按正确的顺序应用它们。所以为了在这里会default,然后test,然后native,然后test再次(因为的ct命令)。由于配置文件可应用于idempotently,这仅相当于调用rebar3 as native ct。rebar3 release
将仅作为default配置文件构建版本。rebar3 as prod release
将使用更严格的编译器选项来构建没有开发模式的版本。rebar3 as prod, native release
将使用最后一个命令构建发行版,但同时还将模块编译为本机模式。rebar3 as prod release
而REBAR_PROFILE=native在环境中将像上一个命令一样构建发布,但native将在prod之前应用。因此,配置文件的应用顺序如下:
default
REBAR_PROFILE
值,如果有的话as
命令行部分中指定的配置文件通常,配置文件因此应该是可组合的,用于配置要使用的配置子集。
依赖锁定
只有主的rebar.config文件中定义的依赖项会被锁定,而依赖项的依赖项则不会
如果有人想“锁定”编译(使用生产配置),答案是使用releases(参见[[Releases]]),它允许生成可以在任何时间重用的编译工件,如果用于部署可以以rebar3 tar进行打包部署。
尝试自动合并所有配置选项通常很棘手。不同的工具或命令会以不同的方式期望它们,或者将lists of tuples, proplists, key/value pairs转换为某种字典。
为了支持尽可能最通用的形式,rebar3将它们作proplists 和 tuple lists的松散组合来处理。这意味着以下选项都被视为具有密钥native
:
native
{native, o3}
{native, still, supported}
即使其中一些工具可能支持也可能不支持。例如,Erlang编译器支持将宏定义为{d, 'MACRONAME'}
或者{d, 'MACRONAME', MacroValue}
,但单独的d不行,而它确实支持native
和{native, o3}
。
rebar3正确支持所有这些表单并以功能方式合并它们。我们以下面的配置文件为例:
{profiles, [
{prod, [
{erl_opts, [no_debug_info, warnings_as_errors]},
]},
{native, [
{erl_opts, [{native, o3}, {d, 'NATIVE'}]}
]},
{test, [
{erl_opts, [debug_info]}
]}
]}.
以不同的顺序调用这些配置将生成不同的erl_opts列表:
rebar3 as prod,native,test <command>
: [debug_info, {d, ‘NATIVE’}, {native, o3}, no_debug_info, warnings_as_errors]rebar3 as test,prod,native <command>
: [{d, ‘NATIVE’}, {native, o3}, no_debug_info, warnings_as_errors, debug_info]rebar3 as native,test,prod <command>
: [no_debug_info, warnings_as_errors, debug_info, {d, ‘NATIVE’}, {native, o3}]rebar3 as native,prod,test <command>
: [debug_info, no_debug_info, warnings_as_errors, {d, ‘NATIVE’}, {native, o3}]请注意,应用的最后一个配置文件会生成列表中的第一个元素,并且每个配置文件列表中的元素将根据其键进行排序。
这将允许rebar3命令以正确的顺序拾取元素,同时仍然支持需要许多元素共享相同键的多值列表(例如[{d, ‘ABC’}, {d, ‘DEF’}],这是两个独立的宏!)。不支持重复元素的命令可以在第一个元素之后停止处理它们,而那些构建字典(或映射)的命令可以选择按原样插入它们,或者可以安全地反转列表(如果最后处理的元素变为maps中的最后一个)。
所有配置文件合并规则都以这种方式安全处理。插件编写者应该了解这些规则并做出相应的计划。