Permalink
Browse files

Strip debug information from escripts by default and add option :stri…

…p_beam (#5829)
  • Loading branch information...
ivan authored and josevalim committed Mar 3, 2017
1 parent 824b268 commit 3ba85ad570df6ea47756652b68a74fc94e9de7d8
Showing with 75 additions and 0 deletions.
  1. +20 −0 lib/mix/lib/mix/tasks/escript.build.ex
  2. +55 −0 lib/mix/test/mix/tasks/escript_test.exs
@@ -44,6 +44,10 @@ defmodule Mix.Tasks.Escript.Build do
Defaults to app name. Set it to `nil` if no application should
be started.
* `:strip_beam` - if `true` strip BEAM code in the escript to remove chunks
unnecessary at runtime, such as debug information and documentation.
Defaults to `true`.
* `:embed_elixir` - if `true` embed Elixir and its children apps
(`ex_unit`, `mix`, etc.) mentioned in the `:applications` list inside the
`application/0` function in `mix.exs`.
@@ -123,6 +127,7 @@ defmodule Mix.Tasks.Escript.Build do
filename = escript_opts[:path] || script_name
main = escript_opts[:main_module]
app = Keyword.get(escript_opts, :app, project[:app])
strip_beam? = Keyword.get(escript_opts, :strip_beam, true)
files = project_files()
escript_mod = String.to_atom(Atom.to_string(app) <> "_escript")
@@ -149,6 +154,7 @@ defmodule Mix.Tasks.Escript.Build do
tuples = gen_main(project, escript_mod, main, app, language) ++
read_beams(beam_paths)
tuples = if strip_beam?, do: strip_beams(tuples), else: tuples
case :zip.create 'mem', tuples, [:memory] do
{:ok, {'mem', zip}} ->
@@ -242,6 +248,20 @@ defmodule Mix.Tasks.Escript.Build do
end)
end
defp strip_beams(tuples) do
for {basename, maybe_beam} <- tuples do
case Path.extname(basename) do
".beam" -> {basename, strip_beam(maybe_beam)}
_ -> {basename, maybe_beam}
end
end
end
defp strip_beam(beam) do
{:ok, {_, stripped_beam}} = :beam_lib.strip(beam)
stripped_beam
end
defp consolidated_paths(config) do
if config[:consolidate_protocols] do
Mix.Project.consolidation_path(config)
@@ -15,6 +15,17 @@ defmodule Mix.Tasks.EscriptTest do
end
end
defmodule EscriptWithDebugInfo do
def project do
[app: :escripttestwithdebuginfo,
version: "0.0.1",
escript: [
main_module: Escripttest,
strip_beam: false
]]
end
end
defmodule EscriptWithPath do
def project do
[app: :escripttestwithpath,
@@ -77,6 +88,7 @@ defmodule Mix.Tasks.EscriptTest do
Mix.Tasks.Escript.Build.run []
assert_received {:mix_shell, :info, ["Generated escript escriptest with MIX_ENV=dev"]}
assert System.cmd("escript", ["escriptest"]) == {"TEST\n", 0}
assert count_abstract_code("escriptest") == 0
Mix.Tasks.Escript.Build.run []
refute_received {:mix_shell, :info, ["Generated escript escriptest with MIX_ENV=dev"]}
@@ -94,6 +106,49 @@ defmodule Mix.Tasks.EscriptTest do
Mix.Tasks.Escript.Build.run []
assert_received {:mix_shell, :info, ["Generated escript escriptest with MIX_ENV=dev"]}
assert System.cmd("escript", ["escriptest"]) == {"FROM CONFIG\n", 0}
assert count_abstract_code("escriptest") == 0
end
end
test "generate escript with debug information" do
Mix.Project.push EscriptWithDebugInfo
in_fixture "escripttest", fn ->
Mix.Tasks.Escript.Build.run []
assert_received {:mix_shell, :info, ["Generated escript escripttestwithdebuginfo with MIX_ENV=dev"]}
assert System.cmd("escript", ["escripttestwithdebuginfo"]) == {"TEST\n", 0}
assert count_abstract_code("escripttestwithdebuginfo") > 0
Mix.Tasks.Escript.Build.run []
refute_received {:mix_shell, :info, ["Generated escript escripttestwithdebuginfo with MIX_ENV=dev"]}
end
end
defp count_abstract_code(escript_filename) do
escript_filename
|> get_beams()
|> Enum.count(fn {_, beam} -> get_abstract_code(beam) end)
end
defp get_beams(escript_filename) do
# :zip.unzip cannot unzip an escript unless we remove the escript header
zip_data = remove_escript_header(File.read!(escript_filename))
{:ok, tuples} = :zip.unzip(zip_data, [:memory])
for {filename, beam} <- tuples, Path.extname(filename) == ".beam" do
{filename, beam}
end
end
defp remove_escript_header(escript_data) do
{offset, _length} = :binary.match(escript_data, "\nPK")
zip_start = offset + 1
binary_part(escript_data, zip_start, byte_size(escript_data) - zip_start)
end
defp get_abstract_code(beam) do
case :beam_lib.chunks(beam, [:abstract_code]) do
{:ok, {_, [{:abstract_code, {_, abstract_code}}]}} -> abstract_code
_ -> nil
end
end

0 comments on commit 3ba85ad

Please sign in to comment.