Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
RパッケージでRustを使うには: extendr入門 / extendr-pkg-dev
Search
yutannihilation
May 30, 2021
Programming
1
7k
RパッケージでRustを使うには: extendr入門 / extendr-pkg-dev
第92回R勉強会
の発表スライドです。
(
ウェブ版
をPDFエクスポートしたものですが、Slidevの使い方がわからず画像が消えてしまっています...)
yutannihilation
May 30, 2021
Tweet
Share
More Decks by yutannihilation
See All by yutannihilation
🦀
yutannihilation
2
770
rayshader入門 / rayshader-tokyor88
yutannihilation
0
1.1k
RとApache Arrow / r-and-apache-arrow
yutannihilation
4
7k
そろそろ使ってみませんかApache Arrow / why-dont-you-arrow-now
yutannihilation
2
1.1k
A Graphical Introduction to tidyr's pivot_*()
yutannihilation
5
5.2k
tidyr 1.0.0の新機能 pivot_*() / tidyr-pivot
yutannihilation
4
11k
RとApache Arrow
yutannihilation
0
3.3k
Yet Another Introduction to tidyeval
yutannihilation
10
7.8k
Introduction to gghighlight
yutannihilation
6
2.9k
Other Decks in Programming
See All in Programming
漸進。
ssssota
0
1.8k
エラーって何種類あるの?
kajitack
5
110
Spring gRPC で始める gRPC 入門 / Introduction to gRPC with Spring gRPC
mackey0225
2
480
Zennの運営完全に理解した #完全に理解したTalk
wadayusuke
1
180
統一感のある Go コードを生成 AI の力で手にいれる
otakakot
0
2.9k
GoのGenericsによるslice操作との付き合い方
syumai
1
360
UPDATEがシステムを複雑にする? イミュータブルデータモデルのすすめ
shimomura
1
520
FastMCPでMCPサーバー/クライアントを構築してみる
ttnyt8701
2
130
XSLTで作るBrainfuck処理系
makki_d
0
180
Beyond Portability: Live Migration for Evolving WebAssembly Workloads
chikuwait
0
330
Use Perl as Better Shell Script
karupanerura
0
690
FormFlow - Build Stunning Multistep Forms
yceruto
1
150
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
The World Runs on Bad Software
bkeepers
PRO
68
11k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
The Pragmatic Product Professional
lauravandoore
35
6.7k
Navigating Team Friction
lara
186
15k
Testing 201, or: Great Expectations
jmmastey
42
7.5k
Automating Front-end Workflow
addyosmani
1370
200k
Adopting Sorbet at Scale
ufuk
77
9.4k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
657
60k
The Invisible Side of Design
smashingmag
299
50k
Why Our Code Smells
bkeepers
PRO
337
57k
Building Applications with DynamoDB
mza
95
6.4k
Transcript
Rパッケージで Rustを使うには: extendr入門 Hiroaki Yutani (@yutannihilation) Tokyo.R#92
ドーモ! : @yutannihilation 好きな言語: R、Rust、忍殺語 最近の趣味: ガスコンロの電子楽器 をつくってます
Rユーザのための RStudio[実践]入 門 第2版! https://gihyo.jp/book/2021/978- 4-297-12170-9 紙は6月3日、電子は5 月31日発売です。
extendr
extendrとは? RustとRを連携させるためのフレームワーク RからRustを使うだけではなく、RustからRを使 うこともできる(つまり、Rustの中でggplot2を 呼び出してプロットしたり、とかできるらしい) なぜか私も中の人です…
なぜRust? → そこにRustがあるから!! (誰か教えてください…)
※今日話さないこと Rustの何が素晴らしいのか Rust入門 Rust側からRを操作する方法 R MarkdownのRust engineとか、パッケージ外 でのextendrの使いみち
extendrの愉快な仲間たち libR-sys(Rust): RのC APIにbindgenで生成したバインディング extendr(Rust): libR-sysを使いやすくラップしたフレームワーク rextendr(Rパッケージ): Rからextendrを使うためのユーティリティ (usethisパッケージのような立ち位置)
準備
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
rextendrパッケージのインストール GitHubからインストール devtools::install_github("extendr/rextendr")
パッケージのセットアップ
RStudioからパッケージ作成
Roxygenを使うように設定変更 NAMESPACEを上書き Build optionsを設定 Build > Configure Build Tools… >
Generate documentation with Roxygen に を入れる 不要なファイルを削除 R/hello.R man/hello.Rd usethis::use_namespace() ` ` ` `
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
生成されたファイル . ├── R │ └── extendr-wrappers.R ... └── src
├── Makevars ├── Makevars.win ├── entrypoint.c └── rust ├── Cargo.toml └── src └── lib.rs
いじるファイル src/rust: extendrを使ったRustのcrate。開発のメインはこ こ。
基本いじらないファイル Makevars, Makevars.win: パッケージインストール時に cargo build が走るように する設定。 entrypoint.c: コンパイラにシンボルを勝手に消されないためのおま
じない。 R/extendr-wrappers.R: Rustの関数から自動生成されたRの関数。 ` `
src/rust/Cargo.toml [package] name = 'myextendr' version = '0.1.0' edition =
'2018' [lib] crate-type = [ 'staticlib' ] [dependencies] extendr-api = '*'
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; }
src/rust/src/lib.rs よく使う関数をまとめて読み込み /// (3つ)のコメントはそのままRoxygenのコ メントになる これをつけるとRの関数が自動生成! use extendr_api::prelude::*; ` `
/// Return string `"Hello world!"` to R. /// @export #[extendr]
src/rust/src/lib.rs 関数をエクスポートしてRが認識できるように登録 (routine registration)してくれるマクロ。 新 しく関数を追加したらここに入れる必要がある。 extendr_module! { mod myextendr;
fn hello_world; }
開発の流れ
開発の流れ 1. Rustのコードを編集 2. rextendr::document() でRのコードを自動生成(Rust のコードのコンパイルもこれがやってくれる) 3. (必要あれば)生成されたコードをRの側でいい感 じにラップする
4. devtools::load_all() (やテスト)で動作確認 ` ` ` `
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
生成されるファイル . ... ├── NAMESPACE <- @exportが反映される ├── R │
└── extendr-wrappers.R <- Rustの関数から自動生成 └── src ├── myextendr.so <- libmyextendr.aを使ってビルドされた └── rust 共有オブジェクト └── target <- Rustの生成物が入るディレクトリ └── release ├── libmyextendr.a <- Rustのコードの静的ライブラリ ... (OSによって拡張子は違う)
自動生成された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)
実行結果 #> [1] "Hello world!" devtools::load_all(".") hello_world()
例1) i32 (integer)を引数に取る 関数
自動生成されたRの関数 Rust R /// @export #[extendr] fn add(x: i32, y:
i32) -> i32 { x + y } #' @export add <- function(x, y) .Call(wrap__add, x, y)
実行結果 #> [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)
例2) Vec<i32>を引数に取る関数
自動生成されたRの関数 Rust R #[extendr] fn mult(x: Vec<i32>, y: i32) ->
Vec<i32> { x .iter() .map(|n| n * y) .collect::<Vec<_>>() } #' @export mult <- function(x, y) .Call(wrap__mult, x, y)
実行結果 #> [1] 10 20 30 40 50 devtools::load_all(".") mult(1:5,
10)
例3) struct
struct…? 環境としてエクスポートされるので状態を持つこ とができる たまに便利(正規表現のキャッシュを持たせてい る例: rr4r)
自動生成された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 } }
自動生成された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]]
実行結果 #> [1] 1 #> [1] 2 devtools::load_all(".") cnt <-
Counter$new() cnt$count() cnt$count()
その他こまごました話 (時間があれば)
その他 文字列関連はlifetimeを意識しないと使えないの で初心者にはハードモード。数値計算系からはじ めるのがおすすめ。 Windowsのセットアップはやや面倒だけど、 GitHub Actionsでビルド済みのバイナリを配布し たりできるはず(調査中) CRANにはすでにextendrを使っているパッケージ も存在する
まとめ
まとめ extendrを使うとマクロの魔術でRustの関数から Rの関数を生成してくれる。 関数の引数の対応づけはRcppやcpp11と同じノ リ。慣れている人はわりとすぐに使えるはず。 ちなみに、今回はすべてRustのデータ型に変換 するタイプだったが、SEXPのまま扱うことも できる(ここはよく理解できていない) フィードバックお待ちしています!
r-wakalangにrustチャンネルをつくり ました
References extendr: https://github.com/extendr/extendr extendrのロゴはCC-BY-SA 4.0ライセンスで配布 されています: https://github.com/extendr/artwork.