From 2f3f6f8b71e40954c44b81e15f637a2abe36ee35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 26 Jan 2017 16:43:47 +0100 Subject: [PATCH] Improve compilation with rebar3 --- rebar.config | 15 +- rebar.config.script | 405 +++++++++++++++++++++++++++----------------- 2 files changed, 259 insertions(+), 161 deletions(-) diff --git a/rebar.config b/rebar.config index 7e9fe145e..f824f620f 100644 --- a/rebar.config +++ b/rebar.config @@ -43,12 +43,12 @@ {tag, "1.0.2"}}}}, {if_var_true, riak, {riakc, ".*", {git, "https://github.com/basho/riak-erlang-client", {tag, "2.4.1"}}}}, - %% Elixir support, needed to run tests + %% Elixir support, needed to run tests {if_var_true, elixir, {elixir, ".*", {git, "https://github.com/elixir-lang/elixir", {tag, {if_version_above, "17", "v1.2.6", "v1.1.1"}}}}}, %% TODO: When modules are fully migrated to new structure and mix, we will not need anymore rebar_elixir_plugin - {if_var_true, elixir, {rebar_elixir_plugin, ".*", - {git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}}, + {if_not_rebar3, {if_var_true, elixir, {rebar_elixir_plugin, ".*", + {git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}}}, {if_var_true, iconv, {iconv, ".*", {git, "https://github.com/processone/iconv", {tag, "1.0.3"}}}}, {if_var_true, tools, {meck, "0.8.*", {git, "https://github.com/eproxus/meck", @@ -96,9 +96,12 @@ {deps_erl_opts, [{if_var_true, hipe, native}]}. -{plugins, [deps_erl_opts, - {if_var_true, elixir, rebar_elixir_compiler}, - {if_var_true, elixir, rebar_exunit}]}. +{if_rebar3, {plugins, [rebar3_hex, {provider_asn1, "0.2.0"}]}}. +{if_not_rebar3, {plugins, [ + deps_erl_opts, + {if_var_true, elixir, rebar_elixir_compiler}, + {if_var_true, elixir, rebar_exunit} + ]}}. {if_var_true, elixir, {lib_dirs, ["deps/elixir/lib"]}}. diff --git a/rebar.config.script b/rebar.config.script index ba8c66c66..5e371b175 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -18,34 +18,63 @@ %%% %%%---------------------------------------------------------------------- -ModCfg0 = fun(F, Cfg, [Key|Tail], Op, Default) -> - {OldVal,PartCfg} = case lists:keytake(Key, 1, Cfg) of - {value, {_, V1}, V2} -> {V1, V2}; - false -> {if Tail == [] -> Default; true -> [] end, Cfg} - end, - case Tail of - [] -> - [{Key, Op(OldVal)} | PartCfg]; - _ -> - [{Key, F(F, OldVal, Tail, Op, Default)} | PartCfg] - end - end, -ModCfg = fun(Cfg, Keys, Op, Default) -> ModCfg0(ModCfg0, Cfg, Keys, Op, Default) end, +Vars = case file:consult("vars.config") of + {ok, Terms} -> + Terms; + _Err -> + [] + end ++ [{cflags, "-g -O2 -Wall"}, {cppflags, "-g -O2 -Wall"}, {ldflags, ""}], +{cflags, CFlags} = lists:keyfind(cflags, 1, Vars), +{cppflags, CPPFlags} = lists:keyfind(cppflags, 1, Vars), +{ldflags, LDFlags} = lists:keyfind(ldflags, 1, Vars), + +GetCfg0 = fun(F, Cfg, [Key | Tail], Default) -> + Val = case lists:keyfind(Key, 1, Cfg) of + {Key, V1} -> V1; + false -> Default + end, + case Tail of + [] -> + Val; + _ -> + F(F, Val, Tail, Default) + end + end, +ModCfg0 = fun(F, Cfg, [Key | Tail], Op, Default) -> + {OldVal, PartCfg} = case lists:keytake(Key, 1, Cfg) of + {value, {_, V1}, V2} -> {V1, V2}; + false -> {if Tail == [] -> Default; true -> [] end, Cfg} + end, + case Tail of + [] -> + [{Key, Op(OldVal)} | PartCfg]; + _ -> + [{Key, F(F, OldVal, Tail, Op, Default)} | PartCfg] + end + end, + +FilterConfig = fun(F, Cfg, [{Path, true, ModFun, Default} | Tail]) -> + F(F, ModCfg0(ModCfg0, Cfg, Path, ModFun, Default), Tail); + (F, Cfg, [{Path, SourcePath, true, ModFun, Default, SourceDefault} | Tail]) -> + SourceVal = GetCfg0(GetCfg0, Cfg, SourcePath, SourceDefault), + ModFun2 = fun(V) -> ModFun(V, SourceVal) end, + F(F, ModCfg0(ModCfg0, Cfg, Path, ModFun2, Default), Tail); + (F, Cfg, [_ | Tail]) -> + F(F, Cfg, Tail); + (_, Cfg, []) -> + Cfg + end, IsRebar3 = case application:get_key(rebar, vsn) of {ok, VSN} -> [VSN1 | _] = string:tokens(VSN, "-"), - [Maj, Min, Patch] = string:tokens(VSN1, "."), + [Maj, _Min, _Patch] = string:tokens(VSN1, "."), (list_to_integer(Maj) >= 3); undefined -> lists:keymember(mix, 1, application:loaded_applications()) end, -Cfg = case file:consult(filename:join(filename:dirname(SCRIPT), "vars.config")) of - {ok, Terms} -> - Terms; - _Err -> - [] - end, + +SysVer = erlang:system_info(otp_release), ProcessSingleVar = fun(F, Var, Tail) -> case F(F, [Var], []) of @@ -55,10 +84,10 @@ ProcessSingleVar = fun(F, Var, Tail) -> end, ProcessVars = fun(_F, [], Acc) -> - lists:reverse(Acc); - (F, [{Type, Ver, Value} | Tail], Acc) when - Type == if_version_above orelse - Type == if_version_below -> + lists:reverse(Acc); + (F, [{Type, Ver, Value} | Tail], Acc) when + Type == if_version_above orelse + Type == if_version_below -> SysVer = erlang:system_info(otp_release), Include = if Type == if_version_above -> SysVer > Ver; @@ -66,78 +95,127 @@ ProcessVars = fun(_F, [], Acc) -> SysVer < Ver end, if Include -> - F(F, Tail, ProcessSingleVar(F, Value, Acc)); + F(F, Tail, ProcessSingleVar(F, Value, Acc)); true -> - F(F, Tail, Acc) + F(F, Tail, Acc) end; - (F, [{Type, Ver, Value, ElseValue} | Tail], Acc) when - Type == if_version_above orelse - Type == if_version_below -> - SysVer = erlang:system_info(otp_release), + (F, [{Type, Ver, Value, ElseValue} | Tail], Acc) when + Type == if_version_above orelse + Type == if_version_below -> Include = if Type == if_version_above -> SysVer > Ver; true -> SysVer < Ver end, if Include -> - F(F, Tail, ProcessSingleVar(F, Value, Acc)); + F(F, Tail, ProcessSingleVar(F, Value, Acc)); true -> - F(F, Tail, ProcessSingleVar(F, ElseValue, Acc)) + F(F, Tail, ProcessSingleVar(F, ElseValue, Acc)) end; - (F, [{Type, Var, Value} | Tail], Acc) when - Type == if_var_true orelse - Type == if_var_false -> - Flag = Type == if_var_true, - case proplists:get_bool(Var, Cfg) of - V when V == Flag -> - F(F, Tail, ProcessSingleVar(F, Value, Acc)); - _ -> - F(F, Tail, Acc) - end; - (F, [{Type, Var, Match, Value} | Tail], Acc) when - Type == if_var_match orelse - Type == if_var_no_match -> - case proplists:get_value(Var, Cfg) of - V when V == Match -> - F(F, Tail, ProcessSingleVar(F, Value, Acc)); - _ -> - F(F, Tail, Acc) - end; - (F, [Other1 | Tail1], Acc) -> - F(F, Tail1, [F(F, Other1, []) | Acc]); - (F, Val, Acc) when is_tuple(Val) -> - list_to_tuple(F(F, tuple_to_list(Val), Acc)); - (_F, Other2, _Acc) -> - Other2 - end, + (F, [{Type, Var, Value} | Tail], Acc) when + Type == if_var_true orelse + Type == if_var_false -> + Flag = Type == if_var_true, + case proplists:get_bool(Var, Vars) of + V when V == Flag -> + F(F, Tail, ProcessSingleVar(F, Value, Acc)); + _ -> + F(F, Tail, Acc) + end; + (F, [{Type, Value} | Tail], Acc) when + Type == if_rebar3 orelse + Type == if_not_rebar3 -> + Flag = Type == if_rebar3, + case IsRebar3 == Flag of + true -> + F(F, Tail, ProcessSingleVar(F, Value, Acc)); + _ -> + F(F, Tail, Acc) + end; + (F, [{Type, Var, Match, Value} | Tail], Acc) when + Type == if_var_match orelse + Type == if_var_no_match -> + case proplists:get_value(Var, Vars) of + V when V == Match -> + F(F, Tail, ProcessSingleVar(F, Value, Acc)); + _ -> + F(F, Tail, Acc) + end; + (F, [Other1 | Tail1], Acc) -> + F(F, Tail1, [F(F, Other1, []) | Acc]); + (F, Val, Acc) when is_tuple(Val) -> + list_to_tuple(F(F, tuple_to_list(Val), Acc)); + (_F, Other2, _Acc) -> + Other2 + end, -CFLags = proplists:get_value(cflags, Cfg, ""), -CPPFLags = proplists:get_value(cppflags, Cfg, ""), -LDFLags = proplists:get_value(ldflags, Cfg, ""), +MaybeApply = fun(Val) when is_function(Val) -> + Val(); + (Val) -> + Val + end, +MaybeApply2 = fun(Val, Arg) when is_function(Val) -> + Val(Arg); + (Val, _) -> + Val + end, -ConfigureCmd = fun(Pkg, Flags) -> - {'get-deps', - "sh -c 'cd deps/" ++ Pkg ++ - " && CFLAGS=\""++ CFLags ++"\" CPPFLAGS=\""++ CPPFLags ++"\" LDFLAGS=\""++ LDFLags ++"\"" ++ - " ./configure " ++ Flags ++ "'"} - end, +AppendStr = fun(Append) -> + fun("") -> + lists:flatten(MaybeApply(Append)); + (Val) -> + lists:flatten([Val, " ", MaybeApply(Append)]) + end + end, +AppendList = fun(Append) -> + fun(Val) -> + Val ++ MaybeApply(Append) + end + end, +AppendStr2 = fun(Append) -> + fun("", Arg) -> + lists:flatten(MaybeApply2(Append, Arg)); + (Val, Arg) -> + lists:flatten([Val, " ", MaybeApply2(Append, Arg)]) + end + end, +AppendList2 = fun(Append) -> + fun(Val, Arg) -> + Val ++ MaybeApply2(Append, Arg) + end + end, -Conf = ProcessVars(ProcessVars, CONFIG, []), +Rebar3DepsFilter = +fun(DepsList) -> + lists:map(fun({DepName, _, {git, _, {tag, Version}}}) -> + {DepName, Version}; + (Dep) -> + Dep + end, DepsList) +end, -Conf1 = case lists:keytake(post_hook_configure, 1, Conf) of - {value, {_, Items}, Rest} -> - [{post_hooks, [ConfigureCmd(Mod, string:join(Opts, " ")) || {Mod, Opts} <- Items]} | Rest]; - _ -> - Conf - end, +GlobalDepsFilter = +fun(Deps) -> + DepNames = lists:map(fun({DepName, _, _}) -> DepName; + ({DepName, _}) -> DepName + end, Deps), + lists:filtermap(fun(Dep) -> + case code:lib_dir(Dep) of + {error, _} -> + {true, "Unable to locate dep '" ++ atom_to_list(Dep) ++ "' in system deps."}; + _ -> + false + end + end, DepNames) +end, {ok, Cwd} = file:get_cwd(), TestConfigFile = filename:join([Cwd, "test", "config.ctc"]), TestConfig = case file:read_file_info(TestConfigFile) of - {ok, _} -> - "-userconfig ct_config_plain " ++ TestConfigFile ++ " "; - _ -> - "" + {ok, _} -> + ["-userconfig ct_config_plain ", TestConfigFile, " "]; + _ -> + "" end, ResolveDepPath = case IsRebar3 of @@ -145,102 +223,119 @@ ResolveDepPath = case IsRebar3 of fun("deps/" ++ Rest) -> Slash = string:str(Rest, "/"), Dir = "_build/default/lib/" ++ - string:sub_string(Rest, 1, Slash-1), + string:sub_string(Rest, 1, Slash - 1), Dir ++ string:sub_string(Rest, Slash); (Path) -> Path end; _ -> fun(P) -> - P + P end end, -CtIncludes = case lists:keyfind(eunit_compile_opts, 1, Conf1) of - false -> - []; - {_, EunitCompOpts} -> - [[" -include ", filename:join([Cwd, ResolveDepPath(IncPath)])] - || {i, IncPath} <- EunitCompOpts] - end, +CtParams = fun(CompileOpts) -> + ["-ct_hooks cth_surefire ", + lists:map(fun({i, IncPath}) -> + [" -include ", filename:join([Cwd, ResolveDepPath(IncPath)])] + end, CompileOpts), + TestConfig] + end, -ProcessErlOpt = fun({i, Path}) -> - {i, ResolveDepPath(Path)}; - (ErlOpt) -> - ErlOpt - end, +GenDepConfigureLine = +fun(DepPath, Flags) -> + ["sh -c 'if test ! -f ",DepPath,"config.status -o ", + "config.status -nt ",DepPath,"config.status; ", + "then (cd ", DepPath, " && ", + "CFLAGS=\"", CFlags,"\" ", + "CPPFLAGS=\"", CPPFlags, "\" " + "LDFLAGS=\"", LDFlags, "\"", + " ./configure ", string:join(Flags, " "), + "); fi'"] +end, -Conf1a = ModCfg(Conf1, [erl_opts], - fun(ErlOpts) -> lists:map(ProcessErlOpt, ErlOpts) end, []), +GenDepsConfigure = +fun(Hooks) -> + lists:map(fun({Pkg, Flags}) -> + DepPath = ResolveDepPath("deps/" ++ Pkg ++ "/"), + {'compile', + lists:flatten(GenDepConfigureLine(DepPath, Flags))} + end, Hooks) +end, -Conf2a = [{ct_extra_params, lists:flatten(["-ct_hooks cth_surefire ", TestConfig, - CtIncludes])} | Conf1a], +ProcessErlOpt = fun(Vals) -> + lists:map( + fun({i, Path}) -> + {i, ResolveDepPath(Path)}; + (ErlOpt) -> + ErlOpt + end, Vals) + end, -Conf2 = case IsRebar3 of - true -> - DepsFun = fun(DepsList) -> - lists:filtermap(fun({rebar_elixir_plugin, _, _}) -> - false; - ({DepName,_, {git,_, _} = Git}) -> - {true, {DepName, Git}}; - (Dep) -> - true - end, DepsList) - end, - RB1 = ModCfg(Conf2a, [deps], DepsFun, []), - ModCfg(RB1, [plugins], fun(V) -> V -- [deps_erl_opts, - rebar_elixir_compiler, - rebar_exunit] ++ - [rebar3_hex] end, []); - false -> - Conf2a - end, +ProcssXrefExclusions = fun(Items) -> + [{lists:flatten(["(XC - UC) || (XU - X - B ", + [[" - ", V] || V <- Items], ")"]), + []}] + end, +ProcessFloatingDeps = +fun(Deps, FDeps) -> + lists:map(fun({DepName, _Ver, {git, Repo, _Commit}} = Dep) -> + case lists:member(DepName, FDeps) of + true -> + {DepName, ".*", {git, Repo}}; + _ -> + Dep + end; + (Dep2) -> + Dep2 + end, Deps) +end, -Conf3 = case lists:keytake(xref_exclusions, 1, Conf2) of - {value, {_, Items2}, Rest2} -> - [{xref_queries, [{lists:flatten(["(XC - UC) || (XU - X - B ", - [[" - ", V] || V <- Items2], ")"]), []}]} | Rest2]; - _ -> - Conf2 - end, +TravisPostHooks = +fun(true) -> + [{eunit, "echo '\n%%! -pa .eunit/ deps/coveralls/ebin\n" ++ + "main(_)->{ok,F}=file:open(\"erlang.json\",[write])," ++ + "io:fwrite(F,\"~s\",[coveralls:convert_file(" ++ + "\".eunit/cover.coverdata\", \"" ++ + os:getenv("TRAVIS_JOB_ID") ++ + "\", \"travis-ci\",\"\")]).' > getcover.erl"}, + {eunit, "escript ./getcover.erl"}]; + (_) -> + [] +end, -Conf5 = case lists:keytake(floating_deps, 1, Conf3) of - {value, {_, FloatingDeps}, Rest4} -> - case lists:keytake(deps, 1, Rest4) of - {value, {_, Deps}, Rest41} -> - ND = lists:map(fun({DepName, Ver, {git, Repo, _Commit}}=Dep) -> - case lists:member(DepName, FloatingDeps) of - true -> - {DepName, ".*", {git, Repo}}; - _ -> - Dep - end; - (Dep2) -> - Dep2 - end, Deps), - [{deps, ND} | Rest41]; - _ -> - Rest4 - end; - _ -> - Conf3 - end, +Rules = [ + {[provider_hooks], IsRebar3, + AppendList([{pre, [ + {compile, {asn, compile}}, + {clean, {asn, clean}} + ]}]), []}, + {[deps], os:getenv("TRAVIS") == "true", + AppendList([{coveralls, ".*", {git, "https://github.com/markusn/coveralls-erl.git", "master"}}]), []}, + {[post_hooks], [cover_enabled], os:getenv("TRAVIS") == "true", + AppendList2(TravisPostHooks), [], false}, + {[pre_hooks], [post_hook_configure], true, + AppendList2(GenDepsConfigure), [], []}, + {[ct_extra_params], [eunit_compile_opts], true, + AppendStr2(CtParams), "", []}, + {[erl_opts], true, + ProcessErlOpt, []}, + {[xref_queries], [xref_exclusions], true, + AppendList2(ProcssXrefExclusions), [], []}, + {[deps], [floating_deps], IsRebar3, + ProcessFloatingDeps, [], []}, + {[deps], IsRebar3, + Rebar3DepsFilter, []}, + {[deps], os:getenv("USE_GLOBAL_DEPS") /= false, + GlobalDepsFilter, []} + ], -%% When running Travis test, upload test coverage result to coveralls: -Conf6 = case {lists:keyfind(cover_enabled, 1, Conf5), os:getenv("TRAVIS")} of - {{cover_enabled, true}, "true"} -> - JobId = os:getenv("TRAVIS_JOB_ID"), - CfgTemp = ModCfg(Conf5, [deps], fun(V) -> [{coveralls, ".*", {git, "https://github.com/markusn/coveralls-erl.git", "master"}}|V] end, []), - ModCfg(CfgTemp, [post_hooks], fun(V) -> V ++ [{ct, "echo '\n%%! -pa ebin/ deps/coveralls/ebin\nmain(_)->{ok,F}=file:open(\"erlang.json\",[write]),io:fwrite(F,\"~s\",[coveralls:convert_file(\"logs/all.coverdata\", \""++JobId++"\", \"travis-ci\", \"\")]).' > getcover.erl"}, - {ct, "escript ./getcover.erl"}] end, []); - _ -> - Conf5 - end, +Config = FilterConfig(FilterConfig, ProcessVars(ProcessVars, CONFIG, []), Rules), -%io:format("ejabberd configuration:~n ~p~n", [Conf6]), +%io:format("ejabberd configuration:~n ~p~n", [Config]), -Conf6. +Config. %% Local Variables: %% mode: erlang