Package: elixir
Version: 1.18.1.dfsg-1
Severity: important
Tags: patch upstream

Dear Maintainer,

Currently in sid, elixir fails to load modules if they are installed
in a subdirectory of /usr/lib/elixir/lib. The list of directories looks
like the following (only elixir, mix, logger, iex, ex_unit, eex
subdirectories are included, they are actually hardcoded in
the lib/elixir/src/elixir.erl source file):

$ iex
Erlang/OTP 27 [erts-15.2.1] [source] [64-bit] [smp:16:16] [ds:16:16:10] 
[async-threads:1] [jit:ns]

Interactive Elixir (1.18.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :code.get_path()
[~c"/usr/lib/elixir/bin/../lib/elixir/ebin",
 ~c"/usr/lib/elixir/bin/../lib/mix/ebin",
 ~c"/usr/lib/elixir/bin/../lib/logger/ebin",
 ~c"/usr/lib/elixir/bin/../lib/iex/ebin",
 ~c"/usr/lib/elixir/bin/../lib/ex_unit/ebin",
 ~c"/usr/lib/elixir/bin/../lib/eex/ebin", ~c".",
 ~c"/usr/lib/erlang/lib/kernel-10.2.1/ebin",
 ~c"/usr/lib/erlang/lib/stdlib-6.2/ebin",
 ~c"/usr/lib/erlang/lib/xmerl-2.1/ebin", ~c"/usr/lib/erlang/lib/wx-2.4.3/ebin",
 ~c"/usr/lib/erlang/lib/tools-4.1.1/ebin",
 ~c"/usr/lib/erlang/lib/syntax_tools-3.2.1/ebin",
 ~c"/usr/lib/erlang/lib/ssl-11.2.6/ebin",
 ~c"/usr/lib/erlang/lib/ssh-5.2.6/ebin", ~c"/usr/lib/erlang/lib/snmp-5.18/ebin",
 ~c"/usr/lib/erlang/lib/sasl-4.2.2/ebin",
 ~c"/usr/lib/erlang/lib/runtime_tools-2.1.1/ebin",
 ~c"/usr/lib/erlang/lib/reltool-1.0.1/ebin",
 ~c"/usr/lib/erlang/lib/public_key-1.17/ebin",
 ~c"/usr/lib/erlang/lib/parsetools-2.6/ebin", ~c"/usr/lib/erlang/lib/odbc-2.15",
 ~c"/usr/lib/erlang/lib/observer-2.17",
 ~c"/usr/lib/erlang/lib/mnesia-4.23.3/ebin", ~c"/usr/lib/erlang/lib/megaco-4.7",
 ~c"/usr/lib/erlang/lib/inets-9.3.1/ebin",
 ~c"/usr/lib/erlang/lib/ftp-1.2.3/ebin",
 ~c"/usr/lib/erlang/lib/eunit-2.9.1/ebin", ~c"/usr/lib/erlang/lib/et-1.7.1",
 ~c"/usr/lib/erlang/lib/erts-15.2.1/ebin",
 ~c"/usr/lib/erlang/lib/erl_interface-5.5.2/ebin",
 ~c"/usr/lib/erlang/lib/eldap-1.2.14", ~c"/usr/lib/erlang/lib/edoc-1.3.2/ebin",
 ~c"/usr/lib/erlang/lib/diameter-2.4.1",
 ~c"/usr/lib/erlang/lib/dialyzer-5.3.1/ebin",
 ~c"/usr/lib/erlang/lib/debugger-5.5/ebin",
 ~c"/usr/lib/erlang/lib/crypto-5.5.2/ebin",
 ~c"/usr/lib/erlang/lib/compiler-8.5.4/ebin",
 ~c"/usr/lib/erlang/lib/common_test-1.27.6/ebin",
 ~c"/usr/lib/erlang/lib/asn1-5.3.1/ebin"]
iex(2)>

In bookworm (elixir 1.14) all the subdirectories of /usr/lib/elixir/lib
are added to the code loading path.

I'd like to suggest a path which adds missing directories (see the
attachment). Otherwise in order to run any system-wide elixir application
(like ex_doc from elixir-ex-doc) one have to use special environment
variable like ERL_LIBS=/usr/lib/elixir/lib, which is very inconvenient.

Cheers!
-- 
Sergei Golovan

-- System Information:
Debian Release: 12.9
  APT prefers stable-security
  APT policy: (500, 'stable-security'), (500, 'proposed-updates'), (500, 
'stable'), (1, 'experimental'), (1, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 6.1.0-29-amd64 (SMP w/16 CPU threads; PREEMPT)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE, 
TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_US:en
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
Author: Sergei Golovan <sgolo...@debian.org>
Description: Add all subdirectories of elixir_root to
 Erlang path to enable using Elixir modules installed
 into /usr/lib/elixir/lib.
Last-Modified: Sat, 25 Jan 2025 16:24:16 +0300

--- a/lib/elixir/src/elixir.erl
+++ b/lib/elixir/src/elixir.erl
@@ -31,6 +31,21 @@
 load_paths(OTP, Paths) when OTP >= 26 -> code:add_pathsa(Paths, cache);
 load_paths(_OTP, Paths) -> code:add_pathsa(Paths).
 
+get_lib_dirs(Root) ->
+  case erl_prim_loader:list_dir(Root) of
+    {ok, Dirs} ->
+      [Root ++ "/" ++ D ++ "/ebin" || D <- Dirs];
+    _ ->
+      [
+        Root ++ "/eex/ebin",
+        Root ++ "/ex_unit/ebin",
+        Root ++ "/iex/ebin",
+        Root ++ "/logger/ebin",
+        Root ++ "/mix/ebin",
+        Root ++ "/elixir/ebin"
+      ]
+    end.
+
 start(_Type, _Args) ->
   OTP = parse_otp_release(),
   preload_common_modules(),
@@ -39,14 +54,7 @@
 
   case init:get_argument(elixir_root) of
     {ok, [[Root]]} ->
-      load_paths(OTP, [
-        Root ++ "/eex/ebin",
-        Root ++ "/ex_unit/ebin",
-        Root ++ "/iex/ebin",
-        Root ++ "/logger/ebin",
-        Root ++ "/mix/ebin",
-        Root ++ "/elixir/ebin"
-      ]);
+      load_paths(OTP, get_lib_dirs(Root));
     _ ->
       ok
   end,

Reply via email to