@@ -45,6 +45,12 @@ defmodule Mix.Tasks.Escript.Build do
4545 * `:embed_elixir` - if `true` embed elixir and its children apps
4646 (`ex_unit`, `mix`, etc.) mentioned in the `:applications` list inside the
4747 `application` function in `mix.exs`.
48+
49+ Defaults to `true` for Elixir projects.
50+
51+ * `:consolidate_protocols` - if `true`, all protocols will be consolidated
52+ before being embedded into the escript.
53+
4854 Defaults to `true` for Elixir projects.
4955
5056 * `:shebang` - shebang interpreter directive used to execute the escript.
@@ -86,18 +92,26 @@ defmodule Mix.Tasks.Escript.Build do
8692 Mix.Task . run :compile , args
8793 end
8894
89- escriptize ( Mix.Project . config , opts [ :force ] )
95+ project = Mix.Project . config
96+ language = Keyword . get ( project , :language , :elixir )
97+ should_consolidate =
98+ Keyword . get ( project , :consolidate_protocols , language == :elixir )
99+
100+ if should_consolidate do
101+ Mix.Task . run "compile.protocols" , [ ]
102+ end
103+
104+ escriptize ( project , language , opts [ :force ] , should_consolidate )
90105 end
91106
92- defp escriptize ( project , force ) do
107+ defp escriptize ( project , language , force , should_consolidate ) do
93108 escript_opts = project [ :escript ] || [ ]
94109
95110 script_name = to_string ( escript_opts [ :name ] || project [ :app ] )
96111 filename = escript_opts [ :path ] || script_name
97112 main = escript_opts [ :main_module ]
98113 app = Keyword . get ( escript_opts , :app , project [ :app ] )
99114 files = project_files ( )
100- language = Keyword . get ( project , :language , :elixir )
101115
102116 escript_mod = String . to_atom ( Atom . to_string ( app ) <> "_escript" )
103117
@@ -111,9 +125,19 @@ defmodule Mix.Tasks.Escript.Build do
111125 "in your project configuration (under `:escript` option) to a module that implements main/1"
112126
113127 force || Mix.Utils . stale? ( files , [ filename ] ) ->
128+ beam_paths =
129+ [ files , deps_files ( ) , core_files ( escript_opts , language ) ]
130+ |> Stream . concat
131+ |> prepare_beam_paths
132+
133+ if should_consolidate do
134+ beam_paths =
135+ Path . wildcard ( consolidated_path <> "/*" )
136+ |> prepare_beam_paths ( beam_paths )
137+ end
138+
114139 tuples = gen_main ( escript_mod , main , app , language ) ++
115- to_tuples ( files ) ++ deps_tuples ( ) ++
116- embed_tuples ( escript_opts , language )
140+ read_beams ( beam_paths )
117141
118142 case :zip . create 'mem' , tuples , [ :memory ] do
119143 { :ok , { 'mem' , zip } } ->
@@ -136,7 +160,7 @@ defmodule Mix.Tasks.Escript.Build do
136160 end
137161 end
138162
139- defp project_files do
163+ defp project_files ( ) do
140164 get_files ( Mix.Project . app_path )
141165 end
142166
@@ -145,29 +169,19 @@ defmodule Mix.Tasks.Escript.Build do
145169 ( Path . wildcard ( "#{ app } /priv/**/*" ) |> Enum . filter ( & File . regular? / 1 ) )
146170 end
147171
148- defp get_tuples ( app ) do
149- get_files ( app ) |> to_tuples
150- end
151-
152- defp to_tuples ( files ) do
153- for f <- files do
154- { String . to_char_list ( Path . basename ( f ) ) , File . read! ( f ) }
155- end
156- end
157-
158172 defp set_perms ( filename ) do
159173 stat = File . stat! ( filename )
160174 :ok = File . chmod ( filename , stat . mode ||| 0o111 )
161175 end
162176
163- defp deps_tuples do
177+ defp deps_files ( ) do
164178 deps = Mix.Dep . loaded ( env: Mix . env ) || [ ]
165- Enum . flat_map ( deps , fn dep -> get_tuples ( dep . opts [ :build ] ) end )
179+ Enum . flat_map ( deps , fn dep -> get_files ( dep . opts [ :build ] ) end )
166180 end
167181
168- defp embed_tuples ( escript_opts , language ) do
182+ defp core_files ( escript_opts , language ) do
169183 if Keyword . get ( escript_opts , :embed_elixir , language == :elixir ) do
170- Enum . flat_map [ :elixir | extra_apps ( ) ] , & app_tuples ( & 1 )
184+ Enum . flat_map [ :elixir | extra_apps ( ) ] , & app_files / 1
171185 else
172186 [ ]
173187 end
@@ -184,13 +198,28 @@ defmodule Mix.Tasks.Escript.Build do
184198 Enum . filter ( extra_apps || [ ] , & ( & 1 in [ :eex , :ex_unit , :mix , :iex , :logger ] ) )
185199 end
186200
187- defp app_tuples ( app ) do
201+ defp app_files ( app ) do
188202 case :code . where_is_file ( '#{ app } .app' ) do
189203 :non_existing -> Mix . raise "Could not find application #{ app } "
190- file -> get_tuples ( Path . dirname ( Path . dirname ( file ) ) )
204+ file -> get_files ( Path . dirname ( Path . dirname ( file ) ) )
191205 end
192206 end
193207
208+ defp prepare_beam_paths ( paths , dict \\ HashDict . new ) do
209+ paths
210+ |> Enum . map ( & { Path . basename ( & 1 ) , & 1 } )
211+ |> Enum . into ( dict )
212+ end
213+
214+ defp read_beams ( items ) do
215+ items
216+ |> Enum . map ( fn { basename , beam_path } ->
217+ { String . to_char_list ( basename ) , File . read! ( beam_path ) }
218+ end )
219+ end
220+
221+ defp consolidated_path , do: Mix.Tasks.Compile.Protocols . default_path
222+
194223 defp build_comment ( user_comment ) do
195224 "%% #{ user_comment } \n "
196225 end
0 commit comments