diff --git a/README.md b/README.md index 7eb9055..ffd2f3c 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,19 @@ BELOW HERE BE DRAGONS %% {ArchRegex, TargetFile, Sources} %% {TargetFile, Sources} %% +%% Note that if you want to use any of the rebar3 variables +%% below you must MUST use a ${}-style to get the expansion +%% to work. e.g. to expand REBAR_DEPS_DIR, do something like: +%% +%% {port_specs, [{"priv/nif.so", +%% ["c_src/nif.c", +%% "${REBAR_DEPS_DIR}/foo/bar.c"]}]}. +%% +%% This is a _very_ good way to be able to use your code both +%% as a top level app and a dependency. +%% +%% CAVEAT! Not using {} is broken for the moment. +%% %% * port_env - Erlang list of key/value pairs which will control %% the environment when running the compiler and linker. %% Variables set in the surrounding system shell are taken diff --git a/src/pc_compilation.erl b/src/pc_compilation.erl index ed3f9e9..4c161b4 100644 --- a/src/pc_compilation.erl +++ b/src/pc_compilation.erl @@ -60,7 +60,7 @@ compile_and_link(State, Specs) -> true -> LinkLang = pc_port_specs:link_lang(Spec), LinkTemplate = select_link_template(LinkLang, Target), - Env = pc_port_specs:environment(Spec), + Env = pc_port_specs:create_env(State, Spec), Cmd = expand_command(LinkTemplate, Env, pc_util:strjoin(Bins, " "), Target), @@ -97,7 +97,7 @@ compile_sources(Config, Specs) -> fun(Spec, Acc) -> Sources = pc_port_specs:sources(Spec), Type = pc_port_specs:type(Spec), - Env = pc_port_specs:environment(Spec), + Env = pc_port_specs:create_env(Config, Spec), compile_each(Config, Sources, Type, Env, Acc) end, {[], []}, Specs), %% Rewrite clang compile commands database file only if something diff --git a/src/pc_port_specs.erl b/src/pc_port_specs.erl index ab9de58..7f390be 100644 --- a/src/pc_port_specs.erl +++ b/src/pc_port_specs.erl @@ -30,8 +30,10 @@ -export([ construct/1, + create_env/2, %% spec accessors environment/1, + opts/1, objects/1, sources/1, target/1, @@ -66,9 +68,14 @@ construct(State) -> {ok, [S || S <- Specs, S#spec.sources /= []]} end. +create_env(State, Spec) -> + pc_port_specs:environment(Spec) ++ + try_and_create_env(State). + %% == Spec Accessors == environment(#spec{opts = Opts}) -> proplists:get_value(env, Opts). +opts(#spec{opts = Opts}) -> Opts. objects(#spec{objects = Objects}) -> Objects. sources(#spec{sources = Sources}) -> Sources. target(#spec{target = Target}) -> Target. @@ -79,6 +86,13 @@ link_lang(#spec{link_lang = LinkLang}) -> LinkLang. %%% Internal Functions %%%=================================================================== +try_and_create_env(State) -> + _ = code:ensure_loaded(rebar_env), + case erlang:function_exported(rebar_env, create_env, 1) of + false -> []; + true -> rebar_env:create_env(State) + end. + port_spec_from_legacy(Config) -> %% Get the target from the so_name variable Target = case rebar_state:get(Config, so_name, undefined) of @@ -133,13 +147,15 @@ get_port_spec(Config, OsType, {Target, Sources}) -> get_port_spec(Config, OsType, {Arch, Target, Sources}) -> get_port_spec(Config, OsType, {Arch, Target, Sources, []}); get_port_spec(Config, OsType, {_Arch, Target, Sources, Opts}) -> + Env = try_and_create_env(Config), SourceFiles = lists:flatmap( fun(Source) -> - Source1 = rebar_utils:escape_chars( - filename:join(rebar_state:dir(Config), Source)), + Source1 = expand_env(Source, Env), + Source2 = rebar_utils:escape_chars( + filename:join(rebar_state:dir(Config), Source1)), case filelib:wildcard(Source1) of - [] -> [Source1]; + [] -> [Source2]; FileList -> FileList end end, Sources), @@ -162,6 +178,22 @@ get_port_spec(Config, OsType, {_Arch, Target, Sources, Opts}) -> objects = ObjectFiles, opts = [port_opt(Config, O) || O <- fill_in_defaults(Opts)]}. +expand_env(Source, Env) -> + case rebar_string:chr(Source, $$) of + 0 -> + %% No variables to expand. Also hides undef on older rebar3. + Source; + _ -> + lists:foldl( + fun({Key, Value}, Acc) -> + %% TODO: the expand_env_variable/3 only expands + %% variables delimited by whitespace and inside + %% ${}. Either fix or add a new function to + %% rebar3 or make a new function here in pc. + rebar_utils:expand_env_variable(Acc, Key, Value) + end, Source, Env) + end. + coerce_extension({win32, nt}, Target) -> switch_to_dll_or_exe(Target); coerce_extension(_OsType, Target) ->