[erlang-questions] Using -callback with libraries supporting R14 and higher

Fred Hebert <>
Tue Feb 19 18:13:00 CET 2013


First of all, you shouldn't use the OTP version to define your macros --
this is a release name, and it likely will change with custom releases.

You can detect compiler or kernel versions easily if what you want to do
is define macros. Just make a quick call to:

erl -noshell  -eval 'io:format("~s~n",[element(3, lists:keyfind(kernel,1,application:which_applications()))]),init:stop().'

This will tend to break when you don't control how to build the library,
though.

At this point what you might want to do is use a parse transform
that will do the call at compile time to determine what version of the
compiler is being used right now, and filter out the attributes you do
not want to keep.

I've written a quick one that seems to work (didn't test it
extensively). Based on the current ERTS version, it will either drop the
behaviour_info/1 and behavior_info/1 functions (and remove them from the
export lists), or remove the -spec arguments. The script is also visible
at https://gist.github.com/ferd/4987814, and if people are interested,
I'll make it a minimal library application available from my github
account so people can use it with rebar or whatever dependency
management system they have:

-module(behaviour_parse).
-export([parse_transform/2]).
-define(CUTOFF, "2.15"). % R15B

parse_transform(AST, _Opts) ->
    [Vsn] = [X || {kernel,_,X} <- application:which_applications()],
    walk_ast(if Vsn >= ?CUTOFF -> spec;
                Vsn < ?CUTOFF -> func
             end,
             AST).

walk_ast(_, []) ->
    [];
walk_ast(func, [{attribute, _Ln, callback, _}|T]) ->
    walk_ast(func, T);
walk_ast(spec, [{attribute, Ln, export, List}|T]) ->
    [{attribute, Ln, export, List -- [{behaviour_info,1},{behavior_info,1}]}
     | walk_ast(spec, T)];
walk_ast(spec, [{function, _Ln, behaviour_info,1,_Clauses}|T]) ->
    walk_ast(spec, T);
walk_ast(spec, [{function, _Ln, behavior_info,1,_Clauses}|T]) ->
    walk_ast(spec, T);
walk_ast(Type, [H|T]) ->
    [H|walk_ast(Type, T)].


Just include it in a file with:

-compile({parse_transform, behaviour_parse}).

And it should do its thing.

Regards,
Fred.

On 02/19, Anthony Molinaro wrote:
> Hi,
> 
> I recently was asked to add -callback support to a library I maintain
> because someone was getting warnings from dialyzer.  Upon looking into
> it I don't see any way to support both R14 and R15.
> 
> The -callback attribute seems to cause syntax errors with the R14 compiler.
> If you include both with R15 you get an error about how you can't use them
> together.
> 
> I know it's possible using a -D flag and some conditional macros, but that
> requires integration with the build system (and despite its wide appeal,
> rebar is not the only game in town, some people use EMakefiles, some
> GNU autotools, etc).
> 
> Does OTP provide some sort of macro definition, similar to say ?MODULE
> which provides the version of OTP?  If not how are other library
> maintainers providing versions for multiple incompatible OTP releases?
> 
> -Anthony
> 
> -- 
> ------------------------------------------------------------------------
> Anthony Molinaro                           <>
> _______________________________________________
> erlang-questions mailing list
> 
> http://erlang.org/mailman/listinfo/erlang-questions



More information about the erlang-questions mailing list