diff --git a/lib/elixir/lib/code.ex b/lib/elixir/lib/code.ex index 5a8204e1eab..97c5931c88d 100644 --- a/lib/elixir/lib/code.ex +++ b/lib/elixir/lib/code.ex @@ -314,7 +314,7 @@ defmodule Code do :relative_paths ] - @list_compiler_options [:tracers, :parser_options] + @list_compiler_options [:tracers, :parser_options, :erlc_options] @available_compiler_options @boolean_compiler_options ++ @list_compiler_options ++ @@ -1759,6 +1759,10 @@ defmodule Code do * `:docs` - when `true`, retains documentation in the compiled module. Defaults to `true`. + * `:erlc_options` (since v1.21.0) - a list of Erlang compiler options. For example, + `erlc_options: [:beam_debug_info, :beam_debug_stack]` emits Erlang/OTP + debug metadata for BEAM debuggers. Defaults to `[]`. + * `:ignore_already_consolidated` (since v1.10.0) - when `true`, does not warn when a protocol has already been consolidated and a new implementation is added. Defaults to `false`. diff --git a/lib/elixir/src/elixir.erl b/lib/elixir/src/elixir.erl index 9fd968e56c8..82610489902 100644 --- a/lib/elixir/src/elixir.erl +++ b/lib/elixir/src/elixir.erl @@ -88,6 +88,7 @@ start(_Type, _Args) -> %% Compiler options {debug_info, true}, {docs, true}, + {erlc_options, []}, {ignore_already_consolidated, false}, {ignore_module_conflict, false}, {infer_signatures, [elixir]}, diff --git a/lib/elixir/src/elixir_erl_compiler.erl b/lib/elixir/src/elixir_erl_compiler.erl index 3f2bff12105..52b57dfe011 100644 --- a/lib/elixir/src/elixir_erl_compiler.erl +++ b/lib/elixir/src/elixir_erl_compiler.erl @@ -60,16 +60,30 @@ env_compiler_options() -> erl_to_core(Forms, Opts) -> %% TODO: Remove parse transform handling on Elixir v2.0 - case [M || {parse_transform, M} <- Opts] of - [] -> + case requires_abstract_format(Opts, false) of + false -> v3_core:module(Forms, Opts); - _ -> + + beam_debug_info -> + {ok, DbgForms} = sys_coverage:beam_debug_info(Forms), + v3_core:module(DbgForms, Opts); + + parse_transform -> case compile:noenv_forms(Forms, [no_spawn_compiler_process, to_core0, return, no_auto_import | Opts]) of {ok, _Module, Core, Warnings} -> {ok, Core, Warnings}; {error, Errors, Warnings} -> {error, Errors, Warnings} end end. +requires_abstract_format([{parse_transform, _} | _], _Default) -> + parse_transform; +requires_abstract_format([beam_debug_info | Tail], _Default) -> + requires_abstract_format(Tail, beam_debug_info); +requires_abstract_format([_ | Tail], Default) -> + requires_abstract_format(Tail, Default); +requires_abstract_format([], Default) -> + Default. + noenv_forms(Forms, File, Opts) when is_list(Forms), is_list(Opts), is_binary(File) -> Source = elixir_utils:characters_to_list(File), diff --git a/lib/elixir/src/elixir_module.erl b/lib/elixir/src/elixir_module.erl index 419d361fe9c..ae6c0941c48 100644 --- a/lib/elixir/src/elixir_module.erl +++ b/lib/elixir/src/elixir_module.erl @@ -205,7 +205,7 @@ compile(Meta, Module, ModuleAsCharlist, Block, Vars, Prune, E) -> 'Elixir.Module.Types':infer(Module, File, Attributes, AllDefinitions, UsedPrivate, E, CheckerInfo) end, - RawCompileOpts = bag_lookup_element(DataBag, {accumulate, compile}, 2), + RawCompileOpts = bag_lookup_element(DataBag, {accumulate, compile}, 2) ++ elixir_config:get(erlc_options), CompileOpts = validate_compile_opts(RawCompileOpts, AllDefinitions, Unreachable, Line, E), Impls = bag_lookup_element(DataBag, impls, 2), diff --git a/lib/elixir/test/elixir/code_test.exs b/lib/elixir/test/elixir/code_test.exs index 036c516401b..2f40e2dfe21 100644 --- a/lib/elixir/test/elixir/code_test.exs +++ b/lib/elixir/test/elixir/code_test.exs @@ -917,6 +917,34 @@ defmodule Code.SyncTest do Code.put_compiler_option(:module_definition, :compiled) end + if System.otp_release() >= "29" do + test "uses erlc_options compiler option" do + module = CodeTest.ConfiguredBeamDebugInfo + previous = Code.compiler_options(erlc_options: [:beam_debug_info]) + + try do + assert [{^module, binary}] = + Code.compile_string(""" + defmodule CodeTest.ConfiguredBeamDebugInfo do + def sample(value) do + doubled = value * 2 + doubled + 1 + end + end + """) + + assert {:ok, {_, [{~c"DbgB", <<_version::32, entries::32, _::binary>>}]}} = + :beam_lib.chunks(binary, [~c"DbgB"]) + + assert entries > 0 + after + Code.compiler_options(previous) + :code.purge(module) + :code.delete(module) + end + end + end + test "prepend_path" do path = Path.join(__DIR__, "fixtures") true = Code.prepend_path(path)