はじめに
NIFsの使い方がわからないでいたのですが、この度、教わりつつ初歩的なコードが動きましたので書き記します。
NIFsとは
native implemented functionsの略であり、ElixirからCで書かれたコードを呼び出す仕組みです。
トラブル
私の環境ははWindows上でWSLによるUbuntu18.04です。erl_nif.hというヘッダファイルが必要なのですが、これが見つからないとしてCコンパイラがエラーを出してきました。どこにそのファイルが収録されているのかが、わからずに頓挫していました。この度Elixirフォーラムに質問をしたところ解決しました。
回答は次の処理をすればいいよ、というものでした。https://elixirforum.com/t/where-is-erl-nif-h-header-file-required-for-nif/27142
sudo apt install erlang-dev
これにより必要なヘッダファイルが準備され、コンパイル可能となりました。
Cのコード
下記のブログがとてもよく説明しています。そのコードがそのまま動きました。
https://andrealeopardi.com/posts/using-c-from-elixir-with-nifs/
#include "erl_nif.h"
static ERL_NIF_TERM
fast_compare(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
int a, b;
enif_get_int(env, argv[0], &a);
enif_get_int(env, argv[1], &b);
int result = a == b ? 0 : (a > b ? 1 : -1);
return enif_make_int(env, result);
}
// Let's define the array of ErlNifFunc beforehand:
static ErlNifFunc nif_funcs[] = {
// {erl_function_name, erl_function_arity, c_function}
{"fast_compare", 2, fast_compare}
};
ERL_NIF_INIT(Elixir.FastCompare, nif_funcs, NULL, NULL, NULL, NULL)
コンパイル
動的リンク可能なオブジェクトを生成します。GCCを使いました。次のようにコンパイルします。
gcc -shared -fPIC -o nif.so nif.c
Elixirからの呼び出し
上述のブログのコードから引用します。オブジェクトファイルの名前だけを変更しています。
defmodule FastCompare do
@on_load :load_nifs
def load_nifs do
:erlang.load_nif('./nif', 0)
end
def fast_compare(_a, _b) do
raise "NIF fast_compare/2 not implemented"
end
end
起動
iex(1)> FastCompare.fast_compare(99, 100)
-1
iex(2)> FastCompare.fast_compare(101, 100)
1
iex(3)>
上手くいきました。
プロジェクト
NIFsを利用してGPUによるCUDA、cuBLASライブラリを呼び出すことにトライしています。DeepLearningでは高速な行列計算が必要とされます。cuBLASをElixirから利用できればElixirによるAI,DLに有用ではないかと思っています。