代码之家  ›  专栏  ›  技术社区  ›  Roberto Aloi

如何在预处理时区分ERTS版本?

  •  4
  • Roberto Aloi  · 技术社区  · 14 年前

    在最近的Erlang R14中,inets的文件 httpd.hrl 已从以下位置移动:

    src/httpd.hrl
    

    致:

    src/http_server/httpd.hrl
    

    这个 Erlang Web 框架使用以下指令在多个位置包含该文件:

    -include_lib("inets/src/httpd.hrl").
    

    因为我喜欢用Erlang Web编译 二者都 Erlang的版本(R13和R14),理想情况下我需要的是:

    -ifdef(OLD_ERTS_VERSION).
    -include_lib("inets/src/httpd.hrl").
    -else.
    -include_lib("inets/src/http_server/httpd.hrl").
    -endif.
    

    即使可以通过以下方式检索ERTS版本:

    erlang:system_info(version).
    

    这在预处理时确实是不可能的。

    如何处理这些情况?解析转换是唯一的方法吗?有更好的选择吗?

    2 回复  |  直到 14 年前
        1
  •  6
  •   I GIVE TERRIBLE ADVICE    14 年前

    不确定你是否会喜欢这个技巧,但是你可以使用一个解析转换。

    我们首先定义一个基本的解析转换模块:

    -module(erts_v).
    -export([parse_transform/2]).
    
    parse_transform(AST, _Opts) ->
        io:format("~p~n", [AST]).
    

    编译它,然后您可以在希望它工作的模块中包含这两个头。这应给出以下信息:

    -module(test).
    -compile({parse_transform, erts_v}).
    -include_lib("inets/src/httpd.hrl").
    -include_lib("inets/src/http_server/httpd.hrl").
    -export([fake_fun/1]).
    
    fake_fun(A) -> A.
    

    如果您使用的是R14B并编译它,那么应该具有如下所示的模块抽象格式:

    [{attribute,1,file,{"./test.erl",1}},
     {attribute,1,module,test},
     {error,{3,epp,{include,lib,"inets/src/httpd.hrl"}}},
     {attribute,1,file,
         {"/usr/local/lib/erlang/lib/inets-5.5/src/http_server/httpd.hrl",1}},
     {attribute,1,file,
         {"/usr/local/lib/erlang/lib/kernel-2.14.1/include/file.hrl",1}},
     {attribute,24,record,
         {file_info,
             [{record_field,25,{atom,25,size}},
              {record_field,26,{atom,26,type}},
     ...
    

    这告诉我们,我们可以同时使用这两个头,有效的头将自动包含,而另一个将出错。我们要做的就是把 {error,...} 元组并得到一个有效的编译。为此,请修复parse_transform模块,使其看起来如下所示:

    -module(erts_v).
    -export([parse_transform/2]).
    
    parse_transform(AST, _Opts) ->
        walk_ast(AST).
    
    walk_ast([{error,{_,epp,{include,lib,"inets/src/httpd.hrl"}}}|AST]) ->
        AST;
    walk_ast([{error,{_,epp,{include,lib,"inets/src/http_server/httpd.hrl"}}}|AST]) ->
        AST;
    walk_ast([H|T]) ->
        [H|walk_ast(T)].
    

    这将删除错误包含,仅当它在您需要的精确模块上。其他乱七八糟的包括应该照常失败。

    我还没有在所有版本上测试过,所以如果它们之间的行为发生了变化,这就不起作用。另一方面,如果保持不变,这个parse_转换将是独立于版本的,代价是需要对模块的编译顺序进行排序,这对于Emakefiles和rebar来说非常简单。

        2
  •  2
  •   probsolver    14 年前

    如果使用makefile,可以执行以下操作

    ERTS|VER=$(外壳erl+V 2>&1 |出口-o'[0-9]+[0-9]+[0-9]+[0-9]+')

    然后在erlc参数或Emakefile中匹配字符串并定义宏。 别无选择,阿飞。