Module is not available

Background

I have an application :myapp and I am trying to add some web functionality to it from zero using Plug. However, even though I have all the files and modules, present, I still can’t launch it because iex can’t find the modules that are outside the lib folder.

Error

When running iex -S mix I get the following error:

** (Mix) Could not start application myapp: exited in: MyApp.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function MyApp.Web.MetricsExporter.setup/0 is undefined (module MyApp.Web.MetricsExporter is not available)
            MyApp.Web.MetricsExporter.setup()
            (myapp) lib/application.ex:19: MyApp.start/2
            (kernel) application_master.erl:277: :application_master.start_it_old/4

Code

To fix the above error, I added the following lines to my mix.exs:

  defp elixirc_paths(:test), do: ["lib", "web", "test/support"]
  defp elixirc_paths(_),     do: ["lib", "web"]

However the error still persists. My folder structure is the following:

config
lib
  |_ application.ex
web
  |_MetricsExporter.ex

Question

Why can’t iex find and compile the MetricsExporter file?

grep defmodule web/*.ex?

Is there a line saying defmodule MyApp.Web.MetricsExporter do?

$ grep defmodule web/*.ex
web/metrics_exporter.ex:defmodule MyApp.Web.MetricsExporter do
web/metrics_instrumenter.ex:defmodule MyApp.Web.MetricsInstrumenter do
web/router.ex:defmodule MyApp.Web.Router do

Yes, there is.

I have also checked the "_build/#{MIX_ENV}/lib/MyApp/ebin" and I couldn’t find any of the files of the web folder. They are not being compiled as I suspected, but I don’t know why.

And do you actually call elixirc_paths/1 in your mix.exs?

Something like this?

def project do
  [
    # …
    elixirc_paths: elixirc_paths(Mix.env())
  ]
end

The file (redacted to removed sensitive info):


defmodule Quake.MixProject do
  use Mix.Project

  def project do
    [
      app:              :myapp,
      version:          get_version_number(),
      elixir:           "~> 1.8",
      elixirc_path:     elixirc_paths(Mix.env),
      build_embedded:   Mix.env == :prod,
      start_permanent:  Mix.env == :prod,
      test_coverage:    [tool: ExCoveralls],
      deps:             deps()
    ]
  end

  def application do
    [
      extra_applications: [:logger, :runtime_tools],
      mod: {MyApp, []}
    ]
  end

  defp elixirc_paths(:test), do: ["lib", "web", "test/support"]
  defp elixirc_paths(_),     do: ["lib", "web"]

  defp deps do
    [
      { :jason,             "~> 1.0"    },
      { :plug_cowboy,       "~> 2.0 "   },
      { :cowboy,            "~> 2.0"    },
      { :plug,              "~> 1.0"    },
      { :prometheus_plugs,  "~> 1.1.5"  },
      { :prometheus_ex,     "~> 3.0"    },

      # test and dev
      { :excoveralls, "~> 0.8",   only: [:test],        runtime: false  },
      { :dialyxir,    "~> 0.5",   only: [:dev],         runtime: false  },
      { :credo,       "~> 1.0.0", only: [:dev, :test],  runtime: false  },

      # tracing
      { :observer_cli,  "~> 1.5"  }
    ]
  end

  defp get_version_number do
    commit = :os.cmd('git rev-parse --short HEAD') |> to_string |> String.trim_trailing("\n")
    v = "0.1.0+#{commit}"
    case Mix.env do
      :dev -> v <> "dev"
      _ -> v
    end
  end

end

The option has to use plural name.

6 Likes