Browse Source

ft: 优化

master
lijie 3 years ago
parent
commit
452ed2bbba
1 changed files with 195 additions and 145 deletions
  1. +195
    -145
      src/eMake.erl

+ 195
- 145
src/eMake.erl View File

@ -1,46 +1,74 @@
-module(eMake).
%% ,otp/lib/tools/src/make.erl
%% Emakefile,{mods, options},
%% ()
%% mods也可以包含多个模块,1,
%% process进行编译,.
-include_lib("kernel/include/file.hrl").
-export([
main/1
, all/3
]).
-export([
compileWorker/5
, readEMake/0
, saveEMake/1
]).
-define(MakeOpts, [noexec, load, netload, noload]).
main(Args) ->
io:format("~p~n", [Args]),
process_flag(trap_exit, true),
case Args of
[] ->
all(max(1, erlang:system_info(schedulers) - 1), "./Emakefile", []);
[EMakeFileOrCnt] ->
try list_to_integer(EMakeFileOrCnt) of
[EMakeFileOrWorkCnt] ->
try list_to_integer(EMakeFileOrWorkCnt) of
Cnt ->
all(max(1, Cnt), "./Emakefile", [])
catch _:_ ->
all(max(1, erlang:system_info(schedulers) - 1), EMakeFileOrCnt, [])
all(max(1, erlang:system_info(schedulers) - 1), EMakeFileOrWorkCnt, [])
end;
[EMakeFile, CntStr] ->
all(max(1, list_to_integer(CntStr)), EMakeFile, []);
[EMakeFile, CntStr, OptsStr] ->
[EMakeFile, WorkCntStr] ->
all(max(1, list_to_integer(WorkCntStr)), EMakeFile, []);
[EMakeFile, WorkCntStr, OptsStr] ->
{ok, Opts} = strToTerm(OptsStr),
all(max(1, list_to_integer(CntStr)), EMakeFile, Opts)
all(max(1, list_to_integer(WorkCntStr)), EMakeFile, Opts)
end.
eMakeFile() ->
filename:join(code:root_dir(), ".eMake.log").
readEMake() ->
try {ok, [LastTime]} = file:consult(eMakeFile()), LastTime of
Value ->
Value
catch _:_ ->
0
end.
all(Worker, EMakeFile, Opts) ->
saveEMake(NowTime) ->
try file:write_file(eMakeFile(), <<(integer_to_binary(NowTime))/binary, ".">>)
catch _:_ ->
ok
end.
all(WorkerCnt, EMakeFile, Opts) ->
StartTime = erlang:system_time(second),
{MakeOpts, CompileOpts} = splitOpts(Opts, [], []),
case readEMakefile(EMakeFile, CompileOpts) of
Files when is_list(Files) ->
do_make_files(Worker, Files, MakeOpts);
error ->
error
{ok, Files} ->
forMake(Files, WorkerCnt, lists:member(noexec, MakeOpts), load_opt(MakeOpts), []),
EndTime = erlang:system_time(second),
% LastTime = readEMake(),
% case LastTime /= 0 andalso StartTime < LastTime of
% true ->
% %% StartTime < LastTime
% put(compile_all, 1);
% _ ->
% ignore
% end,
% saveEMake(EndTime),
io:format("compile over all is ok use time:~ps", [EndTime - StartTime]);
_Err ->
_Err
end.
splitOpts([], Make, Compile) ->
@ -53,7 +81,6 @@ splitOpts([H | T], Make, Compile) ->
splitOpts(T, Make, [H | Compile])
end.
%% term反序列化, string转换为term
strToTerm(String) ->
case erl_scan:string(String ++ ".") of
@ -63,9 +90,22 @@ strToTerm(String) ->
{error, _Err}
end.
do_make_files(Worker, Fs, Opts) ->
%io:format("worker:~p~nfs:~p~nopts:~p~n", [Worker, Fs, Opts]),
process(Fs, Worker, lists:member(noexec, Opts), load_opt(Opts)).
%% Any flags that are not recognixed as make flags are passed directly
%% to the compiler.
%% So for example make:all([load,debug_info]) will make everything
%% with the debug_info flag and load it.
load_opt(Opts) ->
case lists:member(netload, Opts) of
true ->
netload;
false ->
case lists:member(load, Opts) of
true ->
load;
_ ->
noload
end
end.
%%% Emakefile [{Mods,Opts}]
%%% %%% Mods
@ -73,16 +113,16 @@ do_make_files(Worker, Fs, Opts) ->
readEMakefile(EMakefile, Opts) ->
case file:consult(EMakefile) of
{ok, EMake} ->
Ret = transform(EMake, Opts, []),
Ret = transform(EMake, Opts, []),
erase(),
Ret;
{ok, Ret};
{error, enoent} ->
%% EMakefile 使 filelib:wildcard("./**/*.erl")
Mods = [filename:rootname(F) || F <- filelib:wildcard("*.erl")],
[{Mods, Opts}];
{error, Other} ->
{ok, [{Mods, Opts}]};
{error, Other} = _Err ->
io:format("the Emakefile:~s is error:~p~n", [EMakefile, Other]),
error
_Err
end.
transform([], _Opts, Files) ->
@ -92,7 +132,7 @@ transform([{Mod, ModOpts} | EMake], Opts, Files) ->
[] ->
transform(EMake, Opts, Files);
Mods ->
transform(EMake, Opts, [{Mods, ModOpts ++ Opts} | Files])
transform(EMake, Opts, [{Mods, Opts ++ ModOpts} | Files])
end;
transform([Mod | EMake], Opts, Files) ->
case expand(Mod) of
@ -109,141 +149,151 @@ expand(Mods) when is_list(Mods), not is_integer(hd(Mods)) ->
expand(Mod) ->
case lists:member($*, Mod) of
true ->
Fun = fun(F, Acc) ->
M = filename:rootname(F),
case get(M) of
undefined ->
put(M, 1),
[M | Acc];
_ ->
Acc
end
end,
lists:foldl(Fun, [], filelib:wildcard(Mod ++ ".erl"));
foldErl(filelib:wildcard(Mod ++ ".erl"), []);
_ ->
Mod2 = filename:rootname(Mod, ".erl"),
case get(Mod2) of
M = filename:rootname(Mod, ".erl"),
case get(M) of
undefined ->
put(M, 1),
[Mod2];
[M];
_ ->
[]
end
end.
%% Any flags that are not recognixed as make flags are passed directly
%% to the compiler.
%% So for example make:all([load,debug_info]) will make everything
%% with the debug_info flag and load it.
load_opt(Opts) ->
case lists:member(netload, Opts) of
true ->
netload;
false ->
case lists:member(load, Opts) of
foldErl([], Acc) ->
Acc;
foldErl([OneFile | Left], Acc) ->
M = filename:rootname(OneFile),
case get(M) of
undefined ->
put(M, 1),
foldErl(Left, [M | Acc]);
_ ->
foldErl(Left, Acc)
end.
-define(OnceCnt, 8).
forMake([], _Worker, _NoExec, _Load, AllWorkPids) ->
receive
{mOverCompile, WPid} ->
NewAllWorkPids = lists:delete(WPid, AllWorkPids),
case NewAllWorkPids of
[] ->
ok;
_ ->
forMake([], _Worker, _NoExec, _Load, NewAllWorkPids)
end;
{mCompileError, Err} ->
errorStop(Err, AllWorkPids);
_Other ->
io:format("forMake [] receive unexpect msg:~p ~n", [_Other])
end;
forMake([{Mods, Opts} | Rest], Worker, NoExec, Load, AllWorkPids) ->
case Mods of
[] ->
forMake(Rest, Worker, NoExec, Load, AllWorkPids);
_ ->
case Worker > 0 of
true ->
load;
{Files, More} = splitMods(Mods),
WPid = spawn_link(?MODULE, compileWorker, [Files, Opts, self(), NoExec, Load]),
case More of
over ->
forMake(Rest, Worker - 1, NoExec, Load, [WPid | AllWorkPids]);
_ ->
forMake([{More, Opts} | Rest], Worker - 1, NoExec, Load, [WPid | AllWorkPids])
end;
_ ->
noload
receive
{mOverCompile, WPid} ->
{Files, More} = splitMods(Mods),
erlang:send(WPid, {mNewFile, Files, Opts}),
case More of
over ->
forMake(Rest, Worker, NoExec, Load, AllWorkPids);
_ ->
forMake([{More, Opts} | Rest], Worker, NoExec, Load, AllWorkPids)
end;
{mCompileError, Err} ->
errorStop(Err, AllWorkPids);
_Other ->
io:format("forMake xx receive unexpect msg:~p ~n", [_Other])
end
end
end.
%%
process([{[], _Opts} | Rest], Worker, NoExec, Load) ->
process(Rest, Worker, NoExec, Load);
process([{L, Opts} | Rest], Worker, NoExec, Load) ->
Len = length(L),
Worker2 = erlang:min(Len, Worker),
case catch do_worker(L, Opts, NoExec, Load, Worker2) of
error ->
error;
ok ->
process(Rest, Worker, NoExec, Load)
end;
process([], _Worker, _NoExec, _Load) ->
up_to_date.
do_worker(L, Opts, NoExec, Load, Worker) ->
%% worker个编译进程
SplitNum = min(length(L), Worker),
{L1, L2} = lists:split(SplitNum, L),
splitMods(Mods) ->
case length(Mods) =< ?OnceCnt of
true ->
{Mods, over};
_ ->
lists:split(?OnceCnt, Mods)
end.
%
Ref = make_ref(),
Pids =
[begin
start_worker([E], Opts, NoExec, Load, self(), Ref)
end || E <- L1],
do_wait_worker(length(Pids), L2, Opts, NoExec, Load, Ref).
errorStop(Err, AllWorkPids) ->
[exit(OnePid, kill) || OnePid <- AllWorkPids],
case Err of
{File, Errors, Warnings} ->
io:format("the file:~ts compile error:~p wrar:~p", [File, Errors, Warnings]);
File ->
io:format("the file:~ts compile error please check", [File])
end.
%% @doc ,
do_wait_worker(0, [], _Opts, _NoExec, _Load, _Ref) ->
ok;
do_wait_worker(N, L, Opts, NoExec, Load, Ref) ->
compileWorker([], _Opts, Parent, NoExec, Load) ->
erlang:send(Parent, {mOverCompile, self()}),
receive
{ack, Ref} ->
case L of
[H | T] ->
%%
start_worker(H, Opts, NoExec, Load, self(), Ref),
do_wait_worker(N, T, Opts, NoExec, Load, Ref);
[] ->
%%
do_wait_worker(N - 1, [], Opts, NoExec, Load, Ref)
end;
{error, Ref} ->
throw(error);
{'EXIT', _P, _Reason} ->
do_wait_worker(N, L, Opts, NoExec, Load, Ref);
{mNewFile, Files, Opts} ->
compileWorker(Files, Opts, Parent, NoExec, Load);
_Other ->
io:format("receive unknown msg:~p~n", [_Other]),
do_wait_worker(N, L, Opts, NoExec, Load, Ref)
io:format("compileWorker [] receive unexpect msg:~p ~n", [_Other])
end;
compileWorker([OneFile | Files], Opts, Parent, NoExec, Load) ->
case compile(coerce_2_list(OneFile), NoExec, Load, Opts) of
error ->
Parent ! {mCompileError, OneFile},
exit(error);
{error, Errors, Warnings} ->
Parent ! {mCompileError, {OneFile, Errors, Warnings}},
exit(error);
_ ->
compileWorker(Files, Opts, Parent, NoExec, Load)
end.
start_worker(F, Opts, NoExec, Load, Parent, Ref) ->
Fun =
fun() ->
case recompilep(coerce_2_list(F), NoExec, Load, Opts) of
error ->
Parent ! {error, Ref},
exit(error);
_ ->
ok
end,
Parent ! {ack, Ref}
end,
spawn_link(Fun).
recompilep(File, NoExec, Load, Opts) ->
ObjName = lists:append(filename:basename(File), code:objfile_extension()),
ObjFile = case lists:keysearch(outdir, 1, Opts) of
{value, {outdir, OutDir}} ->
filename:join(coerce_2_list(OutDir), ObjName);
false ->
ObjName
end,
case exists(ObjFile) of
true ->
recompilep1(File, NoExec, Load, Opts, ObjFile);
false ->
compile(File, NoExec, Load, Opts) ->
case get(compile_all) of
undefined ->
ObjName = lists:append(filename:basename(File), code:objfile_extension()),
ObjFile =
case lists:keysearch(outdir, 1, Opts) of
{value, {outdir, OutDir}} ->
filename:join(coerce_2_list(OutDir), ObjName);
false ->
ObjName
end,
case exists(ObjFile) of
true ->
reCompile(File, NoExec, Load, Opts, ObjFile);
false ->
recompile(File, NoExec, Load, Opts)
end;
_ ->
recompile(File, NoExec, Load, Opts)
end.
recompilep1(File, NoExec, Load, Opts, ObjFile) ->
{ok, Erl} = file:read_file_info(lists:append(File, ".erl")),
{ok, Obj} = file:read_file_info(ObjFile),
recompilep1(Erl, Obj, File, NoExec, Load, Opts).
recompilep1(#file_info{mtime = Te},
#file_info{mtime = To}, File, NoExec, Load, Opts) when Te > To ->
recompile(File, NoExec, Load, Opts);
recompilep1(_Erl, #file_info{mtime = To}, File, NoExec, Load, Opts) ->
recompile2(To, File, NoExec, Load, Opts).
reCompile(File, NoExec, Load, Opts, ObjFile) ->
{ok, #file_info{mtime = SrcTime}} = file:read_file_info(lists:append(File, ".erl")),
{ok, #file_info{mtime = ObjTime}} = file:read_file_info(ObjFile),
case SrcTime > ObjTime of
true ->
recompile(File, NoExec, Load, Opts);
_ ->
ckIncludeRecompile(ObjTime, File, NoExec, Load, Opts)
end.
%% recompile2(ObjMTime, File, NoExec, Load, Opts)
%% Check if file is of a later date than include files.
recompile2(ObjMTime, File, NoExec, Load, Opts) ->
ckIncludeRecompile(ObjMTime, File, NoExec, Load, Opts) ->
IncludePath = include_opt(Opts),
case check_includes(lists:append(File, ".erl"), IncludePath, ObjMTime) of
true ->
@ -264,15 +314,15 @@ include_opt([]) ->
%% Where load can be netload | load | noload
recompile(File, true, _Load, _Opts) ->
io:format("Out of date: ~s\n", [File]);
io:format("Out of date: ~ts\n", [File]);
recompile(File, false, noload, Opts) ->
io:format("Recompile: ~s\n", [File]),
% io:format("Recompile: ~ts\n", [File]),
compile:file(File, [report_errors, report_warnings, error_summary | Opts]);
recompile(File, false, load, Opts) ->
io:format("Recompile: ~s\n", [File]),
% io:format("Recompile: ~ts\n", [File]),
c:c(File, Opts);
recompile(File, false, netload, Opts) ->
io:format("Recompile: ~s\n", [File]),
% io:format("Recompile: ~ts\n", [File]),
c:nc(File, Opts).
exists(File) ->
@ -319,4 +369,4 @@ check_includes2(Epp, File, ObjMTime) ->
false;
{error, _Error} ->
check_includes2(Epp, File, ObjMTime)
end.
end.

Loading…
Cancel
Save