From 7fa628d61558a4051c4e415f33cae3cf0927ca2c Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Mon, 16 Feb 2015 14:32:25 -0800 Subject: check already compiled modules compile arguments against current compile arguments to ensure compile results as as intended --- src/rebar_erlc_compiler.erl | 35 +++++++++++++++++++------- test/rebar_compile_SUITE.erl | 58 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index b096705..949fc45 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -254,11 +254,26 @@ include_path(Source, Config) -> ++ proplists:get_all_values(i, ErlOpts)). -spec needs_compile(file:filename(), file:filename(), - [string()]) -> boolean(). -needs_compile(Source, Target, Parents) -> + list(), [string()]) -> boolean(). +needs_compile(Source, Target, Opts, Parents) -> TargetLastMod = filelib:last_modified(Target), - lists:any(fun(I) -> TargetLastMod < filelib:last_modified(I) end, - [Source] ++ Parents). + F = fun(I) -> source_changed(TargetLastMod, I) end, + lists:any(F, [Source] ++ Parents) orelse opts_changed(Opts, Target). + +source_changed(TargetLastMod, I) -> TargetLastMod < filelib:last_modified(I). + +opts_changed(Opts, Target) -> + Basename = filename:basename(Target, ".beam"), + Dirname = filename:dirname(Target), + ObjectFile = filename:join([Dirname, Basename]), + case code:load_abs(ObjectFile) of + {module, Mod} -> + Compile = Mod:module_info(compile), + lists:sort(Opts) =/= lists:sort(proplists:get_value(options, + Compile, + undefined)); + {error, nofile} -> true + end. check_erlcinfo(_Config, #erlcinfo{vsn=?ERLCINFO_VSN}) -> ok; @@ -427,13 +442,15 @@ internal_erl_compile(Config, Dir, Source, OutDir, ErlOpts, G) -> Target = filename:join([OutDir | string:tokens(Module, ".")]) ++ ".beam", ok = filelib:ensure_dir(Target), + %% Construct the compile opts + Opts = [{outdir, filename:dirname(Target)}] ++ + ErlOpts ++ [{i, filename:join(Dir, "include")}], + %% If the file needs compilation, based on last mod date of includes or %% the target - case needs_compile(Source, Target, Parents) of + case needs_compile(Source, Target, Opts, Parents) of true -> - Opts = [{outdir, filename:dirname(Target)}] ++ - ErlOpts ++ [{i, filename:join(Dir, "include")}, return], - case compile:file(Source, Opts) of + case compile:file(Source, Opts ++ [return]) of {ok, _Mod} -> ok; {ok, _Mod, Ws} -> @@ -489,7 +506,7 @@ compile_xrl_yrl(Config, Source, Target, Opts, Mod) -> Dir = rebar_state:dir(Config), Opts1 = [{includefile, filename:join(Dir, I)} || {includefile, I} <- Opts, filename:pathtype(I) =:= relative], - case needs_compile(Source, Target, []) of + case needs_compile(Source, Target, Opts1, []) of true -> case Mod:file(Source, Opts1 ++ [{return, true}]) of {ok, _} -> diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl index 627e834..fd1899f 100644 --- a/test/rebar_compile_SUITE.erl +++ b/test/rebar_compile_SUITE.erl @@ -8,7 +8,9 @@ build_basic_app/1, build_release_apps/1, build_checkout_apps/1, - build_checkout_deps/1]). + build_checkout_deps/1, + recompile_when_opts_change/1, + dont_recompile_when_opts_dont_change/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -28,7 +30,8 @@ init_per_testcase(_, Config) -> all() -> [build_basic_app, build_release_apps, - build_checkout_apps, build_checkout_deps]. + build_checkout_apps, build_checkout_deps, + recompile_when_opts_change, dont_recompile_when_opts_dont_change]. build_basic_app(Config) -> AppDir = ?config(apps, Config), @@ -88,3 +91,54 @@ build_checkout_deps(Config) -> ok = application:load(list_to_atom(Name2)), Loaded = application:loaded_applications(), {_, _, Vsn2} = lists:keyfind(list_to_atom(Name2), 1, Loaded). + +recompile_when_opts_change(Config) -> + AppDir = ?config(apps, Config), + EbinDir = filename:join([AppDir, "ebin"]), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + {ok, Files} = file:list_dir(EbinDir), + ModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- Files, filename:extension(F) == ".beam"], + + timer:sleep(1000), + + rebar_test_utils:create_config(AppDir, [{erl_opts, [{d, some_define}]}]), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + {ok, NewFiles} = file:list_dir(EbinDir), + NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- NewFiles, filename:extension(F) == ".beam"], + + ?assert(ModTime =/= NewModTime). + + +dont_recompile_when_opts_dont_change(Config) -> + AppDir = ?config(apps, Config), + EbinDir = filename:join([AppDir, "ebin"]), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + {ok, Files} = file:list_dir(EbinDir), + ModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- Files, filename:extension(F) == ".beam"], + + timer:sleep(1000), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + {ok, NewFiles} = file:list_dir(EbinDir), + NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- NewFiles, filename:extension(F) == ".beam"], + + ?assert(ModTime == NewModTime). \ No newline at end of file -- cgit v1.1