hotch-potch, Note to self

いろいろ作業記録

Elixir, Note to self

1.はじめに

プログラム言語 Elixir を普段使いする機会が増えてきたので、頻繁に行う内容を覚え書きしてます。(随時追記)

(実行環境)

$ uname -a

2.インストール・アップデート

(1)ビルドに必要なパッケージをインストール

Ubuntu Linux

ビルドに必要なツール、ライブラリをaptでインストールしておきます。

asdfに必要なもの

$ sudo apt install git curl make automake autoconf gcc g++ automake autoconf -y

asdfでElixirをビルドするのに必要なもの

$  sudo apt install libssl-dev libncurses5-dev libwxgtk3.0-gtk3-dev libwxgtk-webview3.0-gtk3-dev libxml2-utils unixodbc-dev xsltproc -y

java関連ライブラリのインストールが伴うもの

aptパッケージ 入れてないときのerlangビルドの際のメッセージ
$ sudo apt install fop DOCUMENTATION INFORMATION
fop is missing.Using fakefop to generate placeholder PDF files.
$ sudo apt install erlang-jinterface APPLICATIONS DISABLED
No Java compiler found
crypto APPLICATIONS INFORMATION
Using OpenSSL 3.0 is not yet recommended for production code.

nervesに必要なもの

nerves-project.org

$ sudo apt install pkg-config -y

# fwup
$ wget https://github.com/fwup-home/fwup/releases/download/v1.9.1/fwup_1.9.1_amd64.deb
$ sudo dpkg -i fwup_1.9.1_amd64.deb 

scenicに必要なもの

github.com

$ sudo apt install libglfw3 libglfw3-dev libglew-dev -y

macOS

% brew install wxWidgets

(2)asdf

GitHub - asdf-vm/asdf: Extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more

Ubuntu Linux

# クローンしてくる。ブランチは、その時点の新しいバージョンを選ぶこと
$ git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.13.1

# asdfのバージョン確認
$ ~/.asdf/bin/asdf --version
v0.10.2-7e7a1fa

# パスを通す
$ echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc 
$ echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.bashrc 

macOS

# インストール
% brew install asdf

# パスを通す
% echo -e "\n. $(brew --prefix asdf)/asdf.sh" >> ~/.zshrc

Elixir関連プラグインの追加

$ asdf plugin-add erlang
$ asdf plugin-add elixir

ターゲットのバージョン一覧を確認

$ asdf list-all erlang | tail25.3.2.6
26.0-rc1
26.0-rc2
26.0-rc3
26.0
26.0.1
26.0.2



$ asdf list-all elixir | grep -v ma | tail1.15.3-otp-25
1.15.3-otp-26
1.15.4
1.15.4-otp-24
1.15.4-otp-25
1.15.4-otp-26
1.15.5
1.15.5-otp-24
1.15.5-otp-25
1.15.5-otp-26

Nerves Systemとの連携をする場合

ErlangとElixirのバージョンが指定されているので、下記を確認して、あまり最新のバージョンをインストールしないこと。

Changelog — nerves v1.10.5

ビルド・インストール

まずは、erlangをインストール

$ asdf install erlang 25.3.2.7

Extracting source code
Building Erlang/OTP 25.3.2.6 (asdf_25.3.2.6), please wait...
APPLICATIONS DISABLED (See: /home/user/.asdf/plugins/erlang/kerl-home/builds/asdf_25.3.2.6/otp_build_25.3.2.6.log)
 * jinterface     : No Java compiler found

DOCUMENTATION INFORMATION (See: /home/user/.asdf/plugins/erlang/kerl-home/builds/asdf_25.3.2.6/otp_build_25.3.2.6.log)
 * documentation  : 
 *                  fop is missing.
 *                  Using fakefop to generate placeholder PDF files.

Erlang/OTP 25.3.2.6 (asdf_25.3.2.6) has been successfully built
Cleaning up compilation products for 
Cleaned up compilation products for  under /home/user/.asdf/plugins/erlang/kerl-home/builds

erlangを有効化

$ asdf local erlang 25.3.2.7

次に、Elixirをインストール

$  asdf install  elixir 1.15.5-otp-25

==> Checking whether specified Elixir release exists...
==> Downloading 1.15.5-otp-25 to /home/user/.asdf/downloads/elixir/1.15.5-otp-25/elixir-precompiled-1.15.5-otp-25.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 6715k  100 6715k    0     0  2159k      0  0:00:03  0:00:03 --:--:-- 2160k
==> Copying release into place

Elixirを有効化

$ asdf local elixir 1.15.5-otp-25

現在有効なバージョンの確認

$ asdf current erlang
erlang          25.3.2.6        /home/user/.tool-versions

$ asdf current elixir
elixir          1.15.5-otp-25   /home/user/.tool-versions

$ elixir -v
Erlang/OTP 25 [erts-13.2.2.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]

Elixir 1.15.5 (compiled with Erlang/OTP 25)

一気にインストールしたい場合は、下記のようにコマンドを組み立てる。 (timeコマンドは、ビルドに要した時間を計るために使用)

$ time asdf install erlang 25.0.4 && asdf local erlang 25.0.4 && time asdf install elixir 1.14.0 && asdf local elixir 1.14.0

$ export KERL_BUILD_DOCS=yes && export ERL=25.0.4 && export EXR=1.13.4-otp-25 && time asdf install erlang ${ERL} && asdf local erlang ${ERL} && time asdf install elixir ${EXR} && asdf local elixir ${EXR}

(3)パッケージマネージャhexのインストール

Hex

$ mix local.hex

~/.asdf/installs/elixir/<version>/.mix/archives/に展開されます。

(4)アップデート

現在インストール済みのバージョンを確認

$ asdf list
elixir
  1.14.2
erlang
  24.3.3

現在有効なバージョンの確認

$ asdf current elixir
elixir          1.14.2   /home/user/.tool-versions

$ asdf current erlang
erlang          24.3.3          /home/user/.tool-versions

新たなバージョンをインストール、有効化

$ asdf install  erlang 25.3.2.6
$ asdf local erlang 25.3.2.6

$ asdf install  elixir 1.15.5-otp-25
$ asdf local elixir 1.15.5-otp-25

不要になったバージョンをアンインストール

$ asdf uninstall elixir 1.14.2

$ asdf uninstall erlang 24.3.3

asdf_24.3.3 /home/user/.asdf/installs/erlang/24.3.3
The asdf_24.3.3 build has been deleted
The installation "/home/user/.asdf/installs/erlang/24.3.3" has been deleted

現在有効なバージョンの確認

$ elixir -v
Erlang/OTP 25 [erts-13.2.2.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]

Elixir 1.15.5 (compiled with Erlang/OTP 25)

(5)VSCode OTP compiled without EEP48 documentation chunks対策

参考資料

2.プロジェクト

(0)コマンド履歴の有効化

iexシェルのコマンド履歴を使えるようにします。

# https://stackoverflow.com/questions/45405070/how-do-i-save-iex-history
$ export ERL_AFLAGS="-kernel shell_history enabled"

(1)プロジェクトの作成

作成コマンド ディレクトリ構成
$ mix new newapp
$ mix new newmod --module MyModule
$ mix new newsup --sup
$ mix new newumb --umbrella

(2)依存関係の処理

$ mix deps.get

(3)ビルドと実行

#対話シェルで実行
$ iex -S mix

#そのまま実行
#https://qiita.com/pojiro/items/8955f78cfeb2e959c983
$ mix release
$ mix run --no-halt 

#escriptで単体実行化
#https://asquera.de/blog/2015-04-10/writing-a-commandline-app-in-elixir/
$ mix escript.build

スクリプトexsの場合

https://blog1.mammb.com/entry/2015/08/04/004748

#ビルド
$ elixirc hello_world.exs
$ ls
Elixir.Hello.beam  hello.exs

#実行
$ elixir -e Hello.hello

(4)デバッグ

mix.iexにモジュールを追加

  def application do
    [
      # 修正前
      # extra_applications: [:logger]
      # 修正後
      extra_applications: [:logger, :observer, :wx, :runtime_tools]
    ]
  end

起動

iex()> :observer.start()

(9)iex その他

3.Livebook

(1)インストール

$ git clone https://github.com/livebook-dev/livebook.git
$ cd livebook
$ mix deps.get
#設定変更
$ nano config/prod.exs

必要に応じて、待機ポート、受信IPを変えておく

import Config

# Default bind and port for production
config :livebook, LivebookWeb.Endpoint,
  http: [ip: {0, 0, 0, 0}, port: 8079],
  server: true

config :livebook, :iframe_port, 8078

# Set log level to warning by default to reduce output
config :logger, level: :warning

とりあえず起動する

$ MIX_ENV=prod mix phx.server
Compiling 151 files (.ex)
Generated livebook app
[Livebook] Application running at http://localhost:8079/?token=4jtc34krphaxbgnyiazoly5q3ykahgk2

起動時に表示されたURL http://localhost:8079/?token=4jtc34krphaxbgnyiazoly5q3ykahgk2 で、ブラウザでアクセス

ひとしきり楽しんだら、[Ctrl-C]で止める。

アドバンスド

#escriptでビルドして起動
$ mix escript.install hex livebook
$ livebook server --help

#localhost以外からも接続OKにする起動コマンド
$ livebook server --port 8082 --ip 0.0.0.0

起動スクリプトサンプル

ディレクトリ構成

~/gitwork/elixir
~/gitwork/elixir/livebook
~/gitwork/elixir/var
#!/bin/bash
#--------------------------------------

SCRIPTDIR="${HOME}/gitwork/elixir"
LOGDIR="${SCRIPTDIR}/var"

cd `dirname $0`
CMDNAME=`basename $0`

#ビルド済みのlivebookをフルパス指定
/home/tailway/.asdf/installs/elixir/1.13.1-otp-24/.mix/escripts/livebook server \
    --port 8082 \
    --ip 0.0.0.0 \
    --home ${SCRIPTDIR} \
    --no-token \
    >> ${LOGDIR}/${CMDNAME}.log 2>&1 &

PIDLB=$!
echo "livebook PID: ${PIDLB}"
echo "livebook PID: ${PIDLB}" >> ${LOGDIR}/${CMDNAME}.log 2>&1

exit 0

(2)nxと画像でひとしきり楽しむ

Mix.install([
    {:nx, "~> 0.1.0-dev", github: "elixir-nx/nx", branch: "main", sparse: "nx"}, 
    {:kino, "~> 0.3.1"},
    {:download, "~> 0.0.4"},
    {:pixels, "~> 0.2.1"},
    {:pngex, "~> 0.1.1"}
])

4.Nerves

(1)mix burnのエラー

$ MIX_TARGET=bbb mix burn
==> nerves
==> hellonerves

Nerves environment
  MIX_TARGET:   bbb
  MIX_ENV:      dev

Use 7.29 GiB memory card found at /dev/sdb? [Yn] y
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper

このエラーを受けてsudoしても、下記エラーで進みません。

$ sudo -S mix firmware.burn
sudo: mix: コマンドが見つかりません

この場合は、直接sudo fwupコマンドを実行します。

#                     ↓TARGET               ↓プロジェクト名.fw
$ sudo fwup ./_build/bbb_dev/nerves/images/hellonerves.fw 

Use 7.82 GB memory card found at /dev/sdb? [y/N] y
100% [====================================] 20.90 MB in / 24.31 MB out       
Success!
Elapsed time: 11.178 s

11.記述

Introduction

Tips

Cheat Sheet

Supervisor

No Title URL
0 GenServer https://hexdocs.pm/elixir/GenServer.html
1 並行性 https://elixirschool.com/ja/lessons/intermediate/concurrency
2 OTPの並行性 https://elixirschool.com/ja/lessons/advanced/otp_concurrency
3 OTPスーパバイザ https://elixirschool.com/ja/lessons/advanced/otp_supervisors
4 OTPディストリビューション https://elixirschool.com/ja/lessons/advanced/otp_distribution
9 GenServer - a cheat sheet https://elixir-lang.org/downloads/cheatsheets/gen-server.pdf

デバッグ

12.こんなときは

asdfのエラー

$ asdf install erlang 25.3.2.7

asdf_25.3.2.7 is not a kerl-managed Erlang/OTP installation
No build named asdf_25.3.2.7
・・・

Erlangのversion管理ツールkerlに依存していないバージョンであることを警告していますが、実際のインストールには影響はありません。

Scienicのエラー

$ mix do deps.get, scenic.run

・・・
No package 'glew' found
c_src/device/glfw.c:17:10: fatal error: GL/glew.h: No such file or directory
   17 | #include <GL/glew.h>
      |          ^~~~~~~~~~~
compilation terminated.
・・・
** (Mix) Could not compile with "make" (exit status: 2).
You need to have gcc and make installed. If you are using
Ubuntu or any other Debian-based system, install the packages
"build-essential". Also install "erlang-dev" package if not
included in your Erlang/OTP version. If you're on Fedora, run
"dnf group install 'Development Tools'".

openGL関連のライブラリが不足しています。 前述に戻って、必要なaptをインストールしてください。

$ mix do deps.get, scenic.run

・・・
09:52:27.830 [info] Scenic.Driver.Local: start: [name: :local, key_map: Scenic.KeyMap.USEnglish, cursor: false, position: [orientation: :normal, centered: false, scaled: false], calibration: [], antialias: true, debug: false, opacity: 255, layer: 0, limit_ms: 29, window: [resizeable: false, title: "my_app"], on_close: :stop_system], pid: #PID<0.401.0>
scenic_driver_local error: "Unable to initialize GLFW"
scenic_driver_local puts: "Failed to initilize the device"

09:52:27.841 [error] scenic_driver_local: "Unable to initialize GLFW"

09:52:27.841 [info] scenic_driver_local: "Failed to initilize the device"

09:52:27.841 [error] Scenic.Driver.Local dirty close

09:52:27.862 [error] GenServer :local terminating
** (ArgumentError) argument error
・・・

リモートのターミナルから起動したときにXの画面の出力先が決まっていないエラーです。

ビルド前に、下記を実行しておくと、本体側のディスプレイにウィンドウが表示されます。

export DISPLAY=:0