Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Rパッケージで Rustを使うには: extendr入門 Hiroaki Yutani (@yutannihilation) Tokyo.R#92
Slide 2
Slide 2 text
ドーモ! : @yutannihilation 好きな言語: R、Rust、忍殺語 最近の趣味: ガスコンロの電子楽器 をつくってます
Slide 3
Slide 3 text
Rユーザのための RStudio[実践]入 門 第2版! https://gihyo.jp/book/2021/978- 4-297-12170-9 紙は6月3日、電子は5 月31日発売です。
Slide 4
Slide 4 text
extendr
Slide 5
Slide 5 text
extendrとは? RustとRを連携させるためのフレームワーク RからRustを使うだけではなく、RustからRを使 うこともできる(つまり、Rustの中でggplot2を 呼び出してプロットしたり、とかできるらしい) なぜか私も中の人です…
Slide 6
Slide 6 text
なぜRust? → そこにRustがあるから!! (誰か教えてください…)
Slide 7
Slide 7 text
※今日話さないこと Rustの何が素晴らしいのか Rust入門 Rust側からRを操作する方法 R MarkdownのRust engineとか、パッケージ外 でのextendrの使いみち
Slide 8
Slide 8 text
extendrの愉快な仲間たち libR-sys(Rust): RのC APIにbindgenで生成したバインディング extendr(Rust): libR-sysを使いやすくラップしたフレームワーク rextendr(Rパッケージ): Rからextendrを使うためのユーティリティ (usethisパッケージのような立ち位置)
Slide 9
Slide 9 text
準備
Slide 10
Slide 10 text
Rustのインストール macOS / Linux: ふつうにRustをインストール(ググる) Windows MSVCのtoolchainに加えて、64bit/32bit GNU用 のtargetを追加する必要がある rustup default stable-msvc rustup target add x86_64-pc-windows-gnu rustup target add i686-pc-windows-gnu
Slide 11
Slide 11 text
rextendrパッケージのインストール GitHubからインストール devtools::install_github("extendr/rextendr")
Slide 12
Slide 12 text
パッケージのセットアップ
Slide 13
Slide 13 text
RStudioからパッケージ作成
Slide 14
Slide 14 text
Roxygenを使うように設定変更 NAMESPACEを上書き Build optionsを設定 Build > Configure Build Tools… > Generate documentation with Roxygen に を入れる 不要なファイルを削除 R/hello.R man/hello.Rd usethis::use_namespace() ` ` ` `
Slide 15
Slide 15 text
extendrのデフォルト設定を生成 rextendr::use_extendr() ✓ Creating src/rust/src. ✓ Writing 'src/entrypoint.c' ✓ Writing 'src/Makevars' ✓ Writing 'src/Makevars.win' ✓ Writing 'src/.gitignore' ✓ Writing src/rust/Cargo.toml. ✓ Writing 'src/rust/src/lib.rs' ✓ Writing 'R/extendr-wrappers.R' ✓ Finished configuring extendr for package myextendr. • Please update the system requirement in DESCRIPTION file. • Please run `rextendr::document()` for changes to take effect
Slide 16
Slide 16 text
生成されたファイル . ├── R │ └── extendr-wrappers.R ... └── src ├── Makevars ├── Makevars.win ├── entrypoint.c └── rust ├── Cargo.toml └── src └── lib.rs
Slide 17
Slide 17 text
いじるファイル src/rust: extendrを使ったRustのcrate。開発のメインはこ こ。
Slide 18
Slide 18 text
基本いじらないファイル Makevars, Makevars.win: パッケージインストール時に cargo build が走るように する設定。 entrypoint.c: コンパイラにシンボルを勝手に消されないためのおま じない。 R/extendr-wrappers.R: Rustの関数から自動生成されたRの関数。 ` `
Slide 19
Slide 19 text
src/rust/Cargo.toml [package] name = 'myextendr' version = '0.1.0' edition = '2018' [lib] crate-type = [ 'staticlib' ] [dependencies] extendr-api = '*'
Slide 20
Slide 20 text
src/rust/src/lib.rs(一部省略) use extendr_api::prelude::*; /// Return string `"Hello world!"` to R. /// @export #[extendr] fn hello_world() -> &'static str { "Hello world!" } extendr_module! { mod myextendr; fn hello_world; }
Slide 21
Slide 21 text
src/rust/src/lib.rs よく使う関数をまとめて読み込み /// (3つ)のコメントはそのままRoxygenのコ メントになる これをつけるとRの関数が自動生成! use extendr_api::prelude::*; ` ` /// Return string `"Hello world!"` to R. /// @export #[extendr]
Slide 22
Slide 22 text
src/rust/src/lib.rs 関数をエクスポートしてRが認識できるように登録 (routine registration)してくれるマクロ。 新 しく関数を追加したらここに入れる必要がある。 extendr_module! { mod myextendr; fn hello_world; }
Slide 23
Slide 23 text
開発の流れ
Slide 24
Slide 24 text
開発の流れ 1. Rustのコードを編集 2. rextendr::document() でRのコードを自動生成(Rust のコードのコンパイルもこれがやってくれる) 3. (必要あれば)生成されたコードをRの側でいい感 じにラップする 4. devtools::load_all() (やテスト)で動作確認 ` ` ` `
Slide 25
Slide 25 text
rextendr::document() ` ` > rextendr::document() ✓ Saving changes in the open files. ℹ Generating extendr wrapper functions for package: myextendr. ! No library found at src/myextendr.so, recompilation is requi Re-compiling myextendr ─ installing *source* package ‘myextendr’ ... (382ms) ** using staged installation ** libs rm -Rf myextendr.so ./rust/target/release/libmyextendr.a en gcc -std=gnu99 -I"/usr/share/R/include" -DNDEBUG -fpic cargo build --lib --release --manifest-path=./rust/Cargo.to Updating crates.io index
Slide 26
Slide 26 text
生成されるファイル . ... ├── NAMESPACE <- @exportが反映される ├── R │ └── extendr-wrappers.R <- Rustの関数から自動生成 └── src ├── myextendr.so <- libmyextendr.aを使ってビルドされた └── rust 共有オブジェクト └── target <- Rustの生成物が入るディレクトリ └── release ├── libmyextendr.a <- Rustのコードの静的ライブラリ ... (OSによって拡張子は違う)
Slide 27
Slide 27 text
自動生成されたRの関数 Rust R /// Return string `"Hello world!"` to R. /// @export #[extendr] fn hello_world() -> &'static str { "Hello world!" } #' Return string `"Hello world!"` to R. #' @export hello_world <- function() .Call(wrap__hello_world)
Slide 28
Slide 28 text
実行結果 #> [1] "Hello world!" devtools::load_all(".") hello_world()
Slide 29
Slide 29 text
例1) i32 (integer)を引数に取る 関数
Slide 30
Slide 30 text
自動生成されたRの関数 Rust R /// @export #[extendr] fn add(x: i32, y: i32) -> i32 { x + y } #' @export add <- function(x, y) .Call(wrap__add, x, y)
Slide 31
Slide 31 text
実行結果 #> [1] 3 #> Error in add(1:2, 2:3) : #> Input must be of length 1. Vector of length >1 given. devtools::load_all(".") # 引数の型は i32 だけど実数も渡せる add(1, 2) # 長さ1以上だとエラーになる add(1:2, 2:3)
Slide 32
Slide 32 text
例2) Vecを引数に取る関数
Slide 33
Slide 33 text
自動生成されたRの関数 Rust R #[extendr] fn mult(x: Vec, y: i32) -> Vec { x .iter() .map(|n| n * y) .collect::>() } #' @export mult <- function(x, y) .Call(wrap__mult, x, y)
Slide 34
Slide 34 text
実行結果 #> [1] 10 20 30 40 50 devtools::load_all(".") mult(1:5, 10)
Slide 35
Slide 35 text
例3) struct
Slide 36
Slide 36 text
struct…? 環境としてエクスポートされるので状態を持つこ とができる たまに便利(正規表現のキャッシュを持たせてい る例: rr4r)
Slide 37
Slide 37 text
自動生成されたRの関数 Rust struct Counter { i: i32, } /// @export #[extendr] impl Counter { fn new() -> Self { Self { i: 0 } } fn count(&mut self) -> i32 { self.i = self.i + 1; self.i } }
Slide 38
Slide 38 text
自動生成されたRの関数 R #' @export Counter <- new.env(parent = emptyenv()) Counter$new <- function() .Call(wrap__Counter__new) Counter$count <- function() .Call(wrap__Counter__count, self) #' @rdname Counter #' @usage NULL #' @export `$.Counter` <- function (self, name) { func <- Counter[[name]]
Slide 39
Slide 39 text
実行結果 #> [1] 1 #> [1] 2 devtools::load_all(".") cnt <- Counter$new() cnt$count() cnt$count()
Slide 40
Slide 40 text
その他こまごました話 (時間があれば)
Slide 41
Slide 41 text
その他 文字列関連はlifetimeを意識しないと使えないの で初心者にはハードモード。数値計算系からはじ めるのがおすすめ。 Windowsのセットアップはやや面倒だけど、 GitHub Actionsでビルド済みのバイナリを配布し たりできるはず(調査中) CRANにはすでにextendrを使っているパッケージ も存在する
Slide 42
Slide 42 text
まとめ
Slide 43
Slide 43 text
まとめ extendrを使うとマクロの魔術でRustの関数から Rの関数を生成してくれる。 関数の引数の対応づけはRcppやcpp11と同じノ リ。慣れている人はわりとすぐに使えるはず。 ちなみに、今回はすべてRustのデータ型に変換 するタイプだったが、SEXPのまま扱うことも できる(ここはよく理解できていない) フィードバックお待ちしています!
Slide 44
Slide 44 text
r-wakalangにrustチャンネルをつくり ました
Slide 45
Slide 45 text
References extendr: https://github.com/extendr/extendr extendrのロゴはCC-BY-SA 4.0ライセンスで配布 されています: https://github.com/extendr/artwork.