ErlangでElixir/mixのようなproject管理ってどうなっているんだ

はじめに
-----
Elixir中心で学んできましたが、kernelやVMのコードを見るとなるErlangを知る必要があると痛感。そして、見ていくと、プロジェクトはどうなっているんだろうか、depsはどのように定義されているのか、気になり始め、調べるに至りました。ここではその学んだ内容を書きます。

Projectを作成する方法には以下の二つの方法があるようです。
1. [rebar3　資料リンク](https://rebar3.org/docs/getting-started/) 
   `mix new <project>`と同じように`rebar3 new ....`で作ります。その他、`mix`と同様にコマンドが多々あります。
2. [erlang.mk　資料リンク](https://erlang.mk/guide/getting_started.html) 
   数百のテンプレートが用意されており、各々に応じた`src`と`erlang.mk`が作成されます。
   `mix`のようなコマンドは無く、`make`コマンド処理される。

本記事では、`rebar3`についてまとめます。ただし、対象はMacOSでのものです。


`rebar3`って何
-----
Erlangの標準ビルトツールで
* オープンソースに沿って公開されたErlangのいろいろなツールを統合するもの
* そして、プロジェクト構成結合をする役割を持つもの

要は各ツールのまとめをやり、モジュール取り込み(deps)を行うもの。

`rebar3`はErlangで作られ、escriptによる実行ファイルです。

`rebar3`のインストール
-----
予めインストールされた仮の`rebar3`を実行する事により新たな`rebar3`をインストールします。

まず、`brew`または`asdf`で`rebar3`をインストールし、そのコマンドにより、新しく`~/.cache/rebar3`ローカルにインストールします。
`rebar3`をインストールするために`rebar3`が必要とはすごくおかしい気がしますが、`brew`などで取得したものは`rebar3`の実行ファイルのみで、以下の方法では展開先`~/.cache/rebar3`にlibが展開され、利用できるようになっていて違っています。
一度、展開したら、予め用意した`rebar3`は不要でアンインストールまたは削除可能です。


* ローカルへインストール
```
$ rebar3 local install
===> Extracting rebar3 libs to ~/.cache/rebar3/lib...
===> Writing rebar3 run script ~/.cache/rebar3/bin/rebar3...
===> Add to $PATH for use: export PATH=$PATH:~/.cache/rebar3/bin
```
upgradeします。
```
$ rebar3 local upgrade
===> Extracting rebar3 libs to ~/.cache/rebar3/lib...
===> Writing rebar3 run script ~/.cache/rebar3/bin/rebar3...
===> Add to $PATH for use: export PATH=$PATH:~/.cache/rebar3/bin
```
PATHを設定します。各shellの環境設定に。(`zshrc`など)
```
export PATH=$PATH:~/.cache/rebar3/bin
```
最後に元々ある`rebar3`は不要となり、uninstalまたは削除lしておきます。

* ソースからインストール
`brew`などで仮の`rebar3`をインストールせず、この手順をやれば問題ないと思えますが、資料がこの順番で紹介され、なぜなのか、わかりません。
```
$ git clone https://github.com/erlang/rebar3.git
$ cd rebar3
$ ./bootstrap
```
`rebar3`の実行ファイルが展開されるので、それ以降は「ローカルへインストール」の手順です。

```
./rebar3 local install
    |
    |
```
展開するディレクトリーは実行できれば良いのでどこでもかまいません。`rebar3 local install`により固定`~/.cache/rebar3`に展開され、処理後は上記ディレクトリーは削除すれば良い。



`$ rebar3 new <template> <project-name>`　- 新しくProjectを作る
-----
projectの用途により各テンプレートが用意され、その指定により`.app、src/code`を生成します。

\<template\>の種類
`app` : アプリケーションのprojectを作ります。
`lib` : ライブラリー作成
`release` : リリース用のprojectを作る。
`umbrella`: Erlangでは`poncho`の構成でなく、`umbrella`構成が標準のようです。
`escript` : 実行ファイルを作る時のproject作成
`plugin` : [plugin](https://medium.com/erlang-battleground/the-rebar3-plugin-a-simple-rebar3-template-to-fast-build-your-plugins-71ab0129456b) を作成
`cmake` : C/C++のコードのMakefileを作成する。コード展開はない。

例、`$ rebar3 new app myapp` --> 以下の構成ファイルに展開されます。
```
myapp
├── LICENSE
├── README.md
├── rebar.config
└── src
    ├── myapp.app.src
    ├── myapp_app.erl
    └── myapp_sup.erl
```

`$ rebar3 compile` - コンパイルする
-----
`new`で各ファイルを展開したものをコンパイルし、`_build`ディレクトリーに展開されます。
上記myappの場合
```
├── _build
│   └── default
│       └── lib
│           └── myapp
│               ├── ebin
│               │   ├── myapp.app
│               │   ├── myapp_app.beam
│               │   └── myapp_sup.beam
│               ├── include -> ../../../../include
│               ├── priv -> ../../../../priv
│               └── src -> ../../../../src
```




`$ rebar3 shell`　- projectを実行する。
-----
`mix run`の代わりに`rebar3 shell`で実行します。
```
$ rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling myapp
Erlang/OTP 25 [erts-13.0.3] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns]

Eshell V13.0.3  (abort with ^G)
1> ===> Booted myapp
 
1> 
```

`$ rebar3 help`　-- タスク一覧と詳細表示
-----
`$ rebar3 help`により各タスクの一覧が表示されます。

各タスクのhelp表示は`$ rebar3 help <task>`です。
例、
```
$ rebar3 help compile
Compile apps .app.src and .erl files.
Usage: rebar3 compile [-d]

  -d, --deps_only  Only compile dependencies, no project apps will be 
                   built.
```

Projectの定義ファイル(`.app` or `.app.src`)
-----
Projectの情報は`.app`または `.app.src`の拡張子のファイルに定義します。

```
%% 項目名        値                          値属性       Default
{application, Application,              %% atom()   
  [{description,  Description},         %% string()     ""
   {id,           Id},                  %% string()     ""
   {vsn,          Vsn},                 %% string()     ""
   {modules,      Modules},             %% [Module]     []
   {maxP,         MaxP},                %% int()        infinity
   {maxT,         MaxT},                %% int()        infinity
   {registered,   Names},               %% [Name]       []
   {included_applications, Apps},       %% [App]        []
   {optional_applications, Apps},       %% [App]        []
   {applications, Apps},                %% [App]        []
   {env,          Env},                 %% [{Par,Val}]  []
   {mod,          Start},               %% {Module,StartArgs}  {}
   {start_phases, Phases},              %% [{Phase,PhaseArgs}]  undefined
   {runtime_dependencies, RTDeps}]}.    %% [ApplicationVersion] []
```
例の`myapp`の場合
```
{application, myapp,
 [{description, "An OTP application"},
  {vsn, "0.1.0"},
  {registered, []},
  {mod, {myapp_app, []}},
  {applications,
   [kernel,
    stdlib
   ]},
  {env,[]},
  {modules, []},

  {licenses, ["Apache-2.0"]},
  {links, []}
 ]}.
```

`deps`の定義はどこに
-----
`rebar.config`のファイルに定義され、そこからローカル(`_build/`)に展開されるようになっています。Elixirでの`deps/`ディレクトリーはなく、コンパイル実行によりすべて`_build/`に展開されるようになっています。

例、`rebar.config`の一部`deps`の部分、参考資料から抜粋して適当セットしました。
```
{deps, [
    {erldns,
     {git, "https://github.com/tsloughter/erldns.git",
     {branch, "revamp"}}},
    {dns,
     {git, "https://github.com/tsloughter/dns_erlang.git",
     {branch, "hex-deps"}}},
    recon,
    eql,
    jsx,
    {uuid, "1.7.5", {pkg, uuid_erl}},
    {elli, "~> 3.2.0"},
    {grpcbox, "~> 0.11.0"}
 ]}.
```
展開結果--`dns`部分の詳細です。
```
_build
└── default
    ├── lib
    │   ├── base32
    │   ├── dns
    │   │   ├── LICENSE
    │   │   ├── Makefile
    │   │   ├── README.markdown
    │   │   ├── asn1
    │   │   │   └── DNS-ASN1.asn1
    │   │   ├── asngen
    │   │   │   ├── DNS-ASN1.asn1db
    │   │   │   ├── DNS-ASN1.beam
    │   │   │   ├── DNS-ASN1.erl
    │   │   │   └── DNS-ASN1.hrl
    │   │   ├── ebin
    │   │   │   ├── DNS-ASN1.beam
    │   │   │   ├── dns.app
    │   │   │   ├── dns.beam
    │   │   │   ├── dns_record.beam
    │   │   │   ├── dns_record_info.beam
    │   │   │   └── dnssec.beam
    │   │   ├── include
    │   │   │   ├── DNS-ASN1.hrl
    │   │   │   ├── dns.hrl
    │   │   │   ├── dns_records.hrl
    │   │   │   ├── dns_terms.hrl
    │   │   │   ├── dns_tests.hrl
    │   │   │   ├── dnssec_tests.hrl
    │   │   │   └── rebar_version.hrl
    │   │   ├── priv
    │   │   │   ├── dnssec_samples.txt
    │   │   │   ├── index.html
    │   │   │   ├── overview.edoc
    │   │   │   ├── rrdata_wire_samples.txt
    │   │   │   └── tsig_wire_samples.txt
    │   │   ├── rebar.config
    │   │   ├── rebar.lock
    │   │   └── src
    │   │       ├── DNS-ASN1.asn1db
    │   │       ├── DNS-ASN1.erl
    │   │       ├── dns.app.src
    │   │       ├── dns.erl
    │   │       ├── dns_record.erl
    │   │       ├── dns_record_info.erl
    │   │       └── dnssec.erl
    │   └── myapp
```

`circuits_i2c`は使えるのか
----
Hexからダウンロードするバージョン
![Screenshot 2023-03-24 at 3.24.35 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146500/bf41fb9a-2bd2-44b9-bcd4-0f9459ab212d.png)


の`rebar.config`のタグから
```
{deps, [
    {circuits_i2c, "1.2.1"}
 ]}.
```
でpackageを取り込めるか、確かめましたが、エラーが発生し、ビルトできませんでした。

`Hex`からダウンロードし、そのpackageを使う事はできるようになっていますが、問題が発生し、処置が必要なようです。



まとめ
-----
Elixir/Mixと違い、`rebar3`はなんか使いにくいとの印象。慣れの問題かもしれない。
Elixirでは`deps`ディレトリー然り、`config`など区別され、分かり易いが、Erlangでは`_build`内に詰め込んでいる。Erlang(旧)からElixir(新)と流れ、やはり新しいのは昔のものの改良版で使いやすいの当然なんだろう。
それと、ElixirからErlangを呼ぶ事は普通だが、その逆ってできるんだろうか、疑問になる。他にも疑問だらけだが、今はerlangの仕組みがわかり、コードを追えれば良いと思うので。深く調べる事はしない。