From 2ad49d339ae7a7f43ea3fed43d9bd321ad29a823 Mon Sep 17 00:00:00 2001 From: Carl-Johan Kjellander Date: Thu, 18 Jan 2018 14:14:26 +0100 Subject: [PATCH 1/8] export env from state during compilation --- src/pc_compilation.erl | 10 +++++----- src/pc_port_specs.erl | 12 ++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/pc_compilation.erl b/src/pc_compilation.erl index ed3f9e9..765e660 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:environment(Spec, State), Cmd = expand_command(LinkTemplate, Env, pc_util:strjoin(Bins, " "), Target), @@ -91,18 +91,18 @@ port_deps(SourceFiles) -> %% == compilation == %% -compile_sources(Config, Specs) -> +compile_sources(State, Specs) -> {NewBins, Db} = lists:foldl( fun(Spec, Acc) -> Sources = pc_port_specs:sources(Spec), Type = pc_port_specs:type(Spec), - Env = pc_port_specs:environment(Spec), - compile_each(Config, Sources, Type, Env, Acc) + Env = pc_port_specs:environment(Spec, State), + compile_each(State, Sources, Type, Env, Acc) end, {[], []}, Specs), %% Rewrite clang compile commands database file only if something %% was compiled. - case {NewBins, rebar_state:get(Config, pc_clang_db, false)} of + case {NewBins, rebar_state:get(State, pc_clang_db, false)} of {[], _} -> ok; {_, true} -> diff --git a/src/pc_port_specs.erl b/src/pc_port_specs.erl index ab9de58..fabf354 100644 --- a/src/pc_port_specs.erl +++ b/src/pc_port_specs.erl @@ -32,6 +32,7 @@ construct/1, %% spec accessors environment/1, + environment/2, objects/1, sources/1, target/1, @@ -69,6 +70,9 @@ construct(State) -> %% == Spec Accessors == environment(#spec{opts = Opts}) -> proplists:get_value(env, Opts). +environment(#spec{opts = Opts}, State) -> + proplists:get_value(env, Opts) ++ + try_and_get_env(State). objects(#spec{objects = Objects}) -> Objects. sources(#spec{sources = Sources}) -> Sources. target(#spec{target = Target}) -> Target. @@ -79,6 +83,14 @@ link_lang(#spec{link_lang = LinkLang}) -> LinkLang. %%% Internal Functions %%%=================================================================== +try_and_get_env(State) -> + case catch rebar_state:env(State) of + {'EXIT', _} -> + []; + Env -> + Env + end. + port_spec_from_legacy(Config) -> %% Get the target from the so_name variable Target = case rebar_state:get(Config, so_name, undefined) of From ea0b87aa3ed2ffb23943b89b4febfdeaf935d504 Mon Sep 17 00:00:00 2001 From: Carl-Johan Kjellander Date: Fri, 19 Jan 2018 11:51:44 +0100 Subject: [PATCH 2/8] expand env in port specs --- src/pc_port_specs.erl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pc_port_specs.erl b/src/pc_port_specs.erl index fabf354..e1a2324 100644 --- a/src/pc_port_specs.erl +++ b/src/pc_port_specs.erl @@ -145,13 +145,19 @@ 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 = rebar_state:env(Config), SourceFiles = lists:flatmap( fun(Source) -> - Source1 = rebar_utils:escape_chars( - filename:join(rebar_state:dir(Config), Source)), + Source1 = + lists:foldl( + fun({Key, Value}, Acc) -> + rebar_utils:expand_env_variable(Acc, Key, Value) + end, 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), From 38af9e19c1c03900ac38be63ca0803613fff21e1 Mon Sep 17 00:00:00 2001 From: Carl-Johan Kjellander Date: Fri, 19 Jan 2018 15:26:21 +0100 Subject: [PATCH 3/8] break out function and hide undef on older rebar3 --- src/pc_port_specs.erl | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/pc_port_specs.erl b/src/pc_port_specs.erl index e1a2324..d5554bf 100644 --- a/src/pc_port_specs.erl +++ b/src/pc_port_specs.erl @@ -149,11 +149,7 @@ get_port_spec(Config, OsType, {_Arch, Target, Sources, Opts}) -> SourceFiles = lists:flatmap( fun(Source) -> - Source1 = - lists:foldl( - fun({Key, Value}, Acc) -> - rebar_utils:expand_env_variable(Acc, Key, Value) - end, Source, Env), + Source1 = expand_env(Source, Env), Source2 = rebar_utils:escape_chars( filename:join(rebar_state:dir(Config), Source1)), case filelib:wildcard(Source1) of @@ -180,6 +176,18 @@ 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) -> + 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) -> From 9958c6f0d9e4344d048ca43bb3d3e0aa81bdc594 Mon Sep 17 00:00:00 2001 From: Carl-Johan Kjellander Date: Fri, 19 Jan 2018 15:39:10 +0100 Subject: [PATCH 4/8] expand README to explain how to use env vars --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 7eb9055..f2c4f81 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 you 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 From 22839beb3a0c284efc8fe73d99205f40d7106a44 Mon Sep 17 00:00:00 2001 From: Carl-Johan Kjellander Date: Thu, 15 Feb 2018 08:16:51 +0100 Subject: [PATCH 5/8] fix typo in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2c4f81..ffd2f3c 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ BELOW HERE BE DRAGONS %% ["c_src/nif.c", %% "${REBAR_DEPS_DIR}/foo/bar.c"]}]}. %% -%% This is a _very_ good way to be able to use you code both +%% 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. From c9e8cc95da8e666c0000feb3be23709c06fd0dfb Mon Sep 17 00:00:00 2001 From: Carl-Johan Kjellander Date: Thu, 15 Feb 2018 08:17:05 +0100 Subject: [PATCH 6/8] add TODO on variable expansion --- src/pc_port_specs.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pc_port_specs.erl b/src/pc_port_specs.erl index d5554bf..9972046 100644 --- a/src/pc_port_specs.erl +++ b/src/pc_port_specs.erl @@ -184,6 +184,10 @@ expand_env(Source, Env) -> _ -> 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. From 455cc74425e405f602a8f9ad97f974761e1404d6 Mon Sep 17 00:00:00 2001 From: Carl-Johan Kjellander Date: Mon, 26 Feb 2018 09:01:22 +0100 Subject: [PATCH 7/8] adapt fix for new inteface --- src/pc_compilation.erl | 10 +++++----- src/pc_port_specs.erl | 26 +++++++++++++++----------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/pc_compilation.erl b/src/pc_compilation.erl index 765e660..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, State), + Env = pc_port_specs:create_env(State, Spec), Cmd = expand_command(LinkTemplate, Env, pc_util:strjoin(Bins, " "), Target), @@ -91,18 +91,18 @@ port_deps(SourceFiles) -> %% == compilation == %% -compile_sources(State, Specs) -> +compile_sources(Config, Specs) -> {NewBins, Db} = lists:foldl( fun(Spec, Acc) -> Sources = pc_port_specs:sources(Spec), Type = pc_port_specs:type(Spec), - Env = pc_port_specs:environment(Spec, State), - compile_each(State, Sources, Type, Env, Acc) + 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 %% was compiled. - case {NewBins, rebar_state:get(State, pc_clang_db, false)} of + case {NewBins, rebar_state:get(Config, pc_clang_db, false)} of {[], _} -> ok; {_, true} -> diff --git a/src/pc_port_specs.erl b/src/pc_port_specs.erl index 9972046..672c588 100644 --- a/src/pc_port_specs.erl +++ b/src/pc_port_specs.erl @@ -30,9 +30,10 @@ -export([ construct/1, + create_env/2, %% spec accessors environment/1, - environment/2, + opts/1, objects/1, sources/1, target/1, @@ -67,12 +68,15 @@ construct(State) -> {ok, [S || S <- Specs, S#spec.sources /= []]} end. +create_env(State, Spec) -> + Opts = rebar_state:opts(State), + pc_port_specs:environment(Spec) ++ + try_and_create_env(State, Opts). + %% == Spec Accessors == environment(#spec{opts = Opts}) -> proplists:get_value(env, Opts). -environment(#spec{opts = Opts}, State) -> - proplists:get_value(env, Opts) ++ - try_and_get_env(State). +opts(#spec{opts = Opts}) -> Opts. objects(#spec{objects = Objects}) -> Objects. sources(#spec{sources = Sources}) -> Sources. target(#spec{target = Target}) -> Target. @@ -83,12 +87,11 @@ link_lang(#spec{link_lang = LinkLang}) -> LinkLang. %%% Internal Functions %%%=================================================================== -try_and_get_env(State) -> - case catch rebar_state:env(State) of - {'EXIT', _} -> - []; - Env -> - Env +try_and_create_env(State, Opts) -> + _ = code:ensure_loaded(rebar_env), + case erlang:function_exported(rebar_env, create_env, 2) of + false -> []; + true -> rebar_env:create_env(State, Opts) end. port_spec_from_legacy(Config) -> @@ -145,7 +148,8 @@ 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 = rebar_state:env(Config), + StateOpts = rebar_state:opts(Config), + Env = try_and_create_env(Config, StateOpts), SourceFiles = lists:flatmap( fun(Source) -> From b56a837b0e126b718f6f7177ddd7a8a79a5fc2a7 Mon Sep 17 00:00:00 2001 From: Carl-Johan Kjellander Date: Mon, 26 Feb 2018 16:09:21 +0100 Subject: [PATCH 8/8] hide some of the internals of rebar --- src/pc_port_specs.erl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pc_port_specs.erl b/src/pc_port_specs.erl index 672c588..7f390be 100644 --- a/src/pc_port_specs.erl +++ b/src/pc_port_specs.erl @@ -69,9 +69,8 @@ construct(State) -> end. create_env(State, Spec) -> - Opts = rebar_state:opts(State), pc_port_specs:environment(Spec) ++ - try_and_create_env(State, Opts). + try_and_create_env(State). %% == Spec Accessors == @@ -87,11 +86,11 @@ link_lang(#spec{link_lang = LinkLang}) -> LinkLang. %%% Internal Functions %%%=================================================================== -try_and_create_env(State, Opts) -> +try_and_create_env(State) -> _ = code:ensure_loaded(rebar_env), - case erlang:function_exported(rebar_env, create_env, 2) of + case erlang:function_exported(rebar_env, create_env, 1) of false -> []; - true -> rebar_env:create_env(State, Opts) + true -> rebar_env:create_env(State) end. port_spec_from_legacy(Config) -> @@ -148,8 +147,7 @@ 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}) -> - StateOpts = rebar_state:opts(Config), - Env = try_and_create_env(Config, StateOpts), + Env = try_and_create_env(Config), SourceFiles = lists:flatmap( fun(Source) ->