📄 systools_make.erl
字号:
end, ok = xref:set_library_path(?XREF_SERVER, LibPath), check_xref(sofs:to_external(AppDirs)).check_xref([{App,AppDir} | Appls]) -> case xref:add_application(?XREF_SERVER, AppDir, {name,App}) of {ok, _App} -> check_xref(Appls); Error -> xref:stop(?XREF_SERVER), [{error, Error}] end;check_xref([]) -> R = case xref:analyze(?XREF_SERVER, undefined_functions) of {ok, []} -> []; {ok, Undefined} -> %% This clause is a (temporary?) fix for hipe. adjust_for_hipe(Undefined); Error -> [{error, Error}] end, xref:stop(?XREF_SERVER), R.adjust_for_hipe(Undef) -> case erlang:system_info(hipe_architecture) of undefined -> U = lists:filter(fun ({hipe_bifs,_,_}) -> false; ({hipe,_,_}) -> false; (_) -> true end, Undef), if [] == U -> []; true -> [{warning, {exref_undef, U}}] end; _Arch -> %% Some BIFs are not always available on all versions of HiPE. U = lists:filter(fun ({hipe_bifs,write_u64,2}) -> false; (_) -> true end, Undef), [{warning, {exref_undef, U}}] end.%% Perform cross reference checks between all modules specified%% in .app files.%%xref_p(Flags) -> case member(exref, Flags) of true -> exists_xref(true); _ -> case get_flag(exref, Flags) of {exref, Appls} when is_list(Appls) -> case a_list_p(Appls) of true -> exists_xref({true, Appls}); _ -> false end; _ -> false end end.exists_xref(Flag) -> case code:ensure_loaded(xref) of {error, _} -> false; _ -> Flag end.objfile_extension(false) -> code:objfile_extension();objfile_extension(Machine) -> "." ++ atom_to_list(Machine).check_mod(Mod,App,Dir,Ext,IncPath) -> ObjFile = mod_to_filename(Dir, Mod, Ext), case file:read_file_info(ObjFile) of {ok,FileInfo} -> LastModTime = FileInfo#file_info.mtime, check_module(Mod, Dir, LastModTime, IncPath); _ -> {error, {module_not_found, App, Mod}} end.mod_to_filename(Dir, Mod, Ext) -> Parts = packages:split(Mod), filename:join([Dir | Parts]) ++ Ext.check_module(Mod, Dir, ObjModTime, IncPath) -> {SrcDirs,_IncDirs}= smart_guess(Mod, Dir,IncPath), case locate_src(Mod,SrcDirs) of {ok,_FDir,_File,LastModTime} -> if LastModTime > ObjModTime -> {warning, obj_out_of_date}; true -> ok end; _ -> {warning, source_not_found} end.locate_src(Mod,[Dir|Dirs]) -> File = filename:join(Dir, mod_to_fname(Mod) ++ ".erl"), case file:read_file_info(File) of {ok,FileInfo} -> LastModTime = FileInfo#file_info.mtime, {ok,Dir,File,LastModTime}; _ -> locate_src(Mod,Dirs) end;locate_src(_,[]) -> false.mod_to_fname(Mod) -> hd(lists:reverse(packages:split(Mod))).%%______________________________________________________________________%% smart_guess(Mod, Dir,IncludePath) -> {[Dirs],[IncDirs]}%% Guess the src code and include directory. If dir contains .../ebin%% src-dir should be one of .../src or .../src/e_src%% If dir does not contain .../ebin set dir to the same directory.smart_guess(Mod, Dir,IncPath) -> case reverse(filename:split(Dir)) of ["ebin"|D] -> Subdirs = case packages:split(Mod) of [_] -> []; [_|_] = Parts -> lists:reverse(tl(lists:reverse(Parts))) end, D1 = reverse(D), Dirs = [filename:join(D1 ++ ["src" | Subdirs]), filename:join(D1 ++ ["src", "e_src" | Subdirs])], {Dirs,Dirs ++ IncPath}; _ -> {[Dir],[Dir] ++ IncPath} end.%%______________________________________________________________________%% generate_script(#release, %% [{{Name,Vsn},#application}], Flags) ->%% ok | {error, Error}%% Writes a script (a la magnus) to the file File.script%% and a bootfile to File.boot.generate_script(Output, Release, Appls, Flags) -> PathFlag = path_flag(Flags), Variables = get_variables(Flags), Script = {script, {Release#release.name,Release#release.vsn}, [{preLoaded, preloaded()}, {progress, preloaded}, {path, create_mandatory_path(Appls, PathFlag, Variables)}, {primLoad, mandatory_modules()}, {kernel_load_completed}, {progress, kernel_load_completed}] ++ load_appl_mods(Appls, mandatory_modules() ++ preloaded(), PathFlag, Variables) ++ [{path, create_path(Appls, PathFlag, Variables)}] ++ create_kernel_procs(Appls) ++ create_load_appls(Appls) ++ create_start_appls(Appls) ++ script_end() }, ScriptFile = Output ++ ".script", case file:open(ScriptFile, write) of {ok, Fd} -> io:format(Fd, "%% script generated at ~w ~w\n~p.\n", [date(), time(), Script]), file:close(Fd), BootFile = Output ++ ".boot", case file:write_file(BootFile, term_to_binary(Script)) of ok -> ok; {error, Reason} -> {error, ?MODULE, {open,BootFile,Reason}} end; {error, Reason} -> {error, ?MODULE, {open,ScriptFile,Reason}} end.path_flag(Flags) -> case {member(local,Flags), member(otp_build, Flags)} of {true, _} -> local; {_, true} -> otp_build; {_, _} -> true end.get_variables(Flags) -> case get_flag(variables, Flags) of {variables, Variables} when is_list(Variables) -> valid_variables(Variables); _ -> [] end.valid_variables([{Var,Path}|Variables]) when is_list(Var), is_list(Path) -> [{Var,rm_tlsl(Path)}|valid_variables(Variables)];valid_variables([{Var,Path}|Variables]) when is_atom(Var), is_list(Path) -> [{to_list(Var),rm_tlsl(Path)}|valid_variables(Variables)];valid_variables([_|Variables]) -> valid_variables(Variables);valid_variables(_) -> [].rm_tlsl(P) -> rm_tlsl1(reverse(P)).rm_tlsl1([$/|P]) -> rm_tlsl1(P);rm_tlsl1(P) -> reverse(P). %%______________________________________________________________________%% Start all applications.%% Do not start applications that are included applications !create_start_appls(Appls) -> Included = append(map(fun({_,A}) -> A#application.includes end, Appls)), create_start_appls(Appls, Included).create_start_appls([{_,A}|T], Incl) -> App = A#application.name, case lists:member(App, Incl) of false when A#application.type == none -> create_start_appls(T, Incl); false when A#application.type == load -> create_start_appls(T, Incl); false -> [{apply, {application, start_boot, [App,A#application.type]}} | create_start_appls(T, Incl)]; _ -> create_start_appls(T, Incl) end;create_start_appls([], _) -> [].%%______________________________________________________________________%% Load all applications.create_load_appls([{{kernel,_},_}|T]) -> %Already added !! create_load_appls(T);create_load_appls([{_,A}|T]) when A#application.type == none -> create_load_appls(T);create_load_appls([{_,A}|T]) -> [{apply, {application, load, [pack_app(A)]}} | create_load_appls(T)];create_load_appls([]) -> [{progress, applications_loaded}].%%______________________________________________________________________%% The final part of the script.script_end() -> [{apply, {c, erlangrc, []}}, {progress, started}].%%-----------------------------------------------------------------%% Function: sort_appls(Appls) -> {ok, Appls'} | throw({error, Error})%% Types: Appls = {{Name, Vsn}, #application}]%% Purpose: Sort applications according to dependencies among%% applications. If order doesn't matter, use the same%% order as in the original list.%% Alg. written by Ulf Wiger 970917 (etxuwig@etxb.ericsson.se)%% Mod. by mbj%%-----------------------------------------------------------------sort_appls(Appls) -> {ok, sort_appls(Appls, [], [], [])}.sort_appls([{N, A}|T], Missing, Circular, Visited) -> {Name,_Vsn} = N, {Uses, T1, NotFnd1} = find_all(Name, A#application.uses, T, Visited, [], []), {Incs, T2, NotFnd2} = find_all(Name, lists:reverse(A#application.includes), T1, Visited, [], []), Missing1 = NotFnd1 ++ NotFnd2 ++ Missing, case Uses ++ Incs of [] -> %% No more app that must be started before this one is %% found; they are all already taken care of (and present %% in Visited list) [{N, A}|sort_appls(T, Missing1, Circular, [N|Visited])]; L -> %% The apps in L must be started before the app. %% Check if we have already taken care of some app in L, %% in that case we have a circular dependency. NewCircular = [N1 || {N1, _} <- L, N2 <- Visited, N1 == N2], Circular1 = case NewCircular of [] -> Circular; _ -> [N | NewCircular] ++ Circular end, %% L must be started before N, try again, with all apps %% in L added before N. Apps = del_apps(NewCircular, L ++ [{N, A}|T2]), sort_appls(Apps, Missing1, Circular1, [N|Visited]) end;sort_appls([], [], [], _) -> [];sort_appls([], Missing, [], _) -> %% this has already been checked before, but as we have the info... throw({error, {undefined_applications, make_set(Missing)}});sort_appls([], [], Circular, _) -> throw({error, {circular_dependencies, make_set(Circular)}});sort_appls([], Missing, Circular, _) -> throw({error, {apps, [{circular_dependencies, make_set(Circular)}, {undefined_applications, make_set(Missing)}]}}).find_all(CheckingApp, [Name|T], L, Visited, Found, NotFound) -> case find_app(Name, L) of {value, App} -> {_A,R} = App, %% It is OK to have a dependecy like %% X includes Y, Y uses X. case lists:member(CheckingApp, R#application.includes) of true -> case lists:keymember(Name, 1, Visited) of true -> find_all(CheckingApp, T, L, Visited, Found, NotFound); false -> find_all(CheckingApp, T, L, Visited, Found, [Name|NotFound]) end; false -> find_all(CheckingApp, T, L -- [App], Visited, [App|Found], NotFound) end; false -> case lists:keymember(Name, 1, Visited) of true -> find_all(CheckingApp, T, L, Visited, Found, NotFound); false -> find_all(CheckingApp, T, L, Visited, Found, [Name|NotFound]) end end;find_all(_CheckingApp, [], L, _Visited, Found, NotFound) -> {Found, L, NotFound}. find_app(Name, [{{Name,Vsn}, Application}|_]) -> {value, {{Name,Vsn},Application}};find_app(Name, [_|T]) -> find_app(Name, T);find_app(_Name, []) -> false.del_apps([Name|T], L) -> del_apps(T, lists:keydelete(Name, 1, L));del_apps([], L) -> L.%%______________________________________________________________________%% Create the load path used in the generated script.%% If PathFlag is true a script intended to be used as a complete%% system (e.g. in an embbeded system), i.e. all applications are%% located under $ROOT/lib.%% Otherwise all paths are set according to dir per application.%% Create the complete path.create_path(Appls, PathFlag, Variables) -> make_set(map(fun({{Name,Vsn},App}) -> cr_path(Name, Vsn, App, PathFlag, Variables) end, Appls)).%% Create the path to a specific application.%% (The otp_build flag is only used for OTP internal system make)cr_path(Name, Vsn, _, true, []) -> filename:join(["$ROOT", "lib", to_list(Name) ++ "-" ++ Vsn, "ebin"]);cr_path(Name, Vsn, App, true, Variables) -> Dir = App#application.dir, N = to_list(Name), Tail = [N ++ "-" ++ Vsn, "ebin"], case variable_dir(Dir, N, Vsn, Variables) of {ok, VarDir} -> filename:join([VarDir] ++ Tail); _ -> filename:join(["$ROOT", "lib"] ++ Tail) end;cr_path(Name, _, _, otp_build, _) -> filename:join(["$ROOT", "lib", to_list(Name), "ebin"]);cr_path(_, _, App, _, _) -> filename:absname(App#application.dir).variable_dir(Dir, Name, Vsn, [{Var,Path}|Variables]) -> case lists:prefix(Path,Dir) of true -> D0 = strip_prefix(Path, Dir), case strip_name_ebin(D0, Name, Vsn) of {ok, D} -> {ok, filename:join(["\$" ++ Var] ++ D)}; _ -> %% We know at least that we are located %% under the variable dir. {ok, filename:join(["\$" ++ Var] ++ D0)} end; _ -> variable_dir(Dir, Name, Vsn, Variables) end;variable_dir(_Dir, _, _, []) -> false.strip_prefix(Path, Dir) -> L = length(filename:split(Path)), lists:nthtail(L, filename:split(Dir)).strip_name_ebin(Dir, Name, Vsn) -> FullName = Name ++ "-" ++ Vsn, case reverse(Dir) of ["ebin",Name|D] -> {ok, reverse(D)}; ["ebin",FullName|D] -> {ok, reverse(D)}; _ -> false end.%% Create the path to the kernel and stdlib applications.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -