iex -S mix on fresh nerves 项目时出错

Error when iex -S mix on fresh nerves project

Elixir 版本:1.6.0 使用 OTP 20 编译 二郎 OTP:20

我在设置 MIX_TARGET=rpi3 时安装了 nerves 并创建了新的 nerves 项目。我得到这个错误

** (FunctionClauseError) no function clause matching in Nerves.Runtime.Kernel.UEvent.handle_info/2

** (FunctionClauseError) no function clause matching in Nerves.Runtime.Kernel.UEvent.handle_info/2
(nerves_runtime) lib/nerves_runtime/kernel/uevent.ex:24: Nerves.Runtime.Kernel.UEvent.handle_info({#Port<0.7405>, {:exit_status, 8}}, %{autoload: true, port: #Port<0.7405>})
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {#Port<0.7405>, {:exit_status, 8}}
State: %{autoload: true, port: #Port<0.7405>}

我查看了uevent.exhandle_info的定义

defmodule Nerves.Runtime.Kernel.UEvent do         use GenServer
  require Logger
  alias Nerves.Runtime.Device

  def start_link(opts \ []) do
    GenServer.start_link(__MODULE__, opts, name:    __MODULE__)
  end

  def init(opts) do
    autoload = if opts[:autoload_modules] != nil,   do: opts[:autoload_modules], else: true
    send(self(), :discover)

    executable = :code.priv_dir(:nerves_runtime) ++ '/uevent'
    port = Port.open({:spawn_executable, executable},
    [{:args, []},
      {:packet, 2},
      :use_stdio,
      :binary,
      :exit_status])

    {:ok, %{port: port, autoload: autoload}}
  end
  def handle_info(:discover, s) do %%%%LINE 24%%%%%%%
    Device.discover
    {:noreply, s}
  end

  def handle_info({_, {:data, <<?n,         message::binary>>}}, s) do
    msg = :erlang.binary_to_term(message)
    handle_port(msg, s)
  end

  defp handle_port({:uevent, _uevent, kv}, s) do
    event =
      Enum.reduce(kv, %{}, fn (str, acc) ->
        [k, v] = String.split(str, "=", parts: 2)
        k = String.downcase(k)
        Map.put(acc, k, v)
      end)
    case Map.get(event, "devpath", "") do
      "/devices" <> _path -> registry(event, s)
      _ -> :noop
    end
    {:noreply, s}
  end

  def registry(%{"action" => "add", "devpath" => devpath} = event, s) do
    attributes = Map.drop(event, ["action", "devpath"])
   scope = scope(devpath)
    #Logger.debug "UEvent Add: #{inspect scope}"
    if subsystem = Map.get(event, "subsystem") do
      SystemRegistry.update_in(subsystem_scope(subsystem), fn(v) ->
        v = if is_nil(v), do: [], else: v
        [scope | v]
      end)
    end
    if s.autoload, do: modprobe(event)
    SystemRegistry.update(scope, attributes)
  end

  def registry(%{"action" => "remove", "devpath" => devpath} = event, _) do
    scope = scope(devpath)
    #Logger.debug "UEvent Remove: #{inspect scope}"
    SystemRegistry.delete(scope)
    if subsystem = Map.get(event, "subsystem") do
      SystemRegistry.update_in(subsystem_scope  (subsystem), fn(v) ->
        v = if is_nil(v), do: [], else: v
        {_, scopes} = Enum.split_with(v, fn(v) ->   v == scope end)
        scopes
      end)
    end
  end

  def registry(%{"action" => "change"} = event, s) do
    #Logger.debug "UEvent Change: #{inspect event}"
    raw = Map.drop(event, ["action"])
    Map.put(raw, "action", "remove")
    |> registry(s)

    Map.put(raw, "action", "add")
    |> registry(s)
  end

  def registry(%{"action" => "move", "devpath" => new, "devpath_old" => old}, _) do
    #Logger.debug "UEvent Move: #{inspect scope (old)} -> #{inspect scope(new)}"
    SystemRegistry.move(scope(old), scope(new))
  end

  def registry(event, _) do
    Logger.debug "UEvent Unhandled: #{inspect event}"
  end

  defp scope("/" <> devpath) do
    scope(devpath)
  end
  defp scope(devpath) do
    [:state | String.split(devpath, "/")]
  end

  defp subsystem_scope(subsystem) do
    [:state, "subsystems", subsystem]   
  end

  defp modprobe(%{"modalias" => modalias}) do
    System.cmd("modprobe", [modalias],  stderr_to_stdout: true)
  end
  defp modprobe(_), do: :noop

end

这是混合文件

     defmodule Powpow.MixProject do
   use Mix.Project

   @target System.get_env("MIX_TARGET") || "host"

   Mix.shell().info([
     :green,
     """
     Mix environment
       MIX_TARGET:   #{@target}
       MIX_ENV:      #{Mix.env()}
     """,
     :reset
   ])

   def project do
     [
       app: :powpow,
       version: "0.1.0",
       elixir: "~> 1.4",
       target: @target,
       archives: [nerves_bootstrap: "~> 0.7"],
       deps_path: "deps/#{@target}",
       build_path: "_build/#{@target}",
       lockfile: "mix.lock.#{@target}",
       build_embedded: Mix.env == :prod,
       start_permanent: Mix.env == :prod,
       aliases: aliases(@target),
       deps: deps()
     ]
   end

   # Run "mix help compile.app" to learn about applications.
   def application, do: application(@target)

   # Specify target specific application configurations
   # It is common that the application start function will start and supervise
   # applications which could cause the host to fail. Because of this, we only
   # invoke Powpow.start/2 when running on a target.
   def application("host") do
     [extra_applications: [:logger]]
   end

   def application(_target) do
     [mod: {Powpow.Application, []}, extra_applications: [:logger]]
   end

   # Run "mix help deps" to learn about dependencies.
   defp deps do
     [{:nerves, "~> 0.9", runtime: false}] ++ deps(@target)
   end

   # Specify target specific dependencies
   defp deps("host"), do: []

   defp deps(target) do
     [
       {:shoehorn, "~> 0.2"},
       {:nerves_runtime, "~> 0.4"}
     ] ++ system(target)
   end

   defp system("rpi"), do: [{:nerves_system_rpi, ">= 0.0.0", runtime: false}]
   defp system("rpi0"), do: [{:nerves_system_rpi0, ">= 0.0.0", runtime: false}]
   defp system("rpi2"), do: [{:nerves_system_rpi2, ">= 0.0.0", runtime: false}]
   defp system("rpi3"), do: [{:nerves_system_rpi3, ">= 0.0.0", runtime: false}]
   defp system("bbb"), do: [{:nerves_system_bbb, ">= 0.0.0", runtime: false}]
   defp system("ev3"), do: [{:nerves_system_ev3, ">= 0.0.0", runtime: false}]
   defp system("qemu_arm"), do: [{:nerves_system_qemu_arm, ">= 0.0.0", runtime: false}]
   defp system("x86_64"), do: [{:nerves_system_x86_64, ">= 0.0.0", runtime: false}]
   defp system(target), do: Mix.raise "Unknown MIX_TARGET: #{target}"

   # We do not invoke the Nerves Env when running on the Host
   defp aliases("host"), do: []

   defp aliases(_target) do
     [
       # Add custom mix aliases here
     ]
     |> Nerves.Bootstrap.add_aliases()
   end
 end

为什么找不到定义?

上面代码中定义了两个&handle_info/2的函数头:

  1. handle_info(:discover, s)
  2. handle_info({_, {:data, <<?n, message::binary>>}}, s)

它被调用:

handle_info({#Port<0.7405>, {:exit_status, 8}}, %{autoload: true, port: #Port<0.7405>})

第一个定义不匹配,因为 {#Port<0.7405>, {:exit_status, 8}} 不匹配 :discover

第二个不匹配,因为 {:exit_status, 8} 不匹配 {:data, <<?n, message::binary>>}

这就是您看到错误的原因。

这里发生的是 Nerves 正在为目标 rpi3 或 Raspberry Pi 3 编译产品,因此,当您调用 iex -S mix 时,它无法在您的主机上 运行 .您必须取消设置 MIX_TARGET 以便您 运行 处于 "host" 模式。

构建项目后,您应该 运行 mix firmware mix firmware.burn 和 运行 目标上的项目。

查看我们的 getting started guide 了解有关如何部署和 运行 项目的更多信息。