在最近的Erlang R14中,inets的文件httpd.hrl
已从以下位置移除:
src/httpd.hrl
为:
src/http_server/httpd.hrl
Erlang Web框架使用以下指令在几个地方包含该文件:
-include_lib("inets/src/httpd.hrl").
由于我喜欢使用两个版本的Erlang(R13和R14)编译Erlang Web,理想情况下我需要的是:
-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).
在预处理时间确实不可能。
如何处理这些情况?解析变换是唯一的方法吗?还有更好的选择吗?
答案 0 :(得分:6)
不确定你是否喜欢这种hackish技巧,但你可以使用解析转换。
让我们首先定义一个基本的解析变换模块:
-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_transform将是版本无关的,代价是需要订购模块的编译顺序,这对于Emakefiles和rebar来说非常简单。
答案 1 :(得分:2)
如果您使用的是makefile,则可以执行类似
的操作ERTS_VER = $(shell erl + V 2>& 1 | egrep -o'[0-9] +。[0-9] +。[0-9] +')
匹配字符串并在erlc参数或Emakefile中定义宏。 没有其他办法,AFAIK。