結論
-
mix compileは複数のcompile.*タスクから成る。 - 自前の
compile.hogehogeタスクもcompileタスクに組み込むことができる。 - コンパイルのタイミングは
mix.exsで指定する。
Code.require_file "lib/mix/tasks/compile.hogehoge.ex"
defmodule MyAwesomeApp.Mixfile do
use Mix.Project
def project do
[app: :my_awesome_app,
version: "0.0.1",
elixir: "~> 1.0",
compilers: [:hogehoge, :elixir, :app],
deps: deps]
end
# 略
end
説明
何したい
例えばNIFなど、Cで書いた関数を使うElixirモジュールを作りたいとする。そのElixirモジュールはCの関数に依存するわけなので、Elixirモジュールのコンパイルの前にはCのコンパイルが済んでいてほしい。自分でやるなら勝手にどうぞって感じだけど、他人にライブラリとして提供する場合はそうもいかない。mix deps.compileのタイミングで、Cのソースもコンパイルしたい。
どうする
mix deps.compile
mix deps.compileは、依存するライブラリを全てコンパイルする。どうやってコンパイルするかは、そのライブラリが持つファイルによって決まる。
| ファイル | コマンド | 優先度 |
|---|---|---|
| mix.exs | mix compile |
高 |
| rebar.config | rebar compile |
↑ |
| Makefile.win | nmake /F Makefile.win |
↓ |
| Makefile | make |
低 |
Makefileを置いてmakeをさせたいけれど、Mixプロジェクトはmix compileされてしまう。
mix compile
mix compileは複数のタスクを実行する。ここにCをコンパイルするタスクを忍ばせる。タスクはcompile.hogehogeのように、compile名前空間になければならない。どのタイミングで実行するかはmix.exsのproject/0で指定する。デフォルトのcompilersはMix.compilersで取得できるので、それらの前に付ける方法がGithubではよく見られる(特にPhoenixプロジェクト)。
defmodule Mix.Tasks.Compile.Hogehoge do
use Mix.Task
def run(_), do: Mix.shell.cmd "make"
end
def MyAwesomeApp.Mixfile do
def project do
[app: :my_awesome_app,
version: "0.0.1",
elixir: "~> 1.0",
compilers: [:hogehoge] ++ Mix.compilers,
deps: deps]
end
end
これでmix compile時にmakeが走る。ライブラリとして提供した際にもmix deps.compileのときにmakeが走ってNIFが使えるようになる。compile名前空間内なのでコンパイル以外の処理をするのはどうかなー感があるが、Cのコンパイルに限らず任意の処理が可能。