Forms 编译包含头文件的表单

Forms 编译包含头文件的表单,forms,erlang,compilation,Forms,Erlang,Compilation,我试图从表单中编译一个模块,其中包含头文件。首先,如果我有一个源文件中的模块,一切正常 user.hrl -record(user, {name :: string()}). -module(zed). -export([f/1]). -include("user.hrl"). f(User) -> User#user.name. 1> compile:file(zed, [return]). {ok,zed,[]} 2> rr("user.hrl"). [use

我试图从表单中编译一个模块,其中包含头文件。首先,如果我有一个源文件中的模块,一切正常

user.hrl

-record(user, {name :: string()}).
-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"
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}}]}],[]}
zed.erl

-record(user, {name :: string()}).
-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"
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}}]}],[]}
壳牌公司

-record(user, {name :: string()}).
-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"
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}}]}],[]}
如果我试图从表单编译相同的模块,我会得到一个未定义的记录错误。玩
{i,Dir}
和其他选项没有帮助

壳牌公司

-record(user, {name :: string()}).
-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"
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}}]}],[]}

我做错了什么?

包括文件和宏,由erlang预处理器epp处理。compile:forms/1函数假定所有预处理都已经完成,因此它将把
{attribute,1,include,…}
作为未知属性进行处理。宏也是如此


现在无法在表单列表上运行预处理器。您必须显式地包含该文件并执行宏处理。从表单和文件中获取一些输入似乎也有点奇怪。

我们这样做只是为了记录,但它需要一些东西:

  • 必须在运行时加载一个模块,该模块包含所需的.hrl文件(此模块的梁也必须在路径上可用)
  • 必须使用调试信息编译模块(
    +debug\u info
    到编译器,或使用
    [debug\u info]
    作为
    c/2
    的选项参数)
  • 您必须自己在表单中插入.hrl记录定义
  • 以下是如何做到这一点:

    首先创建包含.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].
    

    谢谢这方面的文件误导了我。因此,基本上我可以1)自己获取标题,将其解析为表单,并用它们替换属性,或者2)将表单漂亮地打印到源文件中,然后进行编译。或修复epp:-)仅供参考,有一个模块用于对erl_扫描返回的代币进行预处理:感谢分享。这是一个有趣的问题解决方法:)是的!这很好,因为它总是提供最新版本的记录,即使.hrl文件发生了更改(因为my_hrl.erl get被重新编译)。