我正在尝试使用包含的头文件从表单编译模块。首先,如果我在源文件中有模块,一切正常。
user.hrl
-record(user, {name :: string()}).
zed.erl
-module(zed).
-export([f/1]).
-include("user.hrl").
f(User) ->
User#user.name.
壳
1> compile:file(zed, [return]).
{ok,zed,[]}
2> rr("user.hrl").
[user]
3> zed:f(#user{name = "Zed"}).
"Zed"
如果我尝试从表单编译相同的模块,我会收到一个未定义的记录错误。使用{i, Dir}
和其他选项无济于事。
壳
1> Forms = [{attribute,1,module,zed},
1> {attribute,1,export,[{f,1}]},
1> {attribute,1,include,"user.hrl"},
1> {function,1,f,1,
1> [{clause,1,
1> [{var,1,'User'}], [],
1> [{record_field,1,
1> {var,1,'User'},
1> user,
1> {atom,1,name}}]}]}].
....
2> compile:forms(Forms, [return]).
{error,[{".",[{1,erl_lint,{undefined_record,user}}]}],[]}
我做错了什么?
答案 0 :(得分:4)
包含文件和宏由epp(erlang预处理器)处理。 compile:forms / 1函数假定已经完成了所有预处理,因此它将{attribute,1,include,...}
处理为一个未知属性。与宏相同。
今天没有办法在表单列表上运行预处理器。您必须明确包含该文件并执行宏处理。从表单中获取一些输入,从文件中获取一些输入可能看起来有点奇怪。
答案 1 :(得分:0)
我们为一个项目仅为记录做了这个,但它需要一些东西:
+debug_info
编译到编译器或使用[debug_info]
作为c/2
的选项参数进行编译。以下是如何操作:
首先创建一个包含.hrl文件的模块:
-module(my_hrl).
-include("my_hrl.hrl").
-export([records/0]).
records() ->
{_Module, _Beam, FilePath} = code:get_object_code(?MODULE),
{ok, {_, [{abstract_code, {_, AC}}]}} =
beam_lib:chunks(FilePath, [abstract_code]),
[R || {attribute, _, record, _} = R <- AC].
这将为您提供一个模块,其include/0
函数将为您提供该模块中所有记录的抽象代码列表(来自包含在内的.hrl文件)。
这种方式当然可以用于除record属性之外的其他属性(甚至是.hrl文件中的函数)。
获得记录属性列表后,只需将它们附加到表单中即可:
Forms = [{attribute,1,module,zed},
{attribute,1,export,[{f,1}]}]
++ my_hrl:records() ++
[{function,1,f,1,
[{clause,1,
[{var,1,'User'}], [],
[{record_field,1,
{var,1,'User'},
user,
{atom,1,name}}]}]}].