Overhaul env expansion so that rebar fully expands env refs prior to invoking the shell script. Also now using DRV_* env vars for compilation/linking of files found in c_src; this frees up "normal" CFLAGS/LDFLAGS for usage in sub build scripts.

This commit is contained in:
Dave Smith 2010-02-16 07:05:29 -07:00
parent 51133313a6
commit 1f6d861aba
3 changed files with 86 additions and 25 deletions

View file

@ -5,7 +5,7 @@
-define(FAIL, throw({error, failed})). -define(FAIL, throw({error, failed})).
-define(ABORT(Str, Args), ?ERROR(Str, Args), init:stop(1)). -define(ABORT(Str, Args), rebar_utils:abort(Str, Args)).
-define(CONSOLE(Str, Args), io:format(Str, Args)). -define(CONSOLE(Str, Args), io:format(Str, Args)).

View file

@ -47,8 +47,10 @@
%% CFLAGS - C compiler %% CFLAGS - C compiler
%% CXXFLAGS - C++ compiler %% CXXFLAGS - C++ compiler
%% LDFLAGS - Link flags %% LDFLAGS - Link flags
%% DRIVER_CFLAGS - default -I paths for erts and ei %% ERL_CFLAGS - default -I paths for erts and ei
%% DRIVER_LDFLAGS - default -L and -lerl_interface -lei %% ERL_LDFLAGS - default -L and -lerl_interface -lei
%% DRV_CFLAGS - flags that will be used for compiling the driver
%% DRV_LDFLAGS - flags that will be used for linking the driver
%% %%
%% Note that if you wish to extend (vs. replace) these variables, you MUST %% Note that if you wish to extend (vs. replace) these variables, you MUST
%% include a shell-style reference in your definition. E.g. to extend CFLAGS, %% include a shell-style reference in your definition. E.g. to extend CFLAGS,
@ -80,7 +82,7 @@ compile(Config, AppFile) ->
%% default for this operating system. This enables max flexibility for users. %% default for this operating system. This enables max flexibility for users.
DefaultEnvs = filter_envs(default_env(), []), DefaultEnvs = filter_envs(default_env(), []),
OverrideEnvs = filter_envs(rebar_config:get_list(Config, port_envs, []), []), OverrideEnvs = filter_envs(rebar_config:get_list(Config, port_envs, []), []),
Env = merge_envs(OverrideEnvs, DefaultEnvs), Env = expand_vars_loop(merge_each_var(os_env() ++ DefaultEnvs ++ OverrideEnvs, [])),
%% One or more files are available for building. Run the pre-compile hook, if %% One or more files are available for building. Run the pre-compile hook, if
%% necessary. %% necessary.
@ -97,7 +99,8 @@ compile(Config, AppFile) ->
case needs_link(SoName, NewBins) of case needs_link(SoName, NewBins) of
true -> true ->
AllBins = string:join(NewBins ++ ExistingBins, " "), AllBins = string:join(NewBins ++ ExistingBins, " "),
rebar_utils:sh_failfast(?FMT("$CC ~s $LDFLAGS $DRIVER_LDFLAGS -o ~s", [AllBins, SoName]), Env); rebar_utils:sh_failfast(?FMT("$CC ~s $LDFLAGS $DRV_LDFLAGS -o ~s",
[AllBins, SoName]), Env);
false -> false ->
?INFO("Skipping relink of ~s\n", [SoName]), ?INFO("Skipping relink of ~s\n", [SoName]),
ok ok
@ -162,9 +165,11 @@ compile_each([Source | Rest], Config, Env, NewBins, ExistingBins) ->
?CONSOLE("Compiling ~s\n", [Source]), ?CONSOLE("Compiling ~s\n", [Source]),
case compiler(Ext) of case compiler(Ext) of
"$CC" -> "$CC" ->
rebar_utils:sh_failfast(?FMT("$CC -c $CFLAGS $DRIVER_CFLAGS ~s -o ~s", [Source, Bin]), Env); rebar_utils:sh_failfast(?FMT("$CC -c $CFLAGS $DRV_CFLAGS ~s -o ~s",
[Source, Bin]), Env);
"$CXX" -> "$CXX" ->
rebar_utils:sh_failfast(?FMT("$CXX -c $CXXFLAGS $DRIVER_CFLAGS ~s -o ~s", [Source, Bin]), Env) rebar_utils:sh_failfast(?FMT("$CXX -c $CXXFLAGS $DRV_CFLAGS ~s -o ~s",
[Source, Bin]), Env)
end, end,
compile_each(Rest, Config, Env, [Bin | NewBins], ExistingBins); compile_each(Rest, Config, Env, [Bin | NewBins], ExistingBins);
@ -192,13 +197,6 @@ needs_link(SoName, NewBins) ->
MaxLastMod >= Other MaxLastMod >= Other
end. end.
merge_envs(OverrideEnvs, DefaultEnvs) ->
orddict:merge(fun(Key, Override, Default) ->
expand_env_variable(Override, Key, Default)
end,
orddict:from_list(OverrideEnvs),
orddict:from_list(DefaultEnvs)).
%% %%
%% Choose a compiler variable, based on a provided extension %% Choose a compiler variable, based on a provided extension
@ -213,6 +211,62 @@ compiler(".C") -> "$CXX";
compiler(_) -> "$CC". compiler(_) -> "$CC".
%%
%% Given a list of {Key, Value} environment variables, where Key may be defined
%% multiple times, walk the list and expand each self-reference so that we
%% end with a list of each variable singly-defined.
%%
merge_each_var([], Vars) ->
Vars;
merge_each_var([{Key, Value} | Rest], Vars) ->
case orddict:find(Key, Vars) of
error ->
%% Nothing yet defined for this key/value. Expand any self-references
%% as blank.
Evalue = expand_env_variable(Value, Key, "");
{ok, Value0} ->
%% Use previous definition in expansion
Evalue = expand_env_variable(Value, Key, Value0)
end,
merge_each_var(Rest, orddict:store(Key, Evalue, Vars)).
%%
%% Give a unique list of {Key, Value} environment variables, expand each one
%% for every other key until no further expansions are possible.
%%
expand_vars_loop(Vars) ->
expand_vars_loop(Vars, 10).
expand_vars_loop(Vars0, 0) ->
?ABORT("Max. expansion reached for ENV vars!\n", []);
expand_vars_loop(Vars0, Count) ->
Vars = lists:foldl(fun({Key, Value}, Acc) ->
expand_vars(Key, Value, Acc)
end,
Vars0, Vars0),
case orddict:from_list(Vars) of
Vars0 ->
Vars0;
Vars ->
expand_vars_loop(Vars, Count-1)
end.
%%
%% Expand all OTHER references to a given K/V pair
%%
expand_vars(Key, Value, Vars) ->
lists:foldl(fun({AKey, AValue}, Acc) ->
case AKey of
Key ->
NewValue = AValue;
_ ->
NewValue = expand_env_variable(AValue, Key, Value)
end,
[{AKey, NewValue} | Acc]
end,
[], Vars).
%% %%
%% Given env. variable FOO we want to expand all references to %% Given env. variable FOO we want to expand all references to
%% it in InStr. References can have two forms: $FOO and ${FOO} %% it in InStr. References can have two forms: $FOO and ${FOO}
@ -242,18 +296,20 @@ filter_envs([{Key, Value} | Rest], Acc) ->
erts_dir() -> erts_dir() ->
lists:concat([code:root_dir(), "/erts-", erlang:system_info(version)]). lists:concat([code:root_dir(), "/erts-", erlang:system_info(version)]).
os_env() ->
[list_to_tuple(re:split(S, "=", [{return, list}])) || S <- os:getenv()].
default_env() -> default_env() ->
[{"CC", "gcc"}, [{"CC", "gcc"},
{"CXX", "g++"}, {"CXX", "g++"},
{"CFLAGS", "-g -Wall -fPIC"}, {"ERL_CFLAGS", lists:concat([" -I", code:lib_dir(erl_interface, include),
{"CXXFLAGS", "-g -Wall -fPIC"}, " -I", filename:join(erts_dir(), include),
{"LDFLAGS", "-shared"}, " "])},
{"darwin", "LDFLAGS", "-bundle -flat_namespace -undefined suppress"}, {"ERL_LDFLAGS", lists:concat([" -L", code:lib_dir(erl_interface, lib),
{"DRIVER_CFLAGS", lists:concat([" -I", code:lib_dir(erl_interface, include), " -lerl_interface -lei"])},
" -I", filename:join(erts_dir(), include), {"DRV_CFLAGS", "-g -Wall -fPIC $ERL_CFLAGS"},
" "])}, {"DRV_LDFLAGS", "-shared $ERL_LDFLAGS"},
{"DRIVER_LDFLAGS", lists:concat([" -L", code:lib_dir(erl_interface, lib), {"darwin", "DRV_LDFLAGS", "-bundle -flat_namespace -undefined suppress $ERL_LDFLAGS"},
" -lerl_interface -lei"])},
{"ERLANG_ARCH", integer_to_list(8 * erlang:system_info(wordsize))}, {"ERLANG_ARCH", integer_to_list(8 * erlang:system_info(wordsize))},
{"ERLANG_TARGET", rebar_utils:get_arch()}]. {"ERLANG_TARGET", rebar_utils:get_arch()}].

View file

@ -35,7 +35,8 @@
find_files/2, find_files/2,
now_str/0, now_str/0,
ensure_dir/1, ensure_dir/1,
beam_to_mod/2, beams/1]). beam_to_mod/2, beams/1,
abort/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -92,7 +93,7 @@ find_files(Dir, Regex) ->
now_str() -> now_str() ->
{{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(),
lists:flatten(io_lib:format("~4b/~2..0b/~2..0b ~2..0b:~2..0b:~2..0b", lists:flatten(io_lib:format("~4b/~2..0b/~2..0b ~2..0b:~2..0b:~2..0b",
[Year, Month, Day, Hour, Minute, Second])). [Year, Month, Day, Hour, Minute, Second])).
%% TODO: Review why filelib:ensure_dir/1 sometimes returns {error, eexist}. %% TODO: Review why filelib:ensure_dir/1 sometimes returns {error, eexist}.
@ -113,6 +114,10 @@ ensure_dir(Path) ->
Error Error
end. end.
abort(String, Args) ->
?ERROR(String, Args),
halt(1).
%% ==================================================================== %% ====================================================================
%% Internal functions %% Internal functions
%% ==================================================================== %% ====================================================================