这个启动脚本默认是在$ROOT/bin/start.boot文件,所以我们查看一下相应的start.script文件,内容如下
%% script generated at {2012,11,27} {19,37,10} {script, {"OTP APN 181 01","R15B03"}, [{preLoaded, [erl_prim_loader,erlang,init,otp_ring0,prim_file,prim_inet,prim_zip, zlib]}, {progress,preloaded}, {path,["$ROOT/lib/kernel-2.15.3/ebin","$ROOT/lib/stdlib-1.18.3/ebin"]}, {primLoad,[error_handler]}, {kernel_load_completed}, {progress,kernel_load_completed}, {path,["$ROOT/lib/kernel-2.15.3/ebin"]}, {primLoad, [application,application_controller,application_master, application_starter,auth,code,code_server,disk_log,disk_log_1, disk_log_server,disk_log_sup,dist_ac,dist_util,erl_boot_server, erl_ddll,erl_distribution,erl_epmd,erl_reply,error_logger, erts_debug,file,file_io_server,file_server,gen_sctp,gen_tcp,gen_udp, global,global_group,global_search,group,heart,hipe_unified_loader, inet,inet6_sctp,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config, inet_db,inet_dns,inet_gethost_native,inet_hosts,inet_parse,inet_res, inet_sctp,inet_tcp,inet_tcp_dist,inet_udp,kernel,kernel_config,net, net_adm,net_kernel,os,packages,pg2,ram_file,rpc,seq_trace, standard_error,user,user_drv,user_sup,wrap_log_reader]}, {path,["$ROOT/lib/stdlib-1.18.3/ebin"]}, {primLoad, [array,base64,beam_lib,binary,c,calendar,dets,dets_server,dets_sup, dets_utils,dets_v8,dets_v9,dict,digraph,digraph_utils,edlin, edlin_expand,epp,erl_bits,erl_compile,erl_eval,erl_expand_records, erl_internal,erl_lint,erl_parse,erl_posix_msg,erl_pp,erl_scan, erl_tar,error_logger_file_h,error_logger_tty_h,escript,ets, eval_bits,file_sorter,filelib,filename,gb_sets,gb_trees,gen, gen_event,gen_fsm,gen_server,io,io_lib,io_lib_format,io_lib_fread, io_lib_pretty,lib,lists,log_mf_h,math,ms_transform,orddict,ordsets, otp_internal,pg,pool,proc_lib,proplists,qlc,qlc_pt,queue,random,re, sets,shell,shell_default,slave,sofs,string,supervisor, supervisor_bridge,sys,timer,unicode,win32reg,zip]}, {progress,modules_loaded}, {path,["$ROOT/lib/kernel-2.15.3/ebin","$ROOT/lib/stdlib-1.18.3/ebin"]}, {kernelProcess,heart,{heart,start,[]}}, {kernelProcess,error_logger,{error_logger,start_link,[]}}, {kernelProcess,application_controller, {application_controller,start, [{application,kernel, [{description,"ERTS CXC 138 10"}, {vsn,"2.15.3"}, {id,[]}, {modules, [application,application_controller,application_master, application_starter,auth,code,packages,code_server, dist_util,erl_boot_server,erl_distribution,erl_reply, error_handler,error_logger,file,file_server, file_io_server,global,global_group,global_search, group,heart,hipe_unified_loader,inet6_tcp, inet6_tcp_dist,inet6_udp,inet6_sctp,inet_config, inet_hosts,inet_gethost_native,inet_tcp_dist,kernel, kernel_config,net,net_adm,net_kernel,os,ram_file,rpc, user,user_drv,user_sup,disk_log,disk_log_1, disk_log_server,disk_log_sup,dist_ac,erl_ddll, erl_epmd,erts_debug,gen_tcp,gen_udp,gen_sctp,inet, inet_db,inet_dns,inet_parse,inet_res,inet_tcp, inet_udp,inet_sctp,pg2,seq_trace,standard_error, wrap_log_reader]}, {registered, [application_controller,erl_reply,auth,boot_server, code_server,disk_log_server,disk_log_sup, erl_prim_loader,error_logger,file_server_2, fixtable_server,global_group,global_name_server,heart, init,kernel_config,kernel_sup,net_kernel,net_sup,rex, user,os_server,ddll_server,erl_epmd,inet_db,pg2]}, {applications,[]}, {included_applications,[]}, {env,[{error_logger,tty}]}, {maxT,infinity}, {maxP,infinity}, {mod,{kernel,[]}}]}]}}, {progress,init_kernel_started}, {apply, {application,load, [{application,stdlib, [{description,"ERTS CXC 138 10"}, {vsn,"1.18.3"}, {id,[]}, {modules, [array,base64,beam_lib,binary,c,calendar,dets, dets_server,dets_sup,dets_utils,dets_v8,dets_v9,dict, digraph,digraph_utils,edlin,edlin_expand,epp, eval_bits,erl_bits,erl_compile,erl_eval, erl_expand_records,erl_internal,erl_lint,erl_parse, erl_posix_msg,erl_pp,erl_scan,erl_tar, error_logger_file_h,error_logger_tty_h,escript,ets, file_sorter,filelib,filename,gb_trees,gb_sets,gen, gen_event,gen_fsm,gen_server,io,io_lib,io_lib_format, io_lib_fread,io_lib_pretty,lib,lists,log_mf_h,math, ms_transform,orddict,ordsets,otp_internal,pg,pool, proc_lib,proplists,qlc,qlc_pt,queue,random,re,sets, shell,shell_default,slave,sofs,string,supervisor, supervisor_bridge,sys,timer,unicode,win32reg,zip]}, {registered, [timer_server,rsh_starter,take_over_monitor, pool_master,dets]}, {applications,[kernel]}, {included_applications,[]}, {env,[]}, {maxT,infinity}, {maxP,infinity}]}]}}, {progress,applications_loaded}, {apply,{application,start_boot,[kernel,permanent]}}, {apply,{application,start_boot,[stdlib,permanent]}}, {apply,{c,erlangrc,[]}}, {progress,started}]}.
以下是init模块中关于启动脚本解析执行的一段源码:
%解析到process标签时,输出调试信息,通知init主进程
eval_script([{progress,Info}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> debug(Deb,{progress,Info}), init ! {self(),progress,Info}, eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice);
%解析到preLoaded标签,直接略过 eval_script([{preLoaded,_}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice);
%解析到path标签时,根据启动参数中'-path'的设置来确定是否整合路径,false则将Path与启动参数中'-pa' '-pz'的路径进行整合,设置erl_prim_loader的加载路径 eval_script([{path,Path}|CfgL],Init,{Pa,Pz},Vars,false,Ph,Deb,PathChoice) -> RealPath0 = make_path(Pa, Pz, Path, Vars), RealPath = patch_path(RealPath0, PathChoice), erl_prim_loader:set_path(RealPath), eval_script(CfgL,Init,{Pa,Pz},Vars,false,Ph,Deb,PathChoice); eval_script([{path,_}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> %% Ignore, use the command line -path flag. eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice);
%解析到kernel_load_completed标签时候, 根据启动mode的不同,区分interactive | embedded,
分别标示,在后面的primLoad时候,embedded时候,标示为true,则必须加载模块,否则在interactive模式下,由code_server动态加载模块 eval_script([{kernel_load_completed}|CfgL],Init,PathFs,Vars,P,{_,embedded,Par},Deb,PathChoice) -> eval_script(CfgL,Init,PathFs,Vars,P,{true,embedded,Par},Deb,PathChoice); eval_script([{kernel_load_completed}|CfgL],Init,PathFs,Vars,P,{_,E,Par},Deb,PathChoice) -> eval_script(CfgL,Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice);
%解析到primLoad标签时候,首先根据mode不同,确定是否加载,确定是一般加载方式还是并行加载方式。 eval_script([{primLoad,Mods}|CfgL],Init,PathFs,Vars,P,{true,E,Par},Deb,PathChoice) when is_list(Mods) -> if Par =:= true -> par_load_modules(Mods,Init); true -> load_modules(Mods) end, eval_script(CfgL,Init,PathFs,Vars,P,{true,E,Par},Deb,PathChoice);
eval_script([{primLoad,_Mods}|CfgL],Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice) -> %% Do not load now, code_server does that dynamically! eval_script(CfgL,Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice);
%解析到kernelProcess标签时,启动一些特别的进程,这些进程直接被init进程link和监控,
在这个启动脚本中,主要就是heart进程,error_logger进程,还有application_controller进程 eval_script([{kernelProcess,Server,{Mod,Fun,Args}}|CfgL],Init, PathFs,Vars,P,Ph,Deb,PathChoice) -> debug(Deb,{start,Server}), start_in_kernel(Server,Mod,Fun,Args,Init), eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice);
%解析到apply标签,则直接调用函数。 eval_script([{apply,{Mod,Fun,Args}}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> debug(Deb,{apply,{Mod,Fun,Args}}), apply(Mod,Fun,Args), eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice); eval_script([],_,_,_,_,_,_,_) -> ok; eval_script(What,_,_,_,_,_,_,_) -> exit({'unexpected command in bootfile',What}).
以上的启动脚本,我们可以看到在启动过程中执行了启动kernel应用的操作,和stdlib的操作,
而当我启动完虚拟机后,发觉启动的application只有一个,就是kernel,这是因为:
The mod key can be omitted for applications without processes, typically code libraries such as the application STDLIB.
在app文件中如果没有定义key的话是不会有进程作为application启动的,
所以真正在引导程序中启动的application只有kernel. stdlib只是单纯将所有涉及modules载入而已
这里应用启动是直接使用的application:start_boot,而其底层调用的实际是application_controller:start_boot_application方法,
其实application:start_boot和application:start方法本质上没太大区别,
但底层使用的application_controller:start_boot_application方法是不被暴露的,仅仅在启动引导时候使用的。
启动脚本的最后还调用了c:erlangrc/0函数这个是用来执行目录下.erlang文件代码的。基本就是虚拟机启动时的一个钩子。你可以放些路径设置神马的在里面。
That's all.