Skip to content

extra_applications(:host): probe fs for :wx instead of code:lib_dir/1 - #82

Merged
dominicletz merged 1 commit into
mainfrom
fix/extra-applications-wx-name-db
Aug 8, 2026
Merged

extra_applications(:host): probe fs for :wx instead of code:lib_dir/1#82
dominicletz merged 1 commit into
mainfrom
fix/extra-applications-wx-name-db

Conversation

@dominicletz

Copy link
Copy Markdown
Collaborator

Problem

After #80 added the :wx guard in extra_applications(:host), fresh
mix deps.compile runs on hosts that have wx on disk can still fail
with:

src/desktop_wx.erl:2:14: can't find include lib "wx/include/wx.hrl"

Root cause

The guard uses :code.lib_dir(:wx) which consults Erlang's NameDb
ETS table. NameDb only knows about apps that have been loaded into
the current VM.

mix deps.compile runs each dep's compile.all in sequence, and each
compile.all prunes the code path to only the apps the dep declared
(Code.delete_paths(current_paths -- loaded_paths) in
Mix.Tasks.Compile.All). After the first dep that does not list :wx
in its apps finishes, :wx is removed from both the code path AND
from NameDb. By the time desktop.application/0 is evaluated for
the :desktop dep itself, code:lib_dir(:wx) returns
{:error, :bad_name}, so :wx is dropped from desktop.app even
though the wx app is still on disk and wx.hrl is still resolvable.

The failure window:

  1. ensure_desktop_wx_erl!/0 runs while NameDb is still populated
    (before compile.all prunes), so wx_headers_resolvable?/0 is
    true and src/desktop_wx.erl is generated with
    -include_lib("wx/include/wx.hrl").
  2. extra_applications(:host) runs after pruning, so :wx is not
    added to the app file.
  3. compile.erlang fails with
    can't find include lib "wx/include/wx.hrl".

(Side note: mix deps.compile passes --no-code-path-pruning to
disable pruning, but Mix.Tasks.Compile.All only honors
--no-prune-code-paths — different strings — so pruning still
happens regardless of the intent. Filing that separately.)

Fix

Probe the filesystem directly, mirroring what wx_headers_resolvable?/0
already does. The filesystem state is independent of NameDb and stays
consistent across the build.

Test plan

  • Fresh mix deps.compile on a clean build completes end to end
    with :wx present in _build/dev/lib/desktop/ebin/desktop.app.
  • mix compile continues to succeed.
  • Hosts without :wx still see the stub backend generated
    (wx_app_on_disk?/0 returns false).

Local reproduction was on diode-drive (Apple Silicon, OTP 26.2.5
custom build, Elixir 1.16.3-otp-24). The full mix deps.compile and
mix compile both succeed with this patch and exercise the same
extra_applications(:host) code path that fails without it.

Co-authored-by: Cursor cursoragent@cursor.com

Made with Cursor

After PR #80 the `extra_applications(:host)` check uses
`:code.lib_dir(:wx)` to decide whether to include `:wx` in the
generated `desktop.app`. That call consults Erlang's `NameDb` ETS
table, which only knows about apps that have been loaded into the
running VM.

`mix deps.compile` runs each dep's `compile.all` in sequence, and each
`compile.all` prunes the code path to only the apps the dep declared
(see `Code.delete_paths(current_paths -- loaded_paths)` in
`Mix.Tasks.Compile.All`). After the first dep that does not list `:wx`
in its apps finishes, `:wx` is removed from both the code path AND
from `NameDb`. By the time `desktop.application/0` is evaluated for
the `:desktop` dep itself, `code:lib_dir(:wx)` returns
`{:error, :bad_name}`, so `:wx` is dropped from `desktop.app` even
though the wx app is still on disk and `wx.hrl` is still resolvable.

The concrete failure window this opens:

1. `ensure_desktop_wx_erl!/0` runs while `NameDb` is still populated
   (before `compile.all` prunes), so `wx_headers_resolvable?/0` is
   true and `src/desktop_wx.erl` is generated with
   `-include_lib("wx/include/wx.hrl")`.
2. `extra_applications(:host)` runs after pruning, so `:wx` is not
   added to the app file.
3. `compile.erlang` then fails with
   `can't find include lib "wx/include/wx.hrl"`.

(Side note: `mix deps.compile` passes `--no-code-path-pruning` to
disable pruning, but `Mix.Tasks.Compile.All` only honors
`--no-prune-code-paths` — different strings — so pruning still
happens regardless of the intent.)

Fix: probe the filesystem directly, mirroring what
`wx_headers_resolvable?/0` already does. The filesystem state is
independent of `NameDb` and stays consistent across the build.

Tested locally on diode-drive: a fresh `mix deps.compile` previously
failed with `can't find include lib "wx/include/wx.hrl"`; after this
patch it succeeds and `_build/dev/lib/desktop/ebin/desktop.app` lists
`:wx` in its `applications` entry. The behavior on hosts without
`:wx` is preserved — `wx_app_on_disk?/0` returns false and the
stub backend is used.

Co-authored-by: Cursor <cursoragent@cursor.com>
@dominicletz
dominicletz merged commit be6ed2c into main Aug 8, 2026
2 checks passed
@dominicletz
dominicletz deleted the fix/extra-applications-wx-name-db branch August 8, 2026 17:09
dominicletz added a commit that referenced this pull request Aug 8, 2026
Enum.find/2 returns nil when no matching directory is found, but the
with clause used an unbound pattern that silently matched nil and let
the body run with wx_dir = nil, crashing Path.join/1 with:

  ** (FunctionClauseError) no function clause matching in
     IO.chardata_to_string/1 (called with nil)
     (elixir 1.16.3) lib/path.ex:672: Path.do_join/3
     lib/desktop/mix.exs: Desktop.MixProject.wx_app_on_disk?/0

Reproducible on any OTP build configured --without-wx (e.g. the
elixir-desktop/ddrive macOS installer CI): the OTP root's lib/
directory has no wx-* entry, Enum.find returns nil, and the probe
crashes instead of returning false.

Add an is_binary(wx_dir) guard so the with chain falls through to
the existing `else _ -> false` clause on a no-wx host, and document
the pitfall in the comment block above extra_applications/1.

Fixes the regression introduced in #82 and unblocks downstream PRs
that bump the desktop dep to include the fs probe.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant