|
|
@ -30,7 +30,7 @@ |
|
|
|
clean/2]). |
|
|
|
|
|
|
|
%% make available for rebar_eunit until there is a better option |
|
|
|
-export([do_compile/8, compile_opts/2, list_hrls/2]). |
|
|
|
-export([hrls_check/3]). |
|
|
|
|
|
|
|
-include("rebar.hrl"). |
|
|
|
|
|
|
@ -39,18 +39,30 @@ |
|
|
|
%% =================================================================== |
|
|
|
|
|
|
|
compile(Config, _AppFile) -> |
|
|
|
do_compile(Config, "src/*.erl", "ebin", ".erl", ".beam", |
|
|
|
fun list_hrls/2, fun compile_erl/2, |
|
|
|
rebar_config:get_list(Config, erl_first_files, [])), |
|
|
|
do_compile(Config, "mibs/*.mib", "priv/mibs", ".mib", ".bin", |
|
|
|
undefined, fun compile_mib/2, |
|
|
|
rebar_config:get_list(Config, mib_first_files, [])). |
|
|
|
rebar_base_compiler:run(Config, "src", ".erl", "ebin", ".beam", |
|
|
|
rebar_config:get_list(Config, erl_first_files, []), |
|
|
|
fun compile_erl/3, |
|
|
|
[recurse_source_dir, |
|
|
|
{needs_compile_checks, [fun hrls_check/3]}]), |
|
|
|
|
|
|
|
rebar_base_compiler:run(Config, "mibs", ".mib", "priv/mibs", ".bin", |
|
|
|
rebar_config:get_list(Config, mib_first_files, []), |
|
|
|
fun compile_mib/3, |
|
|
|
[]). |
|
|
|
|
|
|
|
clean(_Config, _AppFile) -> |
|
|
|
%% TODO: This would be more portable if it used Erlang to traverse |
|
|
|
%% the dir structure and delete each file; however it would also |
|
|
|
%% much slower. |
|
|
|
[] = os:cmd("rm -f ebin/*.beam priv/mibs/*.bin"), |
|
|
|
ok = rebar_file_utils:rm_rf("ebin/*.beam priv/mibs/*.bin"), |
|
|
|
|
|
|
|
%% Erlang compilation is recursive, so it's possible that we have a nested |
|
|
|
%% directory structure in ebin with .beam files within. As such, we want |
|
|
|
%% to scan whatever is left in the ebin/ directory for sub-dirs which |
|
|
|
%% satisfy our criteria. TODO: Is there a better way to do this? |
|
|
|
BeamFiles = filelib:fold_files("ebin", "^.*\\.beam\$", true, |
|
|
|
fun(F, BeamFiles) -> BeamFiles ++ [F] end, []), |
|
|
|
rebar_file_utils:delete_each(BeamFiles), |
|
|
|
ok. |
|
|
|
|
|
|
|
|
|
|
@ -59,71 +71,11 @@ clean(_Config, _AppFile) -> |
|
|
|
%% Internal functions |
|
|
|
%% =================================================================== |
|
|
|
|
|
|
|
do_compile(Config, SrcWildcard, OutDir, InExt, OutExt, |
|
|
|
IncludeFn, CompileFn, FirstFiles) -> |
|
|
|
case filelib:wildcard(SrcWildcard) of |
|
|
|
[] -> |
|
|
|
ok; |
|
|
|
FoundFiles when is_list(FoundFiles) -> |
|
|
|
%% Ensure that the FirstFiles are compiled first; drop them from the |
|
|
|
%% FoundFiles and compile them in sequence |
|
|
|
FirstTargets = [{Fs, target_file(Fs, OutDir, InExt, OutExt)} || Fs <- FirstFiles], |
|
|
|
RestTargets = [{Fs, target_file(Fs, OutDir, InExt, OutExt)} || |
|
|
|
Fs <- drop_each(FirstFiles, FoundFiles)], |
|
|
|
|
|
|
|
%% Make sure target directory exists |
|
|
|
ok = filelib:ensure_dir(target_file(hd(FoundFiles), OutDir, InExt, OutExt)), |
|
|
|
|
|
|
|
%% Compile first targets in sequence |
|
|
|
compile_each(FirstTargets, Config, IncludeFn, CompileFn), |
|
|
|
|
|
|
|
%% Spin up workers |
|
|
|
Self = self(), |
|
|
|
Pids = [spawn_monitor(fun() -> compile_worker(Self) end) || _I <- lists:seq(1,3)], |
|
|
|
|
|
|
|
%% Process rest of targets |
|
|
|
compile_queue(Pids, RestTargets, Config, IncludeFn, CompileFn) |
|
|
|
end. |
|
|
|
|
|
|
|
drop_each([], List) -> |
|
|
|
List; |
|
|
|
drop_each([Member | Rest], List) -> |
|
|
|
drop_each(Rest, lists:delete(Member, List)). |
|
|
|
|
|
|
|
compile_each([], _Config, _IncludeFn, _CompileFn) -> |
|
|
|
ok; |
|
|
|
compile_each([{Src, Target} | Rest], Config, IncludeFn, CompileFn) -> |
|
|
|
case needs_compile(Src, Target, IncludeFn, Config) of |
|
|
|
true -> |
|
|
|
?CONSOLE("Compiling ~s\n", [Src]), |
|
|
|
CompileFn(Src, Config); |
|
|
|
false -> |
|
|
|
?INFO("Skipping ~s\n", [Src]), |
|
|
|
ok |
|
|
|
end, |
|
|
|
compile_each(Rest, Config, IncludeFn, CompileFn). |
|
|
|
|
|
|
|
needs_compile(Src, Target, IncludeFn, Config) -> |
|
|
|
TargetLM = filelib:last_modified(Target), |
|
|
|
case TargetLM < filelib:last_modified(Src) of |
|
|
|
true -> |
|
|
|
true; |
|
|
|
false -> |
|
|
|
if is_function(IncludeFn) -> |
|
|
|
lists:any(fun(I) -> |
|
|
|
TargetLM < filelib:last_modified(I) |
|
|
|
end, |
|
|
|
IncludeFn(Src, Config)); |
|
|
|
true -> |
|
|
|
false |
|
|
|
end |
|
|
|
end. |
|
|
|
hrls_check(Source, Target, Config) -> |
|
|
|
TargetLastMod = filelib:last_modified(Target), |
|
|
|
lists:any(fun(I) -> TargetLastMod < filelib:last_modified(I) end, |
|
|
|
list_hrls(Source, Config)). |
|
|
|
|
|
|
|
target_file(F, TargetDir, InExt, OutExt) -> |
|
|
|
filename:join([TargetDir, filename:basename(F, InExt) ++ OutExt]). |
|
|
|
|
|
|
|
compile_opts(Config, Key) -> |
|
|
|
rebar_config:get_list(Config, Key, []). |
|
|
|
|
|
|
|
list_hrls(Src, Config) -> |
|
|
|
case epp:open(Src, include_path(Src, Config)) of |
|
|
@ -134,26 +86,31 @@ list_hrls(Src, Config) -> |
|
|
|
false |
|
|
|
end. |
|
|
|
|
|
|
|
include_path(Src, Config) -> |
|
|
|
[filename:dirname(Src)|compile_opts(Config, i)]. |
|
|
|
|
|
|
|
extract_includes(Epp, Src) -> |
|
|
|
case epp:parse_erl_form(Epp) of |
|
|
|
{ok, {attribute, 1, file, {Src, 1}}} -> |
|
|
|
extract_includes(Epp, Src); |
|
|
|
{ok, {attribute, 1, file, {IncFile, 1}}} -> |
|
|
|
{ok, {attribute, 1, file, {Src, 1}}} -> |
|
|
|
extract_includes(Epp, Src); |
|
|
|
{ok, {attribute, 1, file, {IncFile, 1}}} -> |
|
|
|
[IncFile|extract_includes(Epp, Src)]; |
|
|
|
{ok, _} -> |
|
|
|
extract_includes(Epp, Src); |
|
|
|
{eof, _} -> |
|
|
|
epp:close(Epp), |
|
|
|
[]; |
|
|
|
{error, _Error} -> |
|
|
|
extract_includes(Epp, Src) |
|
|
|
{ok, _} -> |
|
|
|
extract_includes(Epp, Src); |
|
|
|
{eof, _} -> |
|
|
|
epp:close(Epp), |
|
|
|
[]; |
|
|
|
{error, _Error} -> |
|
|
|
extract_includes(Epp, Src) |
|
|
|
end. |
|
|
|
|
|
|
|
compile_erl(Source, Config) -> |
|
|
|
Opts = [{i, "include"}, {outdir, "ebin"}, report, return] ++ compile_opts(Config, erl_opts), |
|
|
|
include_path(Source, Config) -> |
|
|
|
[filename:dirname(Source) | compile_opts(Config, i)]. |
|
|
|
|
|
|
|
compile_opts(Config, Key) -> |
|
|
|
rebar_config:get_list(Config, Key, []). |
|
|
|
|
|
|
|
compile_erl(Source, Target, Config) -> |
|
|
|
Opts = [{i, "include"}, {outdir, filename:dirname(Target)}, report, return] ++ |
|
|
|
compile_opts(Config, erl_opts), |
|
|
|
case compile:file(Source, Opts) of |
|
|
|
{ok, _, []} -> |
|
|
|
ok; |
|
|
@ -169,7 +126,7 @@ compile_erl(Source, Config) -> |
|
|
|
?FAIL |
|
|
|
end. |
|
|
|
|
|
|
|
compile_mib(Source, Config) -> |
|
|
|
compile_mib(Source, _Target, Config) -> |
|
|
|
Opts = [{outdir, "priv/mibs"}, {i, ["priv/mibs"]}] ++ compile_opts(Config, mib_opts), |
|
|
|
case snmpc:compile(Source, Opts) of |
|
|
|
{ok, _} -> |
|
|
@ -177,58 +134,3 @@ compile_mib(Source, Config) -> |
|
|
|
{error, compilation_failed} -> |
|
|
|
?FAIL |
|
|
|
end. |
|
|
|
|
|
|
|
compile_queue([], [], _Config, _IncludeFn, _CompileFn) -> |
|
|
|
ok; |
|
|
|
compile_queue(Pids, Targets, Config, IncludeFn, CompileFn) -> |
|
|
|
receive |
|
|
|
{next, Worker} -> |
|
|
|
case Targets of |
|
|
|
[] -> |
|
|
|
Worker ! empty, |
|
|
|
compile_queue(Pids, Targets, Config, IncludeFn, CompileFn); |
|
|
|
[{Src, Target} | Rest] -> |
|
|
|
Worker ! {compile, Src, Target, Config, IncludeFn, CompileFn}, |
|
|
|
compile_queue(Pids, Rest, Config, IncludeFn, CompileFn) |
|
|
|
end; |
|
|
|
|
|
|
|
{fail, Error} -> |
|
|
|
?DEBUG("Worker compilation failed: ~p\n", [Error]), |
|
|
|
?FAIL; |
|
|
|
|
|
|
|
{compiled, Source} -> |
|
|
|
?CONSOLE("Compiled ~s\n", [Source]), |
|
|
|
compile_queue(Pids, Targets, Config, IncludeFn, CompileFn); |
|
|
|
|
|
|
|
{'DOWN', Mref, _, Pid, normal} -> |
|
|
|
?DEBUG("Worker exited cleanly\n", []), |
|
|
|
Pids2 = lists:delete({Pid, Mref}, Pids), |
|
|
|
compile_queue(Pids2, Targets, Config, IncludeFn, CompileFn); |
|
|
|
|
|
|
|
{'DOWN', _Mref, _, _Pid, Info} -> |
|
|
|
?DEBUG("Worker failed: ~p\n", [Info]), |
|
|
|
?FAIL |
|
|
|
end. |
|
|
|
|
|
|
|
compile_worker(QueuePid) -> |
|
|
|
QueuePid ! {next, self()}, |
|
|
|
receive |
|
|
|
{compile, Src, Target, Config, IncludeFn, CompileFn} -> |
|
|
|
case needs_compile(Src, Target, IncludeFn, Config) of |
|
|
|
true -> |
|
|
|
case catch(CompileFn(Src, Config)) of |
|
|
|
ok -> |
|
|
|
QueuePid ! {compiled, Src}, |
|
|
|
compile_worker(QueuePid); |
|
|
|
Error -> |
|
|
|
QueuePid ! {fail, Error}, |
|
|
|
ok |
|
|
|
end; |
|
|
|
false -> |
|
|
|
?INFO("Skipping ~s\n", [Src]), |
|
|
|
compile_worker(QueuePid) |
|
|
|
end; |
|
|
|
|
|
|
|
empty -> |
|
|
|
ok |
|
|
|
end. |