Compile forms with included header files
I'm trying to compile a module from forms, with included header files. First, if I have the module in a source file, everything works fine.
user.hrl
-record(user, {na开发者_如何学Gome :: string()}).
zed.erl
-module(zed).
-export([f/1]).
-include("user.hrl").
f(User) ->
User#user.name.
shell
1> compile:file(zed, [return]).
{ok,zed,[]}
2> rr("user.hrl").
[user]
3> zed:f(#user{name = "Zed"}).
"Zed"
If I try to compile the same module from forms, I get an undefined record error. Playing with {i, Dir}
and other options does not help.
shell
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}}]}],[]}
What am I doing wrong?
Include files, and macros, are handled by epp, the erlang preprocessor. The compile:forms/1 function assumes that all preprocessing has already been done so it will process the {attribute,1,include,...}
as a, for it, unknown attribute. The same with macros.
There is today no way of running the preprocessor on list of forms. You will have to explicitly include the file and do macro processing. It might also seem a little strange to take some of your input from forms and some from files.
We did this for a project only for records, but it requires a couple of things:
- You must have a module loaded in run time which have the .hrl-files you need included (the beam for this module must also be available on the path).
- The module has to be compiled with debug info (
+debug_info
to the compiler or with[debug_info]
as option argument toc/2
). - You have to insert the .hrl-record definitions into your forms yourself.
Here's how to do it:
First create a module which includes the .hrl-file:
-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].
This will give you a module whose include/0
function will give you a list of the abstract code for all the records in that module (coming from the .hrl-files that where inluded).
This way of doing it could of course be used for other attributes than the record attribute as well (or even functions in the .hrl-files).
Once you have the list of record attributes you just append them to your forms:
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}}]}]}].
精彩评论