はじめに
Nerves で開発していると、「ホスト環境と Raspberry Pi などのターゲット環境で、ちょっとだけ処理を変えたい」という場面にしばしば出くわします。
たとえば次のようなケースです。
- ホスト上ではダミーのネットワーク情報を返して動作確認だけしたい
- 実機上では実際のインターフェース状態を取得したい
- ファイルの保存先パスを、ホストとデバイスで切り替えたい
こうした用途では、MIX_TARGET を条件に処理を分けると便利です。
MIX_TARGET そのものの基本については、以前こちらで整理しました。
本記事では、MIX_TARGET に応じて処理を切り替える具体例を簡単に紹介します。
- コンパイル時に分岐するパターン(
Mix.target/0) - 実行時に分岐するパターン(
Nerves.Runtime.mix_target/0)
コンパイル時に分岐する(Mix.target/0)
まずは、コンパイル時に MIX_TARGET を判定し、まるごとモジュールの実装を切り替えるパターンです。
defmodule SampleApp do
if Mix.target() == :host do
def get_ssid, do: "foo"
def get_ssid(_iface), do: get_ssid()
else
def get_ssid(iface \\ "wlan0") do
case VintageNet.get(["interface", iface, "wifi", "current_ap"]) do
%VintageNetWiFi.AccessPoint{ssid: ssid} -> ssid
_ -> "No SSID"
end
end
end
end
このように、if Mix.target() == :host do ... else ... end を モジュール定義の外側 に置くことで、ビルド時の条件に応じてモジュール内部の関数定義そのものを切り替えられます。
この条件はコンパイル時に評価されるため、最終的にコンパイルされる関数定義はどちらか一方だけになります。
-
MIX_TARGET=hostのときは、ダミーのネットワーク情報だけを返すシンプルな実装が採用される -
MIX_TARGET=rpi4などのときは、VintageNetを使って実機のネットワーク情報を取得する実装になる
実行時に分岐する(Nerves.Runtime.mix_target/0)
アプリケーションの起動時に MIX_TARGET を取得して処理を分けるパターンです。
この方法は、Elixir の config/runtime.exs で活用できます。たとえば、Nerves Livebook の runtime.exs には以下のようなコードがあります:
この例では、起動時に Nerves.Runtime.mix_target/0 を使って現在のターゲットを判定し、ノートブックの保存先パスを環境ごとに切り替えています。
おわりに
この記事では、 MIX_TARGET に応じて処理を分岐させる方法を 2 種類紹介しました。
- モジュールの実装そのものを切り替えたい場合、
Mix.target/0を使って コンパイル時に分岐 - 実装は共通で、値だけ環境ごとに変えたい場合、
Nerves.Runtime.mix_target/0を使って 実行時に分岐
どちらも「ホスト環境ではダミー実装」「デバイスでは本番実装」といった用途で使えるので、基本パターンとして覚えておくと便利そうです。