|
@ -28,7 +28,8 @@ |
|
|
-callback clean([file:filename()], rebar_app_info:t()) -> _. |
|
|
-callback clean([file:filename()], rebar_app_info:t()) -> _. |
|
|
|
|
|
|
|
|
-define(DAG_VSN, 2). |
|
|
-define(DAG_VSN, 2). |
|
|
-define(DAG_FILE, "source.dag"). |
|
|
|
|
|
|
|
|
-define(DAG_ROOT, "source"). |
|
|
|
|
|
-define(DAG_EXT, ".dag"). |
|
|
-type dag_v() :: {digraph:vertex(), term()} | 'false'. |
|
|
-type dag_v() :: {digraph:vertex(), term()} | 'false'. |
|
|
-type dag_e() :: {digraph:vertex(), digraph:vertex()}. |
|
|
-type dag_e() :: {digraph:vertex(), digraph:vertex()}. |
|
|
-type dag() :: {list(dag_v()), list(dag_e()), list(string())}. |
|
|
-type dag() :: {list(dag_v()), list(dag_e()), list(string())}. |
|
@ -49,12 +50,13 @@ compile_all(Compilers, AppInfo) -> |
|
|
_ = code:ensure_loaded(compile), |
|
|
_ = code:ensure_loaded(compile), |
|
|
|
|
|
|
|
|
lists:foreach(fun(CompilerMod) -> |
|
|
lists:foreach(fun(CompilerMod) -> |
|
|
run(CompilerMod, AppInfo), |
|
|
|
|
|
run_on_extra_src_dirs(CompilerMod, AppInfo, fun run/2) |
|
|
|
|
|
end, Compilers), |
|
|
|
|
|
|
|
|
run(CompilerMod, AppInfo, undefined), |
|
|
|
|
|
run_on_extra_src_dirs(CompilerMod, AppInfo, |
|
|
|
|
|
fun(Mod, App) -> run(Mod, App, "extra") end) |
|
|
|
|
|
end, Compilers), |
|
|
ok. |
|
|
ok. |
|
|
|
|
|
|
|
|
run(CompilerMod, AppInfo) -> |
|
|
|
|
|
|
|
|
run(CompilerMod, AppInfo, Label) -> |
|
|
#{src_dirs := SrcDirs, |
|
|
#{src_dirs := SrcDirs, |
|
|
include_dirs := InclDirs, |
|
|
include_dirs := InclDirs, |
|
|
src_ext := SrcExt, |
|
|
src_ext := SrcExt, |
|
@ -69,7 +71,7 @@ run(CompilerMod, AppInfo) -> |
|
|
|
|
|
|
|
|
OutDir = rebar_app_info:out_dir(AppInfo), |
|
|
OutDir = rebar_app_info:out_dir(AppInfo), |
|
|
AbsSrcDirs = [filename:join(BaseDir, SrcDir) || SrcDir <- SrcDirs], |
|
|
AbsSrcDirs = [filename:join(BaseDir, SrcDir) || SrcDir <- SrcDirs], |
|
|
G = init_dag(CompilerMod, AbsInclDirs, AbsSrcDirs, FoundFiles, OutDir, EbinDir), |
|
|
|
|
|
|
|
|
G = init_dag(CompilerMod, AbsInclDirs, AbsSrcDirs, FoundFiles, OutDir, EbinDir, Label), |
|
|
{{FirstFiles, FirstFileOpts}, {RestFiles, Opts}} = CompilerMod:needed_files(G, FoundFiles, |
|
|
{{FirstFiles, FirstFileOpts}, {RestFiles, Opts}} = CompilerMod:needed_files(G, FoundFiles, |
|
|
Mappings, AppInfo), |
|
|
Mappings, AppInfo), |
|
|
true = digraph:delete(G), |
|
|
true = digraph:delete(G), |
|
@ -101,11 +103,12 @@ compile_each([Source | Rest], Opts, Config, Outs, CompilerMod) -> |
|
|
-spec clean([module()], rebar_app_info:t()) -> 'ok'. |
|
|
-spec clean([module()], rebar_app_info:t()) -> 'ok'. |
|
|
clean(Compilers, AppInfo) -> |
|
|
clean(Compilers, AppInfo) -> |
|
|
lists:foreach(fun(CompilerMod) -> |
|
|
lists:foreach(fun(CompilerMod) -> |
|
|
clean_(CompilerMod, AppInfo), |
|
|
|
|
|
run_on_extra_src_dirs(CompilerMod, AppInfo, fun clean_/2) |
|
|
|
|
|
end, Compilers). |
|
|
|
|
|
|
|
|
clean_(CompilerMod, AppInfo, undefined), |
|
|
|
|
|
run_on_extra_src_dirs(CompilerMod, AppInfo, |
|
|
|
|
|
fun(Mod, App) -> clean_(Mod, App, "extra") end) |
|
|
|
|
|
end, Compilers). |
|
|
|
|
|
|
|
|
clean_(CompilerMod, AppInfo) -> |
|
|
|
|
|
|
|
|
clean_(CompilerMod, AppInfo, Label) -> |
|
|
#{src_dirs := SrcDirs, |
|
|
#{src_dirs := SrcDirs, |
|
|
src_ext := SrcExt} = CompilerMod:context(AppInfo), |
|
|
src_ext := SrcExt} = CompilerMod:context(AppInfo), |
|
|
BaseDir = rebar_app_info:dir(AppInfo), |
|
|
BaseDir = rebar_app_info:dir(AppInfo), |
|
@ -114,7 +117,7 @@ clean_(CompilerMod, AppInfo) -> |
|
|
|
|
|
|
|
|
FoundFiles = find_source_files(BaseDir, SrcExt, SrcDirs, Opts), |
|
|
FoundFiles = find_source_files(BaseDir, SrcExt, SrcDirs, Opts), |
|
|
CompilerMod:clean(FoundFiles, AppInfo), |
|
|
CompilerMod:clean(FoundFiles, AppInfo), |
|
|
rebar_file_utils:rm_rf(dag_file(CompilerMod, EbinDir)). |
|
|
|
|
|
|
|
|
rebar_file_utils:rm_rf(dag_file(CompilerMod, EbinDir, Label)). |
|
|
|
|
|
|
|
|
-spec needs_compile(filename:all(), extension(), [{extension(), file:dirname()}]) -> boolean(). |
|
|
-spec needs_compile(filename:all(), extension(), [{extension(), file:dirname()}]) -> boolean(). |
|
|
needs_compile(Source, OutExt, Mappings) -> |
|
|
needs_compile(Source, OutExt, Mappings) -> |
|
@ -133,11 +136,17 @@ run_on_extra_src_dirs([], _CompilerMod, _AppInfo, _Fun) -> |
|
|
run_on_extra_src_dirs([Dir | Rest], CompilerMod, AppInfo, Fun) -> |
|
|
run_on_extra_src_dirs([Dir | Rest], CompilerMod, AppInfo, Fun) -> |
|
|
case filelib:is_dir(filename:join(rebar_app_info:dir(AppInfo), Dir)) of |
|
|
case filelib:is_dir(filename:join(rebar_app_info:dir(AppInfo), Dir)) of |
|
|
true -> |
|
|
true -> |
|
|
|
|
|
OldSrcDirs = rebar_app_info:get(AppInfo, src_dirs, ["src"]), |
|
|
|
|
|
AppDir = rebar_app_info:dir(AppInfo), |
|
|
EbinDir = filename:join(rebar_app_info:out_dir(AppInfo), Dir), |
|
|
EbinDir = filename:join(rebar_app_info:out_dir(AppInfo), Dir), |
|
|
AppInfo1 = rebar_app_info:ebin_dir(AppInfo, EbinDir), |
|
|
AppInfo1 = rebar_app_info:ebin_dir(AppInfo, EbinDir), |
|
|
AppInfo2 = rebar_app_info:set(AppInfo1, src_dirs, [Dir]), |
|
|
AppInfo2 = rebar_app_info:set(AppInfo1, src_dirs, [Dir]), |
|
|
AppInfo3 = rebar_app_info:set(AppInfo2, extra_src_dirs, ["src"]), |
|
|
|
|
|
Fun(CompilerMod, AppInfo3); |
|
|
|
|
|
|
|
|
AppInfo3 = rebar_app_info:set(AppInfo2, extra_src_dirs, OldSrcDirs), |
|
|
|
|
|
AppInfo4 = add_to_includes( % give access to .hrl in app's src/ |
|
|
|
|
|
AppInfo3, |
|
|
|
|
|
[filename:join([AppDir, D]) || D <- OldSrcDirs] |
|
|
|
|
|
), |
|
|
|
|
|
Fun(CompilerMod, AppInfo4); |
|
|
_ -> |
|
|
_ -> |
|
|
ok |
|
|
ok |
|
|
end, |
|
|
end, |
|
@ -170,8 +179,16 @@ find_source_files(BaseDir, SrcExt, SrcDirs, Opts) -> |
|
|
rebar_utils:find_files_in_dirs([filename:join(BaseDir, SrcDir)], SourceExtRe, Recursive) |
|
|
rebar_utils:find_files_in_dirs([filename:join(BaseDir, SrcDir)], SourceExtRe, Recursive) |
|
|
end, SrcDirs). |
|
|
end, SrcDirs). |
|
|
|
|
|
|
|
|
dag_file(CompilerMod, Dir) -> |
|
|
|
|
|
filename:join([rebar_dir:local_cache_dir(Dir), CompilerMod, ?DAG_FILE]). |
|
|
|
|
|
|
|
|
%% @private generate the name for the DAG based on the compiler module and |
|
|
|
|
|
%% a custom label, both of which are used to prevent various compiler runs |
|
|
|
|
|
%% from clobbering each other. The label `undefined' is kept for a default |
|
|
|
|
|
%% run of the compiler, to keep in line with previous versions of the file. |
|
|
|
|
|
dag_file(CompilerMod, Dir, undefined) -> |
|
|
|
|
|
filename:join([rebar_dir:local_cache_dir(Dir), CompilerMod, |
|
|
|
|
|
?DAG_ROOT ++ ?DAG_EXT]); |
|
|
|
|
|
dag_file(CompilerMod, Dir, Label) -> |
|
|
|
|
|
filename:join([rebar_dir:local_cache_dir(Dir), CompilerMod, |
|
|
|
|
|
?DAG_ROOT ++ "_" ++ Label ++ ?DAG_EXT]). |
|
|
|
|
|
|
|
|
%% private graph functions |
|
|
%% private graph functions |
|
|
|
|
|
|
|
@ -179,20 +196,22 @@ dag_file(CompilerMod, Dir) -> |
|
|
%% parse transforms, behaviours etc.) located in their directories or given |
|
|
%% parse transforms, behaviours etc.) located in their directories or given |
|
|
%% InclDirs. Note that last modification times stored in vertices already respect |
|
|
%% InclDirs. Note that last modification times stored in vertices already respect |
|
|
%% dependencies induced by given graph G. |
|
|
%% dependencies induced by given graph G. |
|
|
init_dag(Compiler, InclDirs, SrcDirs, Erls, Dir, EbinDir) -> |
|
|
|
|
|
|
|
|
init_dag(Compiler, InclDirs, SrcDirs, Erls, Dir, EbinDir, Label) -> |
|
|
G = digraph:new([acyclic]), |
|
|
G = digraph:new([acyclic]), |
|
|
try restore_dag(Compiler, G, InclDirs, Dir) |
|
|
|
|
|
|
|
|
try restore_dag(Compiler, G, InclDirs, Dir, Label) |
|
|
catch |
|
|
catch |
|
|
_:_ -> |
|
|
_:_ -> |
|
|
?WARN("Failed to restore ~ts file. Discarding it.~n", [dag_file(Compiler, Dir)]), |
|
|
|
|
|
file:delete(dag_file(Compiler, Dir)) |
|
|
|
|
|
|
|
|
?WARN("Failed to restore ~ts file. Discarding it.~n", [dag_file(Compiler, Dir, Label)]), |
|
|
|
|
|
file:delete(dag_file(Compiler, Dir, Label)) |
|
|
end, |
|
|
end, |
|
|
Dirs = lists:usort(InclDirs ++ SrcDirs), |
|
|
Dirs = lists:usort(InclDirs ++ SrcDirs), |
|
|
%% A source file may have been renamed or deleted. Remove it from the graph |
|
|
%% A source file may have been renamed or deleted. Remove it from the graph |
|
|
%% and remove any beam file for that source if it exists. |
|
|
%% and remove any beam file for that source if it exists. |
|
|
Modified = maybe_rm_beams_and_edges(G, EbinDir, Erls), |
|
|
Modified = maybe_rm_beams_and_edges(G, EbinDir, Erls), |
|
|
Modified1 = lists:foldl(update_dag_fun(G, Compiler, Dirs), Modified, Erls), |
|
|
Modified1 = lists:foldl(update_dag_fun(G, Compiler, Dirs), Modified, Erls), |
|
|
if Modified1 -> store_dag(Compiler, G, InclDirs, Dir); not Modified1 -> ok end, |
|
|
|
|
|
|
|
|
if Modified1 -> store_dag(Compiler, G, InclDirs, Dir, Label); |
|
|
|
|
|
not Modified1 -> ok |
|
|
|
|
|
end, |
|
|
G. |
|
|
G. |
|
|
|
|
|
|
|
|
maybe_rm_beams_and_edges(G, Dir, Files) -> |
|
|
maybe_rm_beams_and_edges(G, Dir, Files) -> |
|
@ -229,8 +248,8 @@ maybe_rm_beam_and_edge(G, OutDir, Source) -> |
|
|
target_base(OutDir, Source) -> |
|
|
target_base(OutDir, Source) -> |
|
|
filename:join(OutDir, filename:basename(Source, ".erl")). |
|
|
filename:join(OutDir, filename:basename(Source, ".erl")). |
|
|
|
|
|
|
|
|
restore_dag(Compiler, G, InclDirs, Dir) -> |
|
|
|
|
|
case file:read_file(dag_file(Compiler, Dir)) of |
|
|
|
|
|
|
|
|
restore_dag(Compiler, G, InclDirs, Dir, Label) -> |
|
|
|
|
|
case file:read_file(dag_file(Compiler, Dir, Label)) of |
|
|
{ok, Data} -> |
|
|
{ok, Data} -> |
|
|
% Since externally passed InclDirs can influence dependency graph (see |
|
|
% Since externally passed InclDirs can influence dependency graph (see |
|
|
% modify_dag), we have to check here that they didn't change. |
|
|
% modify_dag), we have to check here that they didn't change. |
|
@ -248,10 +267,10 @@ restore_dag(Compiler, G, InclDirs, Dir) -> |
|
|
ok |
|
|
ok |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
store_dag(Compiler, G, InclDirs, Dir) -> |
|
|
|
|
|
|
|
|
store_dag(Compiler, G, InclDirs, Dir, Label) -> |
|
|
Vs = lists:map(fun(V) -> digraph:vertex(G, V) end, digraph:vertices(G)), |
|
|
Vs = lists:map(fun(V) -> digraph:vertex(G, V) end, digraph:vertices(G)), |
|
|
Es = lists:map(fun(E) -> digraph:edge(G, E) end, digraph:edges(G)), |
|
|
Es = lists:map(fun(E) -> digraph:edge(G, E) end, digraph:edges(G)), |
|
|
File = dag_file(Compiler, Dir), |
|
|
|
|
|
|
|
|
File = dag_file(Compiler, Dir, Label), |
|
|
ok = filelib:ensure_dir(File), |
|
|
ok = filelib:ensure_dir(File), |
|
|
Data = term_to_binary(#dag{info={Vs, Es, InclDirs}}, [{compressed, 2}]), |
|
|
Data = term_to_binary(#dag{info={Vs, Es, InclDirs}}, [{compressed, 2}]), |
|
|
file:write_file(File, Data). |
|
|
file:write_file(File, Data). |
|
@ -313,3 +332,10 @@ update_max_modified_deps(G, Source) -> |
|
|
end, 0, [Source | digraph:out_neighbours(G, Source)]), |
|
|
end, 0, [Source | digraph:out_neighbours(G, Source)]), |
|
|
digraph:add_vertex(G, Source, MaxModified), |
|
|
digraph:add_vertex(G, Source, MaxModified), |
|
|
MaxModified. |
|
|
MaxModified. |
|
|
|
|
|
|
|
|
|
|
|
add_to_includes(AppInfo, Dirs) -> |
|
|
|
|
|
Opts = rebar_app_info:opts(AppInfo), |
|
|
|
|
|
List = rebar_opts:get(Opts, erl_opts, []), |
|
|
|
|
|
NewErlOpts = [{i, Dir} || Dir <- Dirs] ++ List, |
|
|
|
|
|
NewOpts = rebar_opts:set(Opts, erl_opts, NewErlOpts), |
|
|
|
|
|
rebar_app_info:opts(AppInfo, NewOpts). |