LoginSignup
7
4

More than 1 year has passed since last update.

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

Posted at

はじめに

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

Projectを作成する方法には以下の二つの方法があるようです。

  1. rebar3 資料リンク
    mix new <project>と同じようにrebar3 new ....で作ります。その他、mixと同様にコマンドが多々あります。
  2. erlang.mk 資料リンク
    数百のテンプレートが用意されており、各々に応じたsrcerlang.mkが作成されます。
    mixのようなコマンドは無く、makeコマンド処理される。

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

rebar3って何

Erlangの標準ビルトツールで

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

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

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

rebar3のインストール

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

まず、brewまたはasdfrebar3をインストールし、そのコマンドにより、新しく~/.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 を作成
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

rebar.configのタグから

{deps, [
    {circuits_i2c, "1.2.1"}
 ]}.

でpackageを取り込めるか、確かめましたが、エラーが発生し、ビルトできませんでした。

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

まとめ

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

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4