Explorar el Código

recompile all files when a parse transform given as an opt needs updating

there's no way to detect which files actually rely on a parse transform
passed to the compiler via the options (as opposed to `-compile(..)`
so if any parse transforms are in modules that need recompiling just
recompile the world

fixes #1328
pull/1333/head
alisdair sullivan hace 8 años
padre
commit
dad7900d31
Se han modificado 2 ficheros con 118 adiciones y 3 borrados
  1. +15
    -1
      src/rebar_erlc_compiler.erl
  2. +103
    -2
      test/rebar_compile_SUITE.erl

+ 15
- 1
src/rebar_erlc_compiler.erl Ver fichero

@ -202,7 +202,13 @@ compile_dirs(RebarOpts, BaseDir, SrcDirs, OutDir, Opts) ->
G = init_erlcinfo(include_abs_dirs(ErlOpts, BaseDir), AllErlFiles, BaseDir, OutDir),
NeededErlFiles = needed_files(G, ErlOpts, BaseDir, OutDir, AllErlFiles),
{ParseTransforms, Rest} = split_source_files(AllErlFiles, ErlOpts),
NeededErlFiles = case needed_files(G, ErlOpts, BaseDir, OutDir, ParseTransforms) of
[] -> needed_files(G, ErlOpts, BaseDir, OutDir, Rest);
%% at least one parse transform in the opts needs updating, so recompile all
_ -> AllErlFiles
end,
{ErlFirstFiles, ErlOptsFirst} = erl_first_files(RebarOpts, ErlOpts, BaseDir, NeededErlFiles),
{DepErls, OtherErls} = lists:partition(
fun(Source) -> digraph:in_degree(G, Source) > 0 end,
@ -296,6 +302,14 @@ erl_first_files(Opts, ErlOpts, Dir, NeededErlFiles) ->
end, ErlOpts),
{ErlFirstFiles ++ ParseTransformsErls, ErlOptsFirst}.
split_source_files(SourceFiles, ErlOpts) ->
ParseTransforms = proplists:get_all_values(parse_transform, ErlOpts),
lists:partition(fun(Source) ->
lists:member(filename_to_atom(Source), ParseTransforms)
end, SourceFiles).
filename_to_atom(F) -> list_to_atom(filename:rootname(filename:basename(F))).
%% Get subset of SourceFiles which need to be recompiled, respecting
%% dependencies induced by given graph G.
needed_files(G, ErlOpts, Dir, OutDir, SourceFiles) ->

+ 103
- 2
test/rebar_compile_SUITE.erl Ver fichero

@ -42,7 +42,9 @@
deps_build_in_prod/1,
include_file_relative_to_working_directory/1,
include_file_in_src/1,
always_recompile_when_erl_compiler_options_set/1]).
always_recompile_when_erl_compiler_options_set/1,
recompile_when_parse_transform_inline_changes/1,
recompile_when_parse_transform_as_opt_changes/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@ -65,7 +67,9 @@ all() ->
parse_transform_test, erl_first_files_test, mib_test,
umbrella_mib_first_test, only_default_transitive_deps,
clean_all, override_deps, profile_override_deps, deps_build_in_prod,
include_file_relative_to_working_directory, include_file_in_src] ++
include_file_relative_to_working_directory, include_file_in_src,
recompile_when_parse_transform_as_opt_changes,
recompile_when_parse_transform_inline_changes] ++
case erlang:function_exported(os, unsetenv, 1) of
true -> [always_recompile_when_erl_compiler_options_set];
false -> []
@ -1348,5 +1352,102 @@ always_recompile_when_erl_compiler_options_set(Config) ->
_ -> os:putenv("ERL_COMPILER_OPTIONS", ExistingEnv)
end.
recompile_when_parse_transform_inline_changes(Config) ->
AppDir = ?config(apps, Config),
Name = rebar_test_utils:create_random_name("parse_transform_inline_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
ModSrc = <<"-module(example).\n"
"-export([foo/2]).\n"
"-compile([{parse_transform, example_parse_transform}]).\n"
"foo(_, _) -> ok.">>,
ok = file:write_file(filename:join([AppDir, "src", "example.erl"]),
ModSrc),
ParseTransform = <<"-module(example_parse_transform).\n"
"-export([parse_transform/2]).\n"
"parse_transform(AST, _) -> AST.\n">>,
ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
ParseTransform),
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
{ok, Files} = rebar_utils:list_dir(EbinDir),
ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- Files, filename:basename(F, ".beam") == "example"],
timer:sleep(1000),
NewParseTransform = <<"-module(example_parse_transform).\n"
"-export([parse_transform/2]).\n"
"parse_transform(AST, _) -> identity(AST).\n"
"identity(AST) -> AST.\n">>,
ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
NewParseTransform),
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
{ok, NewFiles} = rebar_utils:list_dir(EbinDir),
NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- NewFiles, filename:basename(F, ".beam") == "example"],
?assert(ModTime =/= NewModTime).
recompile_when_parse_transform_as_opt_changes(Config) ->
AppDir = ?config(apps, Config),
Name = rebar_test_utils:create_random_name("parse_transform_opt_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
ModSrc = <<"-module(example).\n"
"-export([foo/2]).\n"
"foo(_, _) -> ok.">>,
ok = file:write_file(filename:join([AppDir, "src", "example.erl"]),
ModSrc),
ParseTransform = <<"-module(example_parse_transform).\n"
"-export([parse_transform/2]).\n"
"parse_transform(AST, _) -> AST.">>,
ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
ParseTransform),
RebarConfig = [{erl_opts, [{parse_transform, example_parse_transform}]}],
rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
{ok, Files} = rebar_utils:list_dir(EbinDir),
ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- Files, filename:basename(F, ".beam") == "example"],
timer:sleep(1000),
NewParseTransform = <<"-module(example_parse_transform).\n"
"-export([parse_transform/2]).\n"
"parse_transform(AST, _) -> identity(AST).\n"
"identity(AST) -> AST.">>,
ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
NewParseTransform),
rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
{ok, NewFiles} = rebar_utils:list_dir(EbinDir),
NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- NewFiles, filename:basename(F, ".beam") == "example"],
?assert(ModTime =/= NewModTime).

Cargando…
Cancelar
Guardar