Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hacking Elixir How-To

ohr486
September 29, 2019

Hacking Elixir How-To

ohr486

September 29, 2019
Tweet

More Decks by ohr486

Other Decks in Programming

Transcript

  1. Hacking Elixir
    HowTo
    tokyo.ex#13 @ohrdev

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  4. 準備
    ● 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  8. 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

    View full-size slide

  9. 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(後述)

    View full-size slide

  10. 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

    View full-size slide

  11. 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ファイルが配置される

    View full-size slide

  12. 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
    で終了する

    View full-size slide

  13. 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

    View full-size slide

  14. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide