From 534f334247163035b477293e74b78823f2d9b7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Mattsson?= Date: Tue, 23 Mar 2010 16:50:50 +0100 Subject: Automatically include applications that must be started Applications that are required to be started before other applications according to their app-file are now automatically included in the release. The kernel and stdlib applications are automatically included. --- lib/reltool/bin/reltool.escript | 10 +- lib/reltool/doc/src/reltool_examples.xml | 4 +- lib/reltool/src/reltool_server.erl | 304 ++++++++++++++++++------------- lib/reltool/src/reltool_target.erl | 271 +++++++++++++++++---------- lib/reltool/src/reltool_utils.erl | 24 +-- lib/reltool/test/reltool_app_SUITE.erl | 8 +- 6 files changed, 378 insertions(+), 243 deletions(-) (limited to 'lib') diff --git a/lib/reltool/bin/reltool.escript b/lib/reltool/bin/reltool.escript index 567cafbcad..1e5f34d99d 100644 --- a/lib/reltool/bin/reltool.escript +++ b/lib/reltool/bin/reltool.escript @@ -27,14 +27,14 @@ main(Args) -> {Options, Actions} = parse_args(Tokens, []), case invoke(Options, Actions) of ok -> - erlang:halt(0); + safe_stop(0); {error, ReasonString} -> fatal_error(ReasonString, 2) end catch throw:usage -> usage(), - erlang:halt(1); + safe_stop(1); exit:Reason -> String = lists:flatten(io_lib:format("EXIT: ~p", [Reason])), fatal_error(String, 3) @@ -59,6 +59,10 @@ usage() -> "See User's guide and Reference manual for more info.\n", [String]). +safe_stop(Code) -> + init:stop(Code), + timer:sleep(infinity). + invoke(Options, Actions) -> case Actions of [] -> @@ -174,7 +178,7 @@ script_name() -> fatal_error(String, Code) -> io:format(standard_error, "~s: ~s\n", [script_name(), String]), - erlang:halt(Code). + safe_stop(Code). write_file(File, IoList) -> case file:write_file(File, IoList) of diff --git a/lib/reltool/doc/src/reltool_examples.xml b/lib/reltool/doc/src/reltool_examples.xml index d6db246f6c..bce9413b52 100644 --- a/lib/reltool/doc/src/reltool_examples.xml +++ b/lib/reltool/doc/src/reltool_examples.xml @@ -249,11 +249,11 @@ Eshell V5.7.3 (abort with ^G)
 5> {ok, Server} = reltool:start_server([{config, {sys, [{boot_rel, "NAME"},
                                                         {rel, "NAME", "VSN",
-                                                        [kernel, stdlib, sasl]}]}}]).
+                                                        [sasl]}]}}]).
 {ok,<0.1288.0>}
 6>  reltool:get_config(Server).
 {ok,{sys,[{boot_rel,"NAME"},
-          {rel,"NAME","VSN",[kernel,stdlib,sasl]}]}}
+          {rel,"NAME","VSN",[sasl]}]}}
 7>  reltool:get_rel(Server, "NAME").
 {ok,{release,{"NAME","VSN"},
              {erts,"5.7"},
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 6a3122f879..a1e9c0193b 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -442,12 +442,13 @@ analyse(#state{common = C,
     MissingApp = default_app(?MISSING_APP, "missing"),
     ets:insert(C#common.app_tab, MissingApp),
 
-    RelApps = apps_in_rels(Rels),
-    {Apps2, Status2} =
+    {RevRelApps, Status2} = apps_in_rels(Rels, Apps, Status),
+    RelApps2 = lists:reverse(RevRelApps),
+    {Apps2, Status3} =
 	lists:mapfoldl(fun(App, Acc) ->
-			       app_init_is_included(C, Sys, App, RelApps, Acc)
+			       app_init_is_included(C, Sys, App, RelApps2, Acc)
 		       end,
-		  Status,
+		  Status2,
 		  Apps),
     Apps3 =
         case app_propagate_is_included(C, Sys, Apps2, []) of
@@ -467,17 +468,51 @@ analyse(#state{common = C,
     %% io:format("Missing app: ~p\n",
     %%           [lists:keysearch(?MISSING_APP, #app.name, Apps4)]),
     Sys2 = Sys#sys{apps = Apps4},
-    case verify_config(Sys2, Status2) of
-	{ok, _Warnings} = Status3 ->
-	    {S#state{sys = Sys2}, Status3};
-	{error, _} = Status3 ->
-            {S, Status3}
+
+    case verify_config(RelApps2, Sys2, Status3) of
+	{ok, _Warnings} = Status4 ->
+	    {S#state{sys = Sys2}, Status4};
+	{error, _} = Status4 ->
+            {S, Status4}
     end.
 
-apps_in_rels(Rels) ->
-    [{RelName, AppName} || #rel{name = RelName, rel_apps = RelApps} <- Rels,
-			   RA <- RelApps,
-			   AppName <- [RA#rel_app.name | RA#rel_app.incl_apps]].
+apps_in_rels(Rels, Apps, Status) ->
+    lists:foldl(fun(Rel, {RelApps, S}) ->
+			{MoreRelApps, S2} = apps_in_rel(Rel, Apps, S),
+			{MoreRelApps ++ RelApps, S2}
+		end,
+		{[], Status},
+		Rels).
+
+apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps, Status) ->
+    Mandatory = [{RelName, kernel}, {RelName, stdlib}],
+    Other = [{RelName, AppName} ||
+		RA <- RelApps,
+		AppName <- [RA#rel_app.name | RA#rel_app.incl_apps],
+		not lists:keymember(AppName, 2, Mandatory)],
+    more_apps_in_rels(Mandatory ++ Other, Apps, [], Status).
+
+more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc, Status) ->
+    case lists:member(RA, Acc) of
+	true ->
+	    more_apps_in_rels(RelApps, Apps, Acc, Status);
+	false ->
+	    case lists:keysearch(AppName, #app.name, Apps) of
+		{value, #app{info = #app_info{applications = InfoApps}}} ->
+		    Extra = [{RelName, N} || N <- InfoApps],
+		    {Acc2, Status2} =
+			more_apps_in_rels(Extra, Apps, [RA | Acc], Status),
+		    more_apps_in_rels(RelApps, Apps, Acc2, Status2);
+		false ->
+		    Text = lists:concat(["Release ", RelName,
+					 " uses non existing application ",
+					 AppName]),
+		    Status2 = reltool_utils:return_first_error(Status, Text),
+		    more_apps_in_rels(RelApps, Apps, Acc, Status2)
+	    end
+    end;
+more_apps_in_rels([], _Apps, Acc, Status) ->
+    {Acc, Status}.
 
 app_init_is_included(C,
 		     Sys,
@@ -706,8 +741,6 @@ mod_propagate_is_used_by(_C, []) ->
 
 read_apps(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc) ->
     {Mods2, IsIncl2} = read_apps(C, Sys, A, Mods, [], IsIncl),
-    %% reltool_utils:print(A#app.name, stdlib, "Mods2: ~p\n",
-    %% [[M#mod.status || M <- Mods2]]),
     Status =
         case lists:keysearch(missing, #mod.status, Mods2) of
             {value, _} -> missing;
@@ -770,9 +803,7 @@ filter_app(A) ->
     Mods = [M#mod{is_app_mod = undefined,
                   is_ebin_mod = undefined,
                   uses_mods = undefined,
-                  exists = false,
-                  is_pre_included = undefined,
-                  is_included = undefined} ||
+                  exists = false} ||
                M <- A#app.mods,
                M#mod.incl_cond =/= undefined],
     if
@@ -781,8 +812,7 @@ filter_app(A) ->
                          label = undefined,
                          info = undefined,
                          mods = [],
-                         uses_mods = undefined,
-                         is_included = undefined}};
+                         uses_mods = undefined}};
         Mods =:= [],
         A#app.mod_cond =:= undefined,
         A#app.incl_cond =:= undefined,
@@ -812,8 +842,7 @@ filter_app(A) ->
                          label = undefined,
                          info = undefined,
                          mods = Mods,
-                         uses_mods = undefined,
-                         is_included = undefined}}
+                         uses_mods = undefined}}
     end.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -850,16 +879,16 @@ refresh_app(#app{name = AppName,
                 end,
 
             %% Add non-existing modules
+	    AppInfoMods = AppInfo#app_info.modules,
             AppModNames =
                 case AppInfo#app_info.mod of
                     {StartModName, _} ->
-                        case lists:member(StartModName,
-					  AppInfo#app_info.modules) of
-                            true  -> AppInfo#app_info.modules;
-                            false -> [StartModName | AppInfo#app_info.modules]
+                        case lists:member(StartModName, AppInfoMods) of
+                            true  -> AppInfoMods;
+                            false -> [StartModName | AppInfoMods]
                         end;
                     undefined ->
-                        AppInfo#app_info.modules
+                        AppInfoMods
                 end,
             MissingMods = add_missing_mods(AppName, EbinMods, AppModNames),
 
@@ -1206,11 +1235,14 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) ->
                 {Sys#sys{root_dir = Val}, Status};
             lib_dirs when is_list(Val) ->
                 {Sys#sys{lib_dirs = Val}, Status};
-            mod_cond when Val =:= all; Val =:= app;
-                          Val =:= ebin; Val =:= derived;
+            mod_cond when Val =:= all;
+			  Val =:= app;
+                          Val =:= ebin;
+			  Val =:= derived;
                           Val =:= none ->
                 {Sys#sys{mod_cond = Val}, Status};
-            incl_cond when Val =:= include; Val =:= exclude;
+            incl_cond when Val =:= include;
+			   Val =:= exclude;
                            Val =:= derived ->
                 {Sys#sys{incl_cond = Val}, Status};
             boot_rel when is_list(Val) ->
@@ -1220,78 +1252,96 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) ->
             profile when Val =:= development ->
                 Val = ?DEFAULT_PROFILE, % assert,
                 {Sys#sys{profile = Val,
-                         incl_sys_filters = dec_re(incl_sys_filters,
-						   ?DEFAULT_INCL_SYS_FILTERS,
-						   Sys#sys.incl_sys_filters),
-                         excl_sys_filters = dec_re(excl_sys_filters,
-						   ?DEFAULT_EXCL_SYS_FILTERS,
-						   Sys#sys.excl_sys_filters),
-                         incl_app_filters = dec_re(incl_app_filters,
-						   ?DEFAULT_INCL_APP_FILTERS,
-						   Sys#sys.incl_app_filters),
-                         excl_app_filters = dec_re(excl_app_filters,
-						   ?DEFAULT_EXCL_APP_FILTERS,
-						   Sys#sys.excl_app_filters)},
+                         incl_sys_filters =
+			 dec_re(incl_sys_filters,
+				?DEFAULT_INCL_SYS_FILTERS,
+				Sys#sys.incl_sys_filters),
+                         excl_sys_filters =
+			 dec_re(excl_sys_filters,
+				?DEFAULT_EXCL_SYS_FILTERS,
+				Sys#sys.excl_sys_filters),
+                         incl_app_filters =
+			 dec_re(incl_app_filters,
+				?DEFAULT_INCL_APP_FILTERS,
+				Sys#sys.incl_app_filters),
+                         excl_app_filters =
+			 dec_re(excl_app_filters,
+				?DEFAULT_EXCL_APP_FILTERS,
+				Sys#sys.excl_app_filters)},
                  Status};
             profile when Val =:= embedded ->
                 {Sys#sys{profile = Val,
-                         incl_sys_filters = dec_re(incl_sys_filters,
-						   ?EMBEDDED_INCL_SYS_FILTERS,
-						   Sys#sys.incl_sys_filters),
-                         excl_sys_filters = dec_re(excl_sys_filters,
-						   ?EMBEDDED_EXCL_SYS_FILTERS,
-						   Sys#sys.excl_sys_filters),
-                         incl_app_filters = dec_re(incl_app_filters,
-						   ?EMBEDDED_INCL_APP_FILTERS,
-						   Sys#sys.incl_app_filters),
-                         excl_app_filters = dec_re(excl_app_filters,
-						   ?EMBEDDED_EXCL_APP_FILTERS,
-						   Sys#sys.excl_app_filters)},
+                         incl_sys_filters =
+			 dec_re(incl_sys_filters,
+				?EMBEDDED_INCL_SYS_FILTERS,
+				Sys#sys.incl_sys_filters),
+                         excl_sys_filters =
+			 dec_re(excl_sys_filters,
+				?EMBEDDED_EXCL_SYS_FILTERS,
+				Sys#sys.excl_sys_filters),
+                         incl_app_filters =
+			 dec_re(incl_app_filters,
+				?EMBEDDED_INCL_APP_FILTERS,
+				Sys#sys.incl_app_filters),
+                         excl_app_filters =
+			 dec_re(excl_app_filters,
+				?EMBEDDED_EXCL_APP_FILTERS,
+				Sys#sys.excl_app_filters)},
                  Status};
             profile when Val =:= standalone ->
                 {Sys#sys{profile = Val,
-                         incl_sys_filters = dec_re(incl_sys_filters,
-						   ?STANDALONE_INCL_SYS_FILTERS,
-						   Sys#sys.incl_sys_filters),
-                         excl_sys_filters = dec_re(excl_sys_filters,
-						   ?STANDALONE_EXCL_SYS_FILTERS,
-						   Sys#sys.excl_sys_filters),
-                         incl_app_filters = dec_re(incl_app_filters,
-						   ?STANDALONE_INCL_APP_FILTERS,
-						   Sys#sys.incl_app_filters),
-                         excl_app_filters = dec_re(excl_app_filters,
-						   ?STANDALONE_EXCL_APP_FILTERS,
-						   Sys#sys.excl_app_filters)},
+                         incl_sys_filters =
+			 dec_re(incl_sys_filters,
+				?STANDALONE_INCL_SYS_FILTERS,
+				Sys#sys.incl_sys_filters),
+                         excl_sys_filters =
+			 dec_re(excl_sys_filters,
+				?STANDALONE_EXCL_SYS_FILTERS,
+				Sys#sys.excl_sys_filters),
+                         incl_app_filters =
+			 dec_re(incl_app_filters,
+				?STANDALONE_INCL_APP_FILTERS,
+				Sys#sys.incl_app_filters),
+                         excl_app_filters =
+			 dec_re(excl_app_filters,
+				?STANDALONE_EXCL_APP_FILTERS,
+				Sys#sys.excl_app_filters)},
                  Status};
             incl_sys_filters ->
-                {Sys#sys{incl_sys_filters = dec_re(Key,
-						   Val,
-						   Sys#sys.incl_sys_filters)},
+                {Sys#sys{incl_sys_filters =
+			 dec_re(Key,
+				Val,
+				Sys#sys.incl_sys_filters)},
 		 Status};
             excl_sys_filters ->
-                {Sys#sys{excl_sys_filters = dec_re(Key,
-						   Val,
-						   Sys#sys.excl_sys_filters)},
+                {Sys#sys{excl_sys_filters =
+			 dec_re(Key,
+				Val,
+				Sys#sys.excl_sys_filters)},
 		 Status};
             incl_app_filters ->
-                {Sys#sys{incl_app_filters = dec_re(Key,
-						   Val,
-						   Sys#sys.incl_app_filters)},
+                {Sys#sys{incl_app_filters =
+			 dec_re(Key,
+				Val,
+				Sys#sys.incl_app_filters)},
 		 Status};
             excl_app_filters ->
-                {Sys#sys{excl_app_filters = dec_re(Key,
-						   Val,
-						   Sys#sys.excl_app_filters)},
+                {Sys#sys{excl_app_filters =
+			 dec_re(Key,
+				Val,
+				Sys#sys.excl_app_filters)},
 		 Status};
             incl_archive_filters ->
-                {Sys#sys{incl_archive_filters = dec_re(Key,
-						       Val,
-						       Sys#sys.incl_archive_filters)},
+                {Sys#sys{incl_archive_filters =
+			 dec_re(Key,
+				Val,
+				Sys#sys.incl_archive_filters)},
 		 Status};
             excl_archive_filters ->
-                {Sys#sys{excl_archive_filters = dec_re(Key,
-						       Val,
-						       Sys#sys.excl_archive_filters)},
+                {Sys#sys{excl_archive_filters =
+			 dec_re(Key,
+				Val,
+				Sys#sys.excl_archive_filters)},
 		 Status};
             archive_opts when is_list(Val) ->
                 {Sys#sys{archive_opts = Val}, Status};
@@ -1300,7 +1350,8 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) ->
             app_type when Val =:= permanent;
 			  Val =:= transient;
 			  Val =:= temporary;
-                          Val =:= load; Val =:= none ->
+                          Val =:= load;
+			  Val =:= none ->
                 {Sys#sys{app_type = Val}, Status};
             app_file when Val =:= keep; Val =:= strip, Val =:= all ->
                 {Sys#sys{app_file = Val}, Status};
@@ -1341,24 +1392,28 @@ decode(#app{} = App, [{Key, Val} | KeyVals], Status) ->
 			  Val =:= none ->
                 {App#app{app_type = Val}, Status};
             incl_app_filters ->
-                {App#app{incl_app_filters = dec_re(Key,
-						   Val,
-						   App#app.incl_app_filters)},
+                {App#app{incl_app_filters =
+			 dec_re(Key,
+				Val,
+				App#app.incl_app_filters)},
 		 Status};
             excl_app_filters ->
-                {App#app{excl_app_filters = dec_re(Key,
-						   Val,
-						   App#app.excl_app_filters)},
+                {App#app{excl_app_filters =
+			 dec_re(Key,
+				Val,
+				App#app.excl_app_filters)},
 		 Status};
             incl_archive_filters ->
-                {App#app{incl_archive_filters = dec_re(Key,
-						       Val,
-						       App#app.incl_archive_filters)},
+                {App#app{incl_archive_filters =
+			 dec_re(Key,
+				Val,
+				App#app.incl_archive_filters)},
 		 Status};
             excl_archive_filters ->
-                {App#app{excl_archive_filters = dec_re(Key,
-						       Val,
-						       App#app.excl_archive_filters)},
+                {App#app{excl_archive_filters =
+			 dec_re(Key,
+				Val,
+				App#app.excl_archive_filters)},
 		 Status};
             archive_opts when is_list(Val) ->
                 {App#app{archive_opts = Val}, Status};
@@ -1463,24 +1518,41 @@ merge_config(OldSys, NewSys, Force, Status) ->
                          apps = PatchedApps},
     {NewSys2, Status5}.
 
-verify_config(Sys, Status) ->
-    case lists:keymember(Sys#sys.boot_rel, #rel.name, Sys#sys.rels) of
+verify_config(RelApps, #sys{boot_rel = BootRel, rels = Rels, apps = Apps}, Status) ->
+    case lists:keymember(BootRel, #rel.name, Rels) of
         true ->
-            lists:foldl(fun(Rel, Acc)-> check_rel(Rel, Sys, Acc) end,
-			Status,
-			Sys#sys.rels);
+	    Status2 = lists:foldl(fun(RA, Acc) ->
+					  check_app(RA, Apps, Acc) end,
+				  Status,
+				  RelApps),
+	    lists:foldl(fun(#rel{name = RelName}, Acc)->
+				check_rel(RelName, RelApps, Acc)
+			end,
+			Status2,
+			Rels);
         false ->
-	    Text = lists:concat(["Release ", Sys#sys.boot_rel,
+	    Text = lists:concat(["Release ", BootRel,
 				 " is mandatory (used as boot_rel)"]),
 	    reltool_utils:return_first_error(Status, Text)
     end.
 
-check_rel(#rel{name = RelName, rel_apps = RelApps},
-	  #sys{apps = Apps},
-	  Status) ->
+check_app({RelName, AppName}, Apps, Status) ->
+    case lists:keysearch(AppName, #app.name, Apps) of
+	{value, App} when App#app.is_pre_included ->
+	    Status;
+	{value, App} when App#app.is_included ->
+	    Status;
+	_ ->
+	    Text = lists:concat(["Release ", RelName,
+						     " uses non included application ",
+				 AppName]),
+	    reltool_utils:return_first_error(Status, Text)
+    end.
+
+check_rel(RelName, RelApps, Status) ->
     EnsureApp =
         fun(AppName, Acc) ->
-                case lists:keymember(AppName, #rel_app.name, RelApps) of
+                case lists:member({RelName, AppName}, RelApps) of
                     true ->
                         Acc;
                     false ->
@@ -1492,23 +1564,7 @@ check_rel(#rel{name = RelName, rel_apps = RelApps},
                 end
         end,
     Mandatory = [kernel, stdlib],
-    Status2 = lists:foldl(EnsureApp, Status, Mandatory),
-    CheckRelApp =
-        fun(#rel_app{name = AppName}, Acc) ->
-                case lists:keysearch(AppName, #app.name, Apps) of
-                    {value, App} when App#app.is_pre_included ->
-                        Acc;
-                    {value, App} when App#app.is_included ->
-                        Acc;
-                    _ ->
-			Text = lists:concat(["Release ", RelName,
-					     " uses non included application ",
-					     AppName]),
-
-			reltool_utils:return_first_error(Acc, Text)
-                end
-        end,
-    lists:foldl(CheckRelApp, Status2, RelApps).
+    lists:foldl(EnsureApp, Status, Mandatory).
 
 patch_erts_version(RootDir, Apps, Status) ->
     AppName = erts,
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 260c8a15f8..aaf9d99d2f 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -67,26 +67,26 @@ kernel_processes(KernelApp) ->
 gen_config(Sys, InclDefs) ->
     {ok, do_gen_config(Sys, InclDefs)}.
 
-do_gen_config(#sys{root_dir          = RootDir,
-		   lib_dirs          = LibDirs,
-		   mod_cond          = ModCond,
-		   incl_cond         = AppCond,
-		   apps              = Apps,
-		   boot_rel          = BootRel,
-		   rels              = Rels,
-		   emu_name          = EmuName,
-		   profile           = Profile,
-		   incl_sys_filters    = InclSysFiles,
-		   excl_sys_filters    = ExclSysFiles,
-		   incl_app_filters    = InclAppFiles,
-		   excl_app_filters    = ExclAppFiles,
+do_gen_config(#sys{root_dir          	= RootDir,
+		   lib_dirs          	= LibDirs,
+		   mod_cond          	= ModCond,
+		   incl_cond         	= AppCond,
+		   apps              	= Apps,
+		   boot_rel          	= BootRel,
+		   rels              	= Rels,
+		   emu_name          	= EmuName,
+		   profile           	= Profile,
+		   incl_sys_filters  	= InclSysFiles,
+		   excl_sys_filters  	= ExclSysFiles,
+		   incl_app_filters  	= InclAppFiles,
+		   excl_app_filters  	= ExclAppFiles,
 		   incl_archive_filters = InclArchiveDirs,
 		   excl_archive_filters = ExclArchiveDirs,
-		   archive_opts      = ArchiveOpts,
-		   relocatable       = Relocatable,
-		   app_type          = AppType,
-		   app_file          = AppFile,
-		   debug_info        = DebugInfo},
+		   archive_opts      	= ArchiveOpts,
+		   relocatable       	= Relocatable,
+		   app_type          	= AppType,
+		   app_file          	= AppFile,
+		   debug_info        	= DebugInfo},
 	      InclDefs) ->
     ErtsItems =
         case lists:keysearch(erts, #app.name, Apps) of
@@ -96,12 +96,11 @@ do_gen_config(#sys{root_dir          = RootDir,
                 []
         end,
     AppsItems =
-        [{app, A#app.name, do_gen_config(A, InclDefs)}
+        [do_gen_config(A, InclDefs)
 	 || A <- Apps,
 	    A#app.name =/= ?MISSING_APP,
 	    A#app.name =/= erts,
-	    A#app.is_included =:= true,
-	    A#app.is_escript =/= true],
+	    not A#app.is_escript],
     EscriptItems = [{escript,
 		     A#app.active_dir,
 		     emit(incl_cond, A#app.incl_cond, undefined, InclDefs)}
@@ -126,7 +125,7 @@ do_gen_config(#sys{root_dir          = RootDir,
      emit(mod_cond, ModCond, ?DEFAULT_MOD_COND, InclDefs) ++
      emit(incl_cond, AppCond, ?DEFAULT_INCL_COND, InclDefs) ++
      ErtsItems ++
-     AppsItems ++
+     lists:flatten(AppsItems) ++
      emit(boot_rel, BootRel, ?DEFAULT_REL_NAME, InclDefs) ++
      RelsItems2 ++
      emit(emu_name, EmuName, ?DEFAULT_EMU_NAME, InclDefs) ++
@@ -142,7 +141,7 @@ do_gen_config(#sys{root_dir          = RootDir,
      emit(app_type, AppType, ?DEFAULT_APP_TYPE, InclDefs) ++
      emit(app_file, AppFile, ?DEFAULT_APP_FILE, InclDefs) ++
      emit(debug_info, DebugInfo, ?DEFAULT_DEBUG_INFO, InclDefs)};
-do_gen_config(#app{name = _Name,
+do_gen_config(#app{name = Name,
 		   mod_cond = ModCond,
 		   incl_cond  = AppCond,
 		   debug_info = DebugInfo,
@@ -154,27 +153,49 @@ do_gen_config(#app{name = _Name,
 		   archive_opts = ArchiveOpts,
 		   use_selected_vsn  = UseSelected,
 		   vsn = Vsn,
-		   mods = Mods},
+		   mods = Mods,
+		   is_included = IsIncl},
 	      InclDefs) ->
-    emit(mod_cond, ModCond, undefined, InclDefs) ++
-	emit(incl_cond, AppCond, undefined, InclDefs) ++
-	emit(debug_info, DebugInfo, undefined, InclDefs) ++
-	emit(app_file, AppFile,  undefined, InclDefs) ++
-	emit(incl_app_filters,    InclAppFiles, undefined, InclDefs) ++
-	emit(excl_app_filters,    ExclAppFiles, undefined, InclDefs) ++
-	emit(incl_archive_filters, InclArchiveDirs, undefined, InclDefs) ++
-	emit(excl_archive_filters, ExclArchiveDirs, undefined, InclDefs) ++
-	emit(archive_opts, ArchiveOpts, undefined, InclDefs) ++
-	emit(vsn, Vsn, undefined, InclDefs orelse UseSelected =/= true) ++
-	[{mod, M#mod.name, do_gen_config(M, InclDefs)} ||
-	    M <- Mods,
-	    M#mod.is_included =:= true];
-do_gen_config(#mod{name = _Name,
+    AppConfig =
+	[
+	 emit(mod_cond, ModCond, undefined, InclDefs),
+	 emit(incl_cond, AppCond, undefined, InclDefs),
+	 emit(debug_info, DebugInfo, undefined, InclDefs),
+	 emit(app_file, AppFile, undefined, InclDefs),
+	 emit(incl_app_filters, InclAppFiles, undefined, InclDefs),
+	 emit(excl_app_filters, ExclAppFiles, undefined, InclDefs),
+	 emit(incl_archive_filters, InclArchiveDirs, undefined, InclDefs),
+	 emit(excl_archive_filters, ExclArchiveDirs, undefined, InclDefs),
+	 emit(archive_opts, ArchiveOpts, undefined, InclDefs),
+	 if
+	     IsIncl, InclDefs -> [{vsn, Vsn}];
+	     UseSelected      -> [{vsn, Vsn}];
+	     true             -> []
+	 end,
+	 [do_gen_config(M, InclDefs) || M <- Mods]
+	],
+    case lists:flatten(AppConfig) of
+	FlatAppConfig when FlatAppConfig =/= []; IsIncl ->
+	    [{app, Name, FlatAppConfig}];
+	[] ->
+	    []
+    end;
+do_gen_config(#mod{name = Name,
 		   incl_cond = AppCond,
-		   debug_info = DebugInfo},
+		   debug_info = DebugInfo,
+		   is_included = IsIncl},
 	      InclDefs) ->
-    emit(incl_cond,  AppCond,   undefined, InclDefs) ++
-	emit(debug_info, DebugInfo, undefined, InclDefs);
+    ModConfig =
+	[
+	 emit(incl_cond,  AppCond, undefined, InclDefs),
+	 emit(debug_info, DebugInfo, undefined, InclDefs)
+	],
+    case lists:flatten(ModConfig) of
+	FlatModConfig when FlatModConfig =/= []; IsIncl ->
+	    [{mod, Name, FlatModConfig}];
+	_ ->
+	    []
+    end;
 do_gen_config(#rel{name = _Name,
 		   vsn = _Vsn,
 		   rel_apps = RelApps},
@@ -247,30 +268,33 @@ gen_app(#app{name = Name,
 
 gen_rel(Rel, Sys) ->
     try
-	{ok, do_gen_rel(Rel, Sys)}
+	MergedApps = merge_apps(Rel, Sys),
+	{ok, do_gen_rel(Rel, Sys, MergedApps)}
     catch
         throw:{error, Text} ->
             {error, Text}
     end.
 
-do_gen_rel(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps},
-	   #sys{apps = Apps}) ->
+do_gen_rel(#rel{name = RelName, vsn = RelVsn},
+	   #sys{apps = Apps},
+	   MergedApps) ->
     ErtsName = erts,
     case lists:keysearch(ErtsName, #app.name, Apps) of
 	{value, Erts} ->
 	    {release,
 	     {RelName, RelVsn},
-	     {erts, Erts#app.vsn},
-	     [app_to_rel(RA, Apps ) || RA <- RelApps]};
+	     {ErtsName, Erts#app.vsn},
+	     [strip_rel_info(App) || App <- MergedApps]};
 	false ->
 	    reltool_utils:throw_error("Mandatory application ~p is "
 				      "not included",
                                       [ErtsName])
     end.
 
-app_to_rel(#rel_app{name = Name, app_type = Type, incl_apps = InclApps},
-	   Apps) ->
-    {value, #app{vsn = Vsn}} = lists:keysearch(Name, #app.name, Apps),
+strip_rel_info(#app{name = Name,
+		    vsn = Vsn,
+		    app_type = Type,
+		    info = #app_info{incl_apps = InclApps}}) ->
     case {Type, InclApps} of
         {undefined, []} -> {Name, Vsn};
         {undefined, _}  -> {Name, Vsn, InclApps};
@@ -278,6 +302,79 @@ app_to_rel(#rel_app{name = Name, app_type = Type, incl_apps = InclApps},
         {_, _}          -> {Name, Vsn, Type, InclApps}
     end.
 
+merge_apps(#rel{name = RelName, rel_apps = RelApps},
+	   #sys{apps = Apps, app_type = DefType}) ->
+    Mandatory = [kernel, stdlib],
+    MergedApps = do_merge_apps(RelName, Mandatory, Apps, permanent, []),
+    MergedApps2 = do_merge_apps(RelName, RelApps, Apps, DefType, MergedApps),
+    sort_apps(MergedApps2).
+
+do_merge_apps(RelName, [#rel_app{name = Name} = RA | RelApps], Apps, DefType, Acc) ->
+    case is_already_merged(Name, RelApps, Acc) of
+	true ->
+	    do_merge_apps(RelName, RelApps, Apps, DefType, Acc);
+	false ->
+	    {value, App} = lists:keysearch(Name, #app.name, Apps),
+	    MergedApp = merge_app(RelName, RA, DefType, App),
+	    MoreNames = (MergedApp#app.info)#app_info.applications,
+	    Acc2 = [MergedApp | Acc],
+	    do_merge_apps(RelName, MoreNames ++ RelApps, Apps, DefType, Acc2)
+    end;
+do_merge_apps(RelName, [Name | RelApps], Apps, DefType, Acc) ->
+  case is_already_merged(Name, RelApps, Acc) of
+	true ->
+	  do_merge_apps(RelName, RelApps, Apps, DefType, Acc);
+	false ->
+	  RelApp = init_rel_app(Name, Apps),
+	  do_merge_apps(RelName, [RelApp | RelApps], Apps, DefType, Acc)
+  end;
+do_merge_apps(_RelName, [], _Apps, _DefType, Acc) ->
+    lists:reverse(Acc).
+
+init_rel_app(Name, Apps) ->
+    {value, App} = lists:keysearch(Name, #app.name, Apps),
+    Info = App#app.info,
+    #rel_app{name = Name,
+	     app_type = undefined,
+	     incl_apps = Info#app_info.incl_apps}.
+
+merge_app(RelName,
+	      #rel_app{name = Name,
+		       app_type = RelAppType,
+		       incl_apps = InclApps},
+	      DefType,
+	      App) ->
+    Type =
+        case {RelAppType, App#app.app_type} of
+            {undefined, undefined} -> DefType;
+            {undefined, AppType} -> AppType;
+            {_, _} -> RelAppType
+        end,
+    Info = App#app.info,
+    case InclApps -- Info#app_info.incl_apps of
+        [] ->
+	    App#app{app_type = Type, info = Info#app_info{incl_apps = InclApps}};
+        BadIncl ->
+            reltool_utils:throw_error("~p: These applications are "
+				      "used by release ~s but are "
+				      "missing as included_applications "
+				      "in the app file: ~p",
+                                      [Name, RelName, BadIncl])
+    end.
+
+is_already_merged(Name, [Name | _], _MergedApps) ->
+    true;
+is_already_merged(Name, [#rel_app{name = Name} | _], _MergedApps) ->
+    true;
+is_already_merged(Name, [_ | RelApps], MergedApps) ->
+    is_already_merged(Name, RelApps, MergedApps);
+is_already_merged(Name, [], [#app{name = Name} | _MergedApps]) ->
+    true;
+is_already_merged(Name, [] = RelApps, [_ | MergedApps]) ->
+    is_already_merged(Name, RelApps, MergedApps);
+is_already_merged(_Name, [], []) ->
+    false.
+
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Generate the contents of a boot file
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -291,27 +388,24 @@ gen_boot({script, {_, _}, _} = Script) ->
 
 gen_script(Rel, Sys, PathFlag, Variables) ->
     try
-        do_gen_script(Rel, Sys, PathFlag, Variables)
+	MergedApps = merge_apps(Rel, Sys),
+        do_gen_script(Rel, Sys, MergedApps, PathFlag, Variables)
     catch
         throw:{error, Text} ->
             {error, Text}
     end.
 
-do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps},
-              #sys{apps = Apps, app_type = DefaultType},
+do_gen_script(#rel{name = RelName, vsn = RelVsn},
+              #sys{apps = Apps},
+	      MergedApps,
               PathFlag,
               Variables) ->
     {value, Erts} = lists:keysearch(erts, #app.name, Apps),
     Preloaded = [Mod#mod.name || Mod <- Erts#app.mods],
     Mandatory = mandatory_modules(),
     Early = Mandatory ++ Preloaded,
-    MergedApps = [merge_app(RA, Apps, DefaultType) || RA <- RelApps],
-    SortedApps = sort_apps(MergedApps),
-    {value, KernelApp} = lists:keysearch(kernel, #app.name, SortedApps),
-
-    InclApps =
-	lists:append([I ||
-			 #app{info = #app_info{incl_apps = I}} <- SortedApps]),
+    {value, KernelApp} = lists:keysearch(kernel, #app.name, MergedApps),
+    InclApps = [I || #app{info = #app_info{incl_apps = I}} <- MergedApps],
 
     %% Create the script
     DeepList =
@@ -321,30 +415,30 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps},
          {progress, preloaded},
 
          %% Load mandatory modules
-         {path, create_mandatory_path(SortedApps, PathFlag, Variables)},
+         {path, create_mandatory_path(MergedApps, PathFlag, Variables)},
          {primLoad, lists:sort(Mandatory)},
          {kernel_load_completed},
          {progress, kernel_load_completed},
 
          %% Load remaining modules
-         [load_app_mods(A, Early, PathFlag, Variables) || A <- SortedApps],
+         [load_app_mods(A, Early, PathFlag, Variables) || A <- MergedApps],
          {progress, modules_loaded},
 
          %% Start kernel processes
-         {path, create_path(SortedApps, PathFlag, Variables)},
+         {path, create_path(MergedApps, PathFlag, Variables)},
          kernel_processes(gen_app(KernelApp)),
          {progress, init_kernel_started},
 
          %% Load applications
          [{apply, {application, load, [gen_app(A)]}} ||
-             A = #app{name = Name, app_type = Type} <- SortedApps,
+             A = #app{name = Name, app_type = Type} <- MergedApps,
              Name =/= kernel,
              Type =/= none],
          {progress, applications_loaded},
 
          %% Start applications
          [{apply, {application, start_boot, [Name, Type]}} ||
-             #app{name = Name, app_type = Type} <- SortedApps,
+             #app{name = Name, app_type = Type} <- MergedApps,
              Type =/= none,
              Type =/= load,
              not lists:member(Name, InclApps)],
@@ -355,28 +449,6 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps},
         ],
     {ok, {script, {RelName, RelVsn}, lists:flatten(DeepList)}}.
 
-merge_app(#rel_app{name = Name, app_type = Type, incl_apps = RelIncl},
-	  Apps,
-	  DefaultType) ->
-    {value, App} = lists:keysearch(Name, #app.name, Apps),
-    Type2 =
-        case {Type, App#app.app_type} of
-            {undefined, undefined} -> DefaultType;
-            {undefined, AppType} -> AppType;
-            {_, _} -> Type
-        end,
-    Info = App#app.info,
-    case RelIncl -- Info#app_info.incl_apps of
-        [] ->
-            App#app{app_type = Type2,
-		    info = Info#app_info{incl_apps = RelIncl}};
-        BadIncl ->
-            reltool_utils:throw_error("~p: These applications are "
-				      "missing as included_applications "
-				      "in the app file: ~p\n",
-                                      [Name, BadIncl])
-    end.
-
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) ->
@@ -459,13 +531,13 @@ sort_apps([], [], [], _) ->
     [];
 sort_apps([], Missing, [], _) ->
     %% this has already been checked before, but as we have the info...
-    reltool_utils:throw_error("Undefined applications: ~p\n",
+    reltool_utils:throw_error("Undefined applications: ~p",
 			      [make_set(Missing)]);
 sort_apps([], [], Circular, _) ->
-    reltool_utils:throw_error("Circular dependencies: ~p\n",
+    reltool_utils:throw_error("Circular dependencies: ~p",
 			      [make_set(Circular)]);
 sort_apps([], Missing, Circular, _) ->
-    reltool_utils:throw_error("Circular dependencies: ~p\n"
+    reltool_utils:throw_error("Circular dependencies: ~p"
                               "Undefined applications: ~p\n",
                               [make_set(Circular), make_set(Missing)]).
 
@@ -624,14 +696,15 @@ gen_rel_files(Sys, TargetDir) ->
 spec_rel_files(#sys{rels = Rels} = Sys) ->
     lists:append([do_spec_rel_files(R, Sys) || R <- Rels]).
 
-do_spec_rel_files(#rel{name = Name} = Rel,  Sys) ->
-    RelFile = Name ++ ".rel",
-    ScriptFile = Name ++ ".script",
-    BootFile = Name ++ ".boot",
-    GenRel = do_gen_rel(Rel, Sys),
+do_spec_rel_files(#rel{name = RelName} = Rel,  Sys) ->
+    RelFile = RelName ++ ".rel",
+    ScriptFile = RelName ++ ".script",
+    BootFile = RelName ++ ".boot",
+    MergedApps = merge_apps(Rel, Sys),
+    GenRel = do_gen_rel(Rel, Sys, MergedApps),
     PathFlag = true,
     Variables = [],
-    {ok, Script} = do_gen_script(Rel, Sys, PathFlag, Variables),
+    {ok, Script} = do_gen_script(Rel, Sys, MergedApps, PathFlag, Variables),
     {ok, BootBin} = gen_boot(Script),
     Date = date(),
     Time = time(),
@@ -978,13 +1051,13 @@ spec_dir(Dir) ->
 		     Base,
 		     [spec_dir(filename:join([Dir, F])) || F <- Files]};
                 error ->
-                    reltool_utils:throw_error("list dir ~s failed\n", [Dir])
+                    reltool_utils:throw_error("list dir ~s failed", [Dir])
             end;
         {ok, #file_info{type = regular}} ->
             %% Plain file
             {copy_file, Base};
         _ ->
-            reltool_utils:throw_error("read file info ~s failed\n", [Dir])
+            reltool_utils:throw_error("read file info ~s failed", [Dir])
     end.
 
 spec_mod(Mod, DebugInfo) ->
@@ -1118,7 +1191,7 @@ do_eval_spec({archive, Archive, Options, Files},
         {ok, _} ->
             ok;
         {error, Reason} ->
-            reltool_utils:throw_error("create archive ~s failed: ~p\n",
+            reltool_utils:throw_error("create archive ~s failed: ~p",
 				      [ArchiveFile, Reason])
     end;
 do_eval_spec({copy_file, File}, _OrigSourceDir, SourceDir, TargetDir) ->
@@ -1320,7 +1393,7 @@ do_install(RelName, TargetDir) ->
             ok = release_handler:create_RELEASES(TargetDir2, RelFile),
             ok;
         _ ->
-            reltool_utils:throw_error("~s: Illegal data file syntax.\n", [DataFile])
+            reltool_utils:throw_error("~s: Illegal data file syntax", [DataFile])
     end.
 
 subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) ->
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index 1768ee0db3..b33820c568 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -125,16 +125,18 @@ prim_parse(Tokens, Acc) ->
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 default_rels() ->
-    Kernel = #rel_app{name = kernel, incl_apps = []},
-    Stdlib = #rel_app{name = stdlib, incl_apps = []},
-    Sasl   = #rel_app{name = sasl,   incl_apps = []},
+    %%Kernel = #rel_app{name = kernel, incl_apps = []},
+    %%Stdlib = #rel_app{name = stdlib, incl_apps = []},
+    Sasl = #rel_app{name = sasl,   incl_apps = []},
     [
      #rel{name = ?DEFAULT_REL_NAME,
 	  vsn = "1.0",
-	  rel_apps = [Kernel, Stdlib]},
+	  rel_apps = []},
+	  %%rel_apps = [Kernel, Stdlib]},
      #rel{name = "start_sasl",
 	  vsn = "1.0",
-	  rel_apps = [Kernel, Sasl, Stdlib]}
+	  rel_apps = [Sasl]}
+	  %%rel_apps = [Kernel, Sasl, Stdlib]}
     ].
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -401,7 +403,7 @@ create_dir(Dir) ->
             ok;
         {error, Reason} ->
             Text = file:format_error(Reason),
-            throw_error("create dir ~s: ~s\n", [Dir, Text])
+            throw_error("create dir ~s: ~s", [Dir, Text])
     end.
 
 list_dir(Dir) ->
@@ -410,7 +412,7 @@ list_dir(Dir) ->
 	    Files;
         error ->
             Text = file:format_error(enoent),
-            throw_error("list dir ~s: ~s\n", [Dir, Text])
+            throw_error("list dir ~s: ~s", [Dir, Text])
     end.
 
 read_file_info(File) ->
@@ -419,7 +421,7 @@ read_file_info(File) ->
 	    Info;
         {error, Reason} ->
             Text = file:format_error(Reason),
-            throw_error("read file info ~s: ~s\n", [File, Text])
+            throw_error("read file info ~s: ~s", [File, Text])
     end.
 
 write_file_info(File, Info) ->
@@ -428,7 +430,7 @@ write_file_info(File, Info) ->
 	    ok;
         {error, Reason} ->
             Text = file:format_error(Reason),
-            throw_error("write file info ~s: ~s\n", [File, Text])
+            throw_error("write file info ~s: ~s", [File, Text])
     end.
 
 read_file(File) ->
@@ -437,7 +439,7 @@ read_file(File) ->
 	    Bin;
         {error, Reason} ->
             Text = file:format_error(Reason),
-            throw_error("read file ~s: ~s\n", [File, Text])
+            throw_error("read file ~s: ~s", [File, Text])
     end.
 
 write_file(File, IoList) ->
@@ -446,7 +448,7 @@ write_file(File, IoList) ->
 	    ok;
         {error, Reason} ->
             Text = file:format_error(Reason),
-            throw_error("write file ~s: ~s\n", [File, Text])
+            throw_error("write file ~s: ~s", [File, Text])
     end.
 
 recursive_delete(Dir) ->
diff --git a/lib/reltool/test/reltool_app_SUITE.erl b/lib/reltool/test/reltool_app_SUITE.erl
index 3944190953..f8433f73d0 100644
--- a/lib/reltool/test/reltool_app_SUITE.erl
+++ b/lib/reltool/test/reltool_app_SUITE.erl
@@ -70,7 +70,7 @@ all(suite) ->
     [
      fields,
      modules,
-     exportall,
+     export_all,
      app_depend,
      undef_funcs
     ].
@@ -175,11 +175,11 @@ extra_modules(Mods, [Mod|Ebins], Extra) ->
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-exportall(suite) ->
+export_all(suite) ->
     [];
-exportall(doc) ->
+export_all(doc) ->
     [];
-exportall(Config) when is_list(Config) ->
+export_all(Config) when is_list(Config) ->
     AppFile = key1search(app_file, Config),
     Mods    = key1search(modules, AppFile),
     check_export_all(Mods).
-- 
cgit v1.2.3