Slide 1

Slide 1 text

Hacking Elixir HowTo tokyo.ex#13 @ohrdev

Slide 2

Slide 2 text

agenda ● Goal ● 準備 ● ElixirのMake ● Makefile内のコマンド ● Compileフロー ● Elixirカーネルcompile ● exファイルcompile ● Hack#1 versionを差し替えてみる ● Hack#2 標準モジュールを追加する

Slide 3

Slide 3 text

Goal ● Elixir本体のコンパイルの流れを理解する ● Elixir本体の改造方法を理解する ● Elixir本体の簡単なHackを体験する

Slide 4

Slide 4 text

準備 ● githubからElixirのソースコードをclone ○ https://github.com/elixir-lang/elixir ■ Elixir 1.9.1 を対象にしています ● Erlangのインストール ○ macの場合 ■ brew install erlang ■ asdf erlang install {VERSION} ○ winの場合 ■ https://www.erlang.org/downloads ● Elixirのインストールに必要なErlangのバージョン ○ Makefile内のチェック関数を参照 ■ elixir 1.9.1の場合は、erlang20.0以上 ● https://github.com/elixir-lang/elixir/blob/v1.9.1/Makefile#L30

Slide 5

Slide 5 text

ElixirのMake ● Elixir本体のCompileはMakefileを利用して行われます ● Makeとは? ○ コンパイル・リンク・インストール等のルールを記述した Makefileに従ってこれらの作業を自動で実 行するツール ● 基本は以下の通り <変数宣言> <タスク名>: <実行したいコマンド> <タスク名>: <依存ファイル> <実行したいコマンド>

Slide 6

Slide 6 text

MakeのTips ● インデントはタブ ● 「:=」で変数定義 ● 実行コマンドの結果を出したくないときは、コマンドの先頭に「@」をつけると非表示 になる ● タスク内から別のタスクを実行することも可能 ● 実行コマンドは複数行にわたって記述可能、ただしインデントは同レベルに ● install, compileの様な明示的な要求タスクは.PHONYで宣言し、ファイルの存在に 関わらず必ず実行できるようにする ● .NOPARALLELで指定されたタスクは(並行オプションをつけていても)シリアルに実 行される

Slide 7

Slide 7 text

Makeの中の自動変数とマクロ ● 自動変数 ○ $@: ターゲットのファイル名 ○ $<: 最初の依存ファイル名 ● マクロ ○ defineでマクロを定義 ○ $nでn番目の引数を受け取り可能 ● マクロの呼び出し ○ callでマクロの呼び出し ● マクロの定義 ○ evalでマクロの変数を展開した上で Makefileの構文として定義

Slide 8

Slide 8 text

Makefile内の実行コマンド変数 ● ELIXIRC: bin以下のelixircシェルスクリプトを実行、実態はexec ○ https://github.com/elixir-lang/elixir/blob/v1.9.1/bin/elixirc#L35 ● ERL: erlangのerlコマンドをオプション付きで実行 ○ erl -I lib/elixir/include -noshell -pa lib/elixir/ebin ○ http://erlang.org/doc/man/erl.html ● ERLC: erlangのerlcコマンドをオプション付きで実行 ○ erlc -I lib/elixir/include $(ERLC_OPTS) ○ http://erlang.org/doc/man/erlc.html

Slide 9

Slide 9 text

Compileフロー ● Makefile( https://github.com/elixir-lang/elixir/blob/v1.9.1/Makefile )のcompileタスク ● 大きく以下の3フェーズに分類 ○ erlangタスク ■ erlangのバージョンチェック ( https://github.com/elixir-lang/elixir/blob/v1.9.1/Makefile#L27 ) ■ パーサージェネレーターの生成 ( https://github.com/elixir-lang/elixir/blob/v1.9.1/Makefile#L78 ) ■ erlangコードのコンパイル( https://github.com/elixir-lang/elixir/blob/v1.9.1/Makefile#L76 ) ○ lib/elixir/ebin/elixir.appを生成 ■ elixir.appファイルをescriptで作成( https://github.com/elixir-lang/elixir/blob/v1.9.1/Makefile#L100 ) ■ escriptは https://github.com/elixir-lang/elixir/blob/v1.9.1/lib/elixir/generate_app.escript ○ elixirタスク ■ stdlib, EEx.beam, mix, ex_unit, logger, eex, iexを生成 ■ elixir本体はstdlibの中のKERNEL(後述)

Slide 10

Slide 10 text

make compile make compile make erlang lib/elixir/ebin/elixir.app make elixir lib/elixir/src/elixir_parser.erl lib/elixir/src/elixir_parser.yrl lib/elixir/src/elixir.app.src lib/elixir/ebin VERSION lib/elixir/generate_app.escript stdlib lib/eex/ebin/Elixir.EEx.beam mix ex_unit logger eex iex APP_TEMPLATE

Slide 11

Slide 11 text

make erlang make erlang lib/elixir/src/elixir_parser.erl lib/elixir/src/elixir_parser.yrl erlc -o lib/elixir/src/elixir_parser.erl +’{verbose,true}’ +’{report,true}’ lib/elixir/src/elixir_parser.yrl yecc: パーサージェネレーター http://erlang.org/doc/man/yecc.html https://github.com/elixir-lang/elixir/blob/v1.9.1/li b/elixir/src/elixir_parser.yrl CHECK_ERLANG_RELEASE https://github.com/elixir-lang/elixir/blob/v1.9.1/Makefile#L28 cd lib/elixir && mkdir -p ebin && erl -make Emakeファイル( https://github.com/elixir-lang/elixir/blob/v1.9.1/lib/elixir/Emakefile ) を読み込んで、make:all() を実行 http://erlang.org/doc/man/make.html lib/elixir/sec以下のerlangコードがコンパイルされ、 lib/elixir/ebin配下にbeamファイルが配置される

Slide 12

Slide 12 text

make stdlib make stdlib lib/elixir/ebin/Elixir.Kernel.beam VERSION lib/elixir/lib/*.ex lib/elixir/lib/*/*.ex lib/elixir/lib/*/*/*.ex KERNEL $(ERL) -s elixir_compiler bootstrap -s erlang halt make unicode cd lib/elixir && ../../$(ELIXIRC) lib/**/*.ex -o ebin make app erl -s … Module:Func(Arg1,...) を実行 ----------------------------------------------- elixir_compiler:bootstrap を実行した後、 elrang:halt で終了する

Slide 13

Slide 13 text

ElixirカーネルComile ● 実体はelixir_compiler:bootstrap ○ https://github.com/elixir-lang/elixir/blob/v1.9.1/lib/elixir/src/elixir_compiler.erl#L123 ● lib/elixir/lib 配下の.exファイルをコンパイル ○ https://github.com/elixir-lang/elixir/blob/v1.9.1/lib/elixir/src/elixir_compiler.erl#L141

Slide 14

Slide 14 text

exファイルCompile ● 実体は$(ELIXIRC) lib/elixir/lib/**/*.ex ○ https://github.com/elixir-lang/elixir/blob/v1.9.1/Makefile#L5 ○ https://github.com/elixir-lang/elixir/blob/v1.9.1/bin/elixirc

Slide 15

Slide 15 text

Hack#1 ● バージョンの差し替え ● elixir --version の結果表示の変更 ● バージョンの実体 ○ https://github.com/elixir-lang/elixir/blob/v1.9.1/lib/elixir/lib/system.ex#L85

Slide 16

Slide 16 text

Hack#2 ● 標準モジュールを追加