<Enjoy-Elixir>Mix

目次

Enjoy-Elixirと称する、プログラミング言語Elixirを勉強する記事群の1つです。

Mixとは?

mix コマンドはElixirをインストールした時に付随してインストールされているはずです。とりあえず help を見てみましょう。

$ mix --help
Mix is a build tool for Elixir

Usage: mix [task]

Examples:

    mix             - Invokes the default task (mix run) in a project
    mix new PATH    - Creates a new Elixir project at the given path
    mix help        - Lists all available tasks
    mix help TASK   - Prints documentation for a given task

The --help and --version options can be given instead of a task for usage and versioning information.

Mix is a build tool for Elixir

mix はElixirのためのビルドツールです。ビルドツールって何でしょうね?

hexdocs を見るともう少し詳しいことが書いてあります。

Mix is a build tool that provides tasks for creating, compiling, and testing Elixir projects, managing its dependencies, and more.

まず Elixirプロジェクト(Mixプロジェクト) という概念・モノがあります。 mix は、この Elixirプロジェクト(Mixプロジェクト) を作成したり、コンパイルしたりテスト実行できるものです。さらにプロジェクトに必要な依存関係も管理してくれます。もっといろんなことも。

というわけで、単に「ビルドツール」と呼ぶより、 Elixirプロジェクトを管理するツール と考えたほうがわかりやすいでしょう。

Elixirプロジェクトを見てみよう

ここでは既存の Elixirプロジェクト を持ってきて、 mix コマンドを使い、どんなことができるかやってみます。

Elixirプロジェクトとして、JSONライブラリである michalmuskala/jason を使います。

# 準備
$ git clone https://github.com/michalmuskala/jason.git
$ cd jason
$ ls -1
CHANGELOG.md
LICENSE
README.md
bench
dialyzer.ignore
formatter_test_suite
json_test_suite
lib
mix.exs
mix.lock
test

mix help コマンドを実行すると、このプロジェクトで利用できる task がわかります。

# current dir is /path/to/jason
$ mix help
mix                   # Runs the default task (current: "mix run")
mix app.config        # Configures all registered apps
mix app.start         # Starts all registered apps
mix app.tree          # Prints the application tree
mix archive           # Lists installed archives
mix archive.build     # Archives this project into a .ez file
mix archive.install   # Installs an archive locally
mix archive.uninstall # Uninstalls archives
mix clean             # Deletes generated application files
mix cmd               # Executes the given command
mix compile           # Compiles source files
mix deps              # Lists dependencies and their status
mix deps.clean        # Deletes the given dependencies' files
mix deps.compile      # Compiles dependencies
mix deps.get          # Gets all out of date dependencies
mix deps.tree         # Prints the dependency tree
mix deps.unlock       # Unlocks the given dependencies
mix deps.update       # Updates the given dependencies
mix do                # Executes the tasks separated by comma
mix escript           # Lists installed escripts
mix escript.build     # Builds an escript for the project
mix escript.install   # Installs an escript locally
mix escript.uninstall # Uninstalls escripts
mix format            # Formats the given files/patterns
mix help              # Prints help information for tasks
mix hex               # Prints Hex help information
mix hex.audit         # Shows retired Hex deps for the current project
mix hex.build         # Builds a new package version locally
mix hex.config        # Reads, updates or deletes local Hex config
mix hex.docs          # Fetches or opens documentation of a package
mix hex.info          # Prints Hex information
mix hex.organization  # Manages Hex.pm organizations
mix hex.outdated      # Shows outdated Hex deps for the current project
mix hex.owner         # Manages Hex package ownership
mix hex.package       # Fetches or diffs packages
mix hex.publish       # Publishes a new package version
mix hex.repo          # Manages Hex repositories
mix hex.retire        # Retires a package version
mix hex.search        # Searches for package names
mix hex.user          # Manages your Hex user account
mix loadconfig        # Loads and persists the given configuration
mix local             # Lists local tasks
mix local.hex         # Installs Hex locally
mix local.public_keys # Manages public keys
mix local.rebar       # Installs Rebar locally
mix new               # Creates a new Elixir project
mix profile.cprof     # Profiles the given file or expression with cprof
mix profile.eprof     # Profiles the given file or expression with eprof
mix profile.fprof     # Profiles the given file or expression with fprof
mix release           # Assembles a self-contained release
mix release.init      # Generates sample files for releases
mix run               # Starts and runs the current application
mix test              # Runs a project's tests
mix test.coverage     # Build report from exported test coverage
mix xref              # Prints cross reference information
iex -S mix            # Starts IEx and runs the default task

けっこう色んな task がありますね。

とりあえずは mix run を実行してみます。

$ mix run 
Unchecked dependencies for environment dev:
* ex_doc (Hex package)
  the dependency is not available, run "mix deps.get"
* decimal (Hex package)
  the dependency is not available, run "mix deps.get"
* dialyxir (Hex package)
  the dependency is not available, run "mix deps.get"
** (Mix) Can't continue due to errors on dependencies

プロジェクトに必要な依存関係が解決されていないようです。

プロジェクトに必要なものを揃えるために、 mix deps.get を実行します。

$ mix deps.get
07:12:39.800 [error] Task #PID<0.160.0> started from :hex_fetcher terminating
** (UndefinedFunctionError) function :ssl.cipher_suites/1 is undefined or private
    (ssl 10.4.1) :ssl.cipher_suites(:openssl)
    (hex 0.20.5) lib/hex/http/ssl.ex:124: Hex.HTTP.SSL.filter_ciphers/1
    (hex 0.20.5) lib/hex/http/ssl.ex:66: Hex.HTTP.SSL.ssl_opts/1
    (hex 0.20.5) lib/hex/http.ex:41: Hex.HTTP.build_http_opts/2
    (hex 0.20.5) lib/hex/http.ex:16: Hex.HTTP.request/5
    (hex 0.20.5) lib/hex/registry/server.ex:306: anonymous fn/3 in Hex.Registry.Server.prefetch_online
/2
    (elixir 1.12.1) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (elixir 1.12.1) lib/task/supervised.ex:35: Task.Supervised.reply/5
Function: #Function<17.86168715/0 in Hex.Registry.Server.prefetch_online/2>
    Args: []

なんかエラーが出ました。。。

調べると、 mix local.hex をする必要があるみたいです。


Hex について少し調べてみましょう。

Hex はパッケージマネージャーです。Hex のサイトにElixrやErlangのアプリケーション、ライブラリが登録されていて、そこからいい感じにバージョンや依存関係を解決して、取得できるものです。

Mix はプロジェクト管理ツールでしたね。 Mix の仕事の1つに依存関係の解決がありますが、そこで Hex を使っているわけです。

Mix で依存関係の解決を行うためには Hex が必要になります。


というわけで、 Hex を導入しましょう。

$ mix local.hex

この後、再び mix deps.get を実行します。

$ mix deps.get
Resolving Hex dependencies...
Dependency resolution completed:
Unchanged:
  decimal 2.0.0
  dialyxir 1.0.0
  earmark_parser 1.4.10
  erlex 0.2.6
  ex_doc 0.23.0
  makeup 1.0.5
  makeup_elixir 0.15.0
  nimble_parsec 1.1.0
  stream_data 0.5.0
* Getting decimal (Hex package)
* Getting dialyxir (Hex package)
* Getting ex_doc (Hex package)
* Getting stream_data (Hex package)
* Getting earmark_parser (Hex package)
* Getting makeup_elixir (Hex package)
* Getting makeup (Hex package)
* Getting nimble_parsec (Hex package)
* Getting erlex (Hex package)

jason プロジェクトに必要なライブラリを取得して、依存関係を解決することができましたね。

mix run を実行してみましょう。

$ mix run
==> earmark_parser
Compiling 1 file (.yrl)
Compiling 2 files (.xrl)
Compiling 3 files (.erl)
Compiling 32 files (.ex)
Generated earmark_parser app
==> erlex
Compiling 1 file (.yrl)
src/parser.yrl: Warning: conflicts: 27 shift/reduce, 0 reduce/reduce
Compiling 1 file (.xrl)
Compiling 2 files (.erl)
Compiling 1 file (.ex)
Generated erlex app
==> nimble_parsec
Compiling 4 files (.ex)
Generated nimble_parsec app
==> makeup
Compiling 44 files (.ex)
Generated makeup app
==> decimal
Compiling 4 files (.ex)
Generated decimal app
==> dialyxir
Compiling 59 files (.ex)
warning: Mix.Project.compile/1 is deprecated. Use Mix.Task.run("compile", args) instead
  lib/dialyxir/project.ex:47: Dialyxir.Project.cons_apps/0

warning: Mix.Project.compile/1 is deprecated. Use Mix.Task.run("compile", args) instead
  lib/mix/tasks/dialyzer.ex:164: Mix.Tasks.Dialyzer.run/1

Generated dialyxir app
==> makeup_elixir
Compiling 6 files (.ex)
Generated makeup_elixir app
==> ex_doc
Compiling 22 files (.ex)
Generated ex_doc app
==> jason
Compiling 9 files (.ex)
Generated jason app

mix run を実行すると、 Generated jason app と最後に出力されているので、アプリケーションのビルドが実行されましたね。アプリケーションのビルドは、プロジェクト管理ツールの仕事の1つですね。

テストも実行してみましょう。テストの実行は mix test です。

$ mix test
==> makeup_elixir
Compiling 6 files (.ex)
Generated makeup_elixir app
bash-3.2$ mix test
==> erlex
Compiling 2 files (.erl)
Compiling 1 file (.ex)
Generated erlex app
==> stream_data
Compiling 3 files (.ex)
Generated stream_data app
==> decimal
Compiling 4 files (.ex)
Generated decimal app
==> dialyxir
Compiling 59 files (.ex)
warning: Mix.Project.compile/1 is deprecated. Use Mix.Task.run("compile", args) instead
  lib/dialyxir/project.ex:47: Dialyxir.Project.cons_apps/0

warning: Mix.Project.compile/1 is deprecated. Use Mix.Task.run("compile", args) instead
  lib/mix/tasks/dialyzer.ex:164: Mix.Tasks.Dialyzer.run/1

Generated dialyxir app
==> jason
Compiling 9 files (.ex)
Generated jason app
......................................................................................................
......................................................................................................
......................................................................................................
......................................................................................................
.............................

Finished in 0.5 seconds (0.5s async, 0.00s sync)
25 doctests, 9 properties, 403 tests, 0 failures

アプリケーションを再コンパイルして、テストを実行、そしてテスト結果が出力されました。テスト実行もプロジェクト管理ツールの1つです。

まとめ

今回の記事は Mix の紹介でした。

以下に内容をまとめます。

  • Elixirプロジェクト(Mixプロジェクト) という概念・モノがある
  • mixElixirプロジェクト を管理するツール
  • hex はパッケージマネージャー。 mix の依存関係解決の仕事で使われるので必要になる
  • mix に定義されている task を実行することで、プロジェクトに関することが色々できる
  • たとえば mix deps.get で依存関係の解決ができる
  • たとえば mix test でテストを実行できる

Mix はElixirプロジェジエクトの管理ツールだ、というところを押さえておきましょう。

次は michalmuskala/jason ライブラリ(Elixirプロジェクト) をコードリーティングしながら、学習を進めていく予定です。

参考