File 3341-diffable-Allow-input-from-external-runtime.patch of Package erlang

From f47e7d5a2464c54e5d86389dce7b1845ea606c71 Mon Sep 17 00:00:00 2001
From: Frej Drejhammar <frej.drejhammar@gmail.com>
Date: Fri, 1 Apr 2022 08:40:45 +0200
Subject: [PATCH] diffable: Allow input from external runtime

When `diffable` is used to evaluate the impact of a compiler
optimization or checking that a compiler refactoring doesn't change
the result in any significant way, the changes to the compiler source
code produce many differences in the output from `diffable`. The sheer
number of changes in line number directives in the output from, for
example, a reformatting which inserts a line early in a module makes
it hard to notice significant changes in the output.

Prior to this patch `diffable` finds the source code to the
applications it compiles by using `code:root_dir/0` and
`code:lib_dir/1`, that is, it assumes that the source code to compile
is the source for the running system. This patch adds a new command
line flag to `diffable`. The flag, `--erltop <path>`, makes diffable
look for the source code for the applications to compile in a
different tree.

The intended use case is as follows, you have a baseline and a
development tree, located in directories $BASE and $DEV
respectively:

```
$ PATH=$BASE/bin:$PATH $BASE/scripts/diffable --asm \
      --deterministic /tmp/baseline
```

Now run `diffable` using the development compiler, but compile the
source code from the baseline:

```
$ PATH=$DEV/bin:$PATH $DEV/scripts/diffable --erltop $BASE --asm \
      --deterministic /tmp/dev
```
---
 scripts/diffable | 88 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 57 insertions(+), 31 deletions(-)

diff --git a/scripts/diffable b/scripts/diffable
index fa3f79454f..c127480242 100755
--- a/scripts/diffable
+++ b/scripts/diffable
@@ -7,7 +7,8 @@
 -define(LONG_COMPILE_THRESHOLD, 10000).
 
 main(Args0) ->
-    DefOpts = #{format=>asm,no_compile=>false,legacy=>false,copts=>[]},
+    DefOpts = #{erltop=>false,format=>asm,no_compile=>false,
+                legacy=>false,copts=>[]},
     {Args,Opts} = opts(Args0, DefOpts),
     case Args of
 	[OutDir] ->
@@ -28,6 +29,10 @@ usage() ->
          "                  --asm)\n"
          "  --co <option>   Add <option> to the list of options given to the\n"
          "                  compiler. See compile:file/2 for valid options.\n"
+         "  --erltop <path> By default diffable looks for the applications to\n"
+         "                  compile by looking up the source for the current\n"
+         "                  runtime. This option allows the user to compile\n"
+         "                  the source in a different source tree.\n"
          "\n"
          "DESCRIPTION\n"
          "\n"
@@ -85,6 +90,8 @@ opts(["--deterministic"|Args], #{copts:=Copts}=Opts) ->
     opts(Args, Opts#{copts:=Copts++[deterministic]});
 opts(["--co",Opt|Args], #{copts:=Copts}=Opts) ->
     opts(Args, Opts#{copts:=Copts++[list_to_atom(Opt)]});
+opts(["--erltop", Path|Args], Opts) ->
+    opts(Args, Opts#{erltop:=Path});
 opts(["--"++Opt|_], _Opts) ->
     io:format("Unknown option: --~ts\n\n", [Opt]),
     usage();
@@ -156,16 +163,16 @@ elixir_root() ->
 %%%
 
 get_specs(Apps, #{format:=dis,no_compile:=true}=Opts) ->
-    Files = get_elixir_beams() ++ get_beams(Apps),
+    Files = get_elixir_beams() ++ get_beams(Apps, Opts),
     {Files,Opts};
 get_specs(Apps, #{}=Opts) ->
-    Inc = make_includes(),
+    Inc = make_includes(Opts),
     CompilerOpts = [{d,epmd_dist_high,42},
                     {d,epmd_dist_low,37},
                     {d,'VSN',1},
                     {d,'COMPILER_VSN',1},
                     {d,erlang_daemon_port,1337}|Inc],
-    Files = get_src(Apps),
+    Files = get_src(Apps, Opts),
     Specs1 = add_opts(Files, CompilerOpts),
     Specs = [{Beam,elixir} || Beam <- get_elixir_beams()] ++ Specs1,
     {Specs,Opts}.
@@ -200,31 +207,50 @@ vsn_is_harmful(F) ->
             App =:= "ssl"
     end.
 
-get_src(["preloaded"|Apps]) ->
-    WC = filename:join(code:root_dir(), "erts/preloaded/src/*.erl"),
-    filelib:wildcard(WC) ++ get_src(Apps);
-get_src(["inets"|Apps]) ->
-    LibDir = code:lib_dir(inets),
+get_src([A="preloaded"|Apps], Opts) ->
+    WC = filename:join(get_lib_dir(A, Opts), "erts/preloaded/src/*.erl"),
+    filelib:wildcard(WC) ++ get_src(Apps, Opts);
+get_src(["inets"|Apps], Opts) ->
+    LibDir = get_lib_dir(inets, Opts),
     WC = filename:join(LibDir, "src/*/*.erl"),
-    filelib:wildcard(WC) ++ get_src(Apps);
-get_src(["syntax_tools"|Apps]) ->
-    LibDir = code:lib_dir(syntax_tools),
+    filelib:wildcard(WC) ++ get_src(Apps, Opts);
+get_src(["syntax_tools"|Apps], Opts) ->
+    LibDir = get_lib_dir(syntax_tools, Opts),
     WC = filename:join(LibDir, "src/*.erl"),
     Files0 = filelib:wildcard(WC),
     Files = [F || F <- Files0,
                   filename:basename(F) =/= "merl_tests.erl"],
-    Files ++ get_src(Apps);
-get_src(["wx"|Apps]) ->
-    LibDir = code:lib_dir(wx),
+    Files ++ get_src(Apps, Opts);
+get_src(["wx"|Apps], Opts) ->
+    LibDir = get_lib_dir(wx, Opts),
     WC1 = filename:join(LibDir, "src/gen/*.erl"),
     WC2 = filename:join(LibDir, "src/*.erl"),
-    filelib:wildcard(WC1) ++ filelib:wildcard(WC2) ++ get_src(Apps);
-get_src([App|Apps]) ->
-    WC = filename:join(code:lib_dir(App), "src/*.erl"),
-    filelib:wildcard(WC) ++ get_src(Apps);
-get_src([]) -> [].
-
-make_includes() ->
+    filelib:wildcard(WC1) ++ filelib:wildcard(WC2) ++ get_src(Apps, Opts);
+get_src([App|Apps], Opts) ->
+    WC = filename:join(get_lib_dir(App, Opts), "src/*.erl"),
+    filelib:wildcard(WC) ++ get_src(Apps, Opts);
+get_src([], _) -> [].
+
+get_root_dir(#{ erltop := false }) ->
+    code:root_dir();
+get_root_dir(#{ erltop := Root }) ->
+    Root.
+
+get_lib_dir("preloaded", Opts) ->
+    get_root_dir(Opts);
+get_lib_dir(App, #{ erltop := false }) ->
+    code:lib_dir(App);
+get_lib_dir(App, #{ erltop := AltRoot }) ->
+    %% The assumption made here is that we intend to compare either
+    %% two installed runtimes or two source trees, that is, the
+    %% application directory names either both contain the same
+    %% version or have no version at all.
+    RuntimeRoot = code:root_dir(),
+    RuntimeLibDir = code:lib_dir(App),
+    AppWithVersion = lists:nthtail(length(RuntimeRoot) + 1, RuntimeLibDir),
+    AltRoot ++ AppWithVersion.
+
+make_includes(Opts) ->
     Is = [{common_test,"include"},
           {inets,"include"},
           {inets,"src/http_client"},
@@ -242,15 +268,15 @@ make_includes() ->
           {wx,"src"},
           {wx,"include"},
           {xmerl,"include"}],
-    [{i,filename:join(code:lib_dir(App), Path)} || {App,Path} <- Is].
-
-get_beams(["preloaded"|Apps]) ->
-    WC = filename:join(code:root_dir(), "erts/preloaded/ebin/*.beam"),
-    filelib:wildcard(WC) ++ get_beams(Apps);
-get_beams([App|Apps]) ->
-    WC = filename:join(code:lib_dir(App), "ebin/*.beam"),
-    filelib:wildcard(WC) ++ get_beams(Apps);
-get_beams([]) -> [].
+    [{i,filename:join(get_lib_dir(App, Opts), Path)} || {App,Path} <- Is].
+
+get_beams(["preloaded"|Apps], Opts) ->
+    WC = filename:join(get_root_dir(Opts), "erts/preloaded/ebin/*.beam"),
+    filelib:wildcard(WC) ++ get_beams(Apps, Opts);
+get_beams([App|Apps], Opts) ->
+    WC = filename:join(get_lib_dir(App, Opts), "ebin/*.beam"),
+    filelib:wildcard(WC) ++ get_beams(Apps, Opts);
+get_beams([], _) -> [].
 
 
 %%%
-- 
2.34.1

openSUSE Build Service is sponsored by