Rの拡張を書く (R 2.15.2)

179
R の拡張を書く Version 2.15.2 R Core Team

description

このPDFファイルは2013年3月下旬にリリースしたWriting R Extensions 2.15.2を日本語に翻訳したドキュメントである。10年以上前の2.1.0の頃から更新されていない状態であったため、本ドキュメントを作成した。

Transcript of Rの拡張を書く (R 2.15.2)

Page 1: Rの拡張を書く (R 2.15.2)

Rの拡張を書くVersion 2.15.2

R Core Team

Page 2: Rの拡張を書く (R 2.15.2)

Permission is granted to make and distribute verbatim copies of this manual provided thecopyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the con-ditions for verbatim copying, provided that the entire resulting derived work is distributedunder the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another lan-guage, under the above conditions for modified versions, except that this permission noticemay be stated in a translation approved by the R Core Team.

Copyright c⃝ 1999–2012 R Core Team

ISBN 3-900051-11-9

日本語訳注:このドキュメントの日本語訳は、英語原文と全く同じ条件の下で自由に配布、利用、

修正可能である。Rの開発の早さから、こうした文章の日本語訳は常に"旧式化"していること

をお断りしておく。翻訳の妥当さについては保証しない。これらの理由から、Rの最新バージョンに付属する文章を適宜参照していただきたい。なお、本ドキュメントはTwitter ID:@ito yanが作成した。

Page 3: Rの拡張を書く (R 2.15.2)

i

Table of Contents

謝辞 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1 Rのパッケージを作る . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.1 パッケージの構造 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.1.1 DESCRIPTIONファイル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.1.2 INDEXファイル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101.1.3 パッケージのサブディレクトリ . . . . . . . . . . . . . . . . . . . . . . . . . . . 111.1.4 パッケージバンドル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151.1.5 パッケージ中のデータ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151.1.6 パッケージ中の非Rスクリプト . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1.2 コンフィギュアとクリーンアップ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161.2.1 Makevarsを使う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

1.2.1.1 OpenMPのサポート . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231.2.1.2 pthreadsを使う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241.2.1.3 サブディレクトリでのコンパイル . . . . . . . . . . . . . . . . . . . . 25

1.2.2 コンフィギュアの例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251.2.3 F95のコードを使う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

1.3 パッケージのチェックとビルド . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281.3.1 パッケージのチェック . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291.3.2 パッケージの tar書庫をビルドする . . . . . . . . . . . . . . . . . . . . . . . . 321.3.3 バイナリパッケージをビルドする . . . . . . . . . . . . . . . . . . . . . . . . . 34

1.4 パッケージのビニェットを書く . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351.4.1 エンコーディングとビニェット . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

1.5 CRANにパッケージを提出する . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381.5.1 PDFのサイズ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401.5.2 パッケージの計時 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411.5.3 Windowsの外部ソフトウェア . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

1.6 パッケージの名前空間 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411.6.1 インポートとエクスポートの指定 . . . . . . . . . . . . . . . . . . . . . . . . . 421.6.2 S3メソッドの登録 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431.6.3 ロードフック . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441.6.4 useDynLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441.6.5 例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461.6.6 要約 – 既存のパッケージの変換 . . . . . . . . . . . . . . . . . . . . . . . . . . . 471.6.7 S4クラスとメソッドの名前空間 . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

1.7 移植可能なパッケージを書く . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491.7.1 エンコーディングの問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511.7.2 バイナリの配布 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

1.8 診断メッセージ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521.9 国際化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

1.9.1 Cレベルのメッセージ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541.9.2 Rのメッセージ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541.9.3 翻訳の設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

Page 4: Rの拡張を書く (R 2.15.2)

ii

1.9.4 Makefileのサポート . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551.10 CITATIONファイル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561.11 パッケージタイプ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

1.11.1 フロントエンド . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571.12 サービス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

2 Rのドキュメントを書く . . . . . . . . . . . . . . . . . . . . . . . . . 582.1 Rd書式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

2.1.1 関数のドキュメント化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592.1.2 データセットのドキュメント化 . . . . . . . . . . . . . . . . . . . . . . . . . . . 642.1.3 S4クラスとメソッドのドキュメント化 . . . . . . . . . . . . . . . . . . . . 652.1.4 パッケージのドキュメント化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

2.2 セクショニング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662.3 テキストを目立たせる . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 672.4 リストと表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682.5 相互参照 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692.6 数学 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702.7 図 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712.8 挿入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712.9 索引 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 722.10 プラットフォーム固有の文書 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 722.11 条件付きテキスト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732.12 動的なページ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732.13 ユーザ定義のマクロ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 742.14 エンコーディング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752.15 Rd書式の処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 762.16 Rdファイルの編集 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

3 Rコードの整理とプロファイリング . . . . . . . . . . . . . . 773.1 Rコードの整理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773.2 速度のためにRコードを整理する . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773.3 メモリ使用量のためにRコードを整理する . . . . . . . . . . . . . . . . . . . . . 79

3.3.1 Rprofのメモリ統計値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803.3.2 メモリ割り当ての追跡 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803.3.3 オブジェクトのコピーの追跡 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

3.4 コンパイル済みコードの整理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813.4.1 Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

3.4.1.1 sprof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813.4.1.2 oprofile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

3.4.2 Solaris . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 833.4.3 Mac OS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

Page 5: Rの拡張を書く (R 2.15.2)

iii

4 デバッグ作業 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844.1 ブラウジング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844.2 Rコードのデバッグ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854.3 gctortureと valgrindを使う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

4.3.1 gctortureを使う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894.3.2 valgrindを使う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

4.4 コンパイル済みコードのデバッグ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 924.4.1 動的にロードされたコードでエントリポイントを見つける . . 934.4.2 デバッグ中にRオブジェクトを検査する . . . . . . . . . . . . . . . . . . 94

5 システムと他言語間のインタフェース . . . . . . . . . . . . 965.1 オペレーティングシステムへのアクセス . . . . . . . . . . . . . . . . . . . . . . . . 965.2 インタフェース関数.Cと.Fortran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965.3 dyn.loadと dyn.unload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 985.4 ネイティブルーチンの登録 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

5.4.1 速度の考慮 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1025.4.2 他のパッケージ内のネイティブルーチンへのリンク . . . . . . . 103

5.5 共有オブジェクトの作成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1045.6 C++コードとのインタフェース . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055.7 Fortran I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1075.8 他のパッケージへのリンク . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

5.8.1 Unix系 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1085.8.2 Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

5.9 CでRのオブジェクトを扱う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1105.9.1 ガーベージコレクションの影響を扱う . . . . . . . . . . . . . . . . . . . . 1115.9.2 ストレージの割り当て . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1135.9.3 Rの型の詳細 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1135.9.4 属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1145.9.5 クラス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1165.9.6 リストを扱う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1175.9.7 文字データを扱う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1175.9.8 変数の発見と設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1185.9.9 いくつかの便利な関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

5.9.9.1 半内部の便利な関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195.9.10 名前付きオブジェクトとコピー . . . . . . . . . . . . . . . . . . . . . . . . . 119

5.10 インタフェース関数.Callと.External . . . . . . . . . . . . . . . . . . . . . . 1205.10.1 .Callの呼び出し . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1205.10.2 .Externalの呼び出し . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225.10.3 欠損値と特殊値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123

5.11 CからRの式を評価する . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1245.11.1 ゼロ点を見つける . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1265.11.2 数値微分の計算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

5.12 CからRのコードを構文解析する . . . . . . . . . . . . . . . . . . . . . . . . . . . 1305.12.1 ソース参照へのアクセス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

5.13 外部ポインタと弱参照 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1325.13.1 例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

5.14 ベクトルアクセサ関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1345.15 文字エンコーディングの問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

Page 6: Rの拡張を書く (R 2.15.2)

iv

6 The R API: Cコードのエントリポイント . . . . . . 1366.1 メモリ割り当て . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

6.1.1 一時的な記憶領域の割り当て . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1376.1.2 ユーザに制御されたメモリ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

6.2 エラー処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1386.2.1 FORTRANからのエラー処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

6.3 乱数生成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1386.4 欠損値と IEEE特殊値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1396.5 印字 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

6.5.1 FORTRANからの印字 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1406.6 FORTRANから Cを呼ぶこととその逆 . . . . . . . . . . . . . . . . . . . . . . . 1406.7 数値解析サブルーチン . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

6.7.1 分布関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1416.7.2 数学関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1426.7.3 数値ユーティリティ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1436.7.4 数学定数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

6.8 最適化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1456.9 積分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1466.10 ユーティリティ関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1476.11 再エンコーディング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1496.12 割り込み許可 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1496.13 プラットフォームとバージョン情報 . . . . . . . . . . . . . . . . . . . . . . . . . . 1506.14 C言語の関数のインライン化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1506.15 可視性の制御 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1516.16 自身の Cコード内でこれらの関数を使う . . . . . . . . . . . . . . . . . . . . . 1516.17 ヘッダファイルの構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

7 総称的関数とメソッド . . . . . . . . . . . . . . . . . . . . . . . . . . 1547.1 新しいジェネリクスを加える . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155

8 GUIと他のフロントエンドをRと結びつける . . . 1568.1 Unix系でRを組み込む . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

8.1.1 Rライブラリに対するコンパイル . . . . . . . . . . . . . . . . . . . . . . . . 1588.1.2 Rのコールバックの設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1588.1.3 シンボルの登録 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1618.1.4 イベントループのかみ合わせ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1628.1.5 スレッドの問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

8.2 WindowsでRを組み込む . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1638.2.1 (D)COMを使う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1638.2.2 直接R.dllを呼び出す . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1648.2.3 R HOMEを見つける . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167

関数と変数の索引 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

概念の索引 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

Page 7: Rの拡張を書く (R 2.15.2)

謝辞 1

謝辞

(.Call and .Externalの使い方に関する最初の草稿を書いた)Saikat DebRoyと (C++とのインタフェースに関する情報を提供してくれた)Adrian Traplettiの貢献に大いに感謝する。

Page 8: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 2

1 Rのパッケージを作る

パッケージはオプションのコード、データ、ドキュメントを必要に応じてロードするメカニズ

ムを提供する。R自身はおよそ 30のパッケージを含んでいる。

以下では、lib.loc 引数を含め、library()について知っているものと仮定する。また、

R CMD INSTALLの効用について基本的な知識を持っているものと仮定する。もし知識を持って

いないようであれば、読み進める前にRの以下のヘルプのページを見ておくこと。

?library

?INSTALL

計算環境については、いくつかのツールを仮定する。“R Installation and Administration”は何が必要であるかということについて記述している。Unix系の大部分のツールについてはデフォルトで用意しているであろうが、Microsoft Windowsは注意深いセットアップを求めてくるかもしれない。

いったんソースパッケージが作られると、R CMD INSTALLというコマンドによってパッケー

ジはインストールされる。

他の拡張方法についてはサポートしない (ただし、稀である): See Section 1.11 [パッケージタイプ], page 57 。

専門用語に関する注釈でこの導入を終える。これはマニュアルを読む手助けとなるであろ

う。また、助けを求めるときに、正確に概念を記述する際にも役立つであろう。

パッケージとは、Rを拡張するファイルのディレクトリである。これはソースパッケージ(パッケージのマスタファイル)か、ソースパッケージのファイルを含む tar書庫、あるいはソースパッケージで R CMD INSTALLを走らせた結果インストールされたパッケージのいずれ

かを指す。いくつかのプラットフォームにおいては、ソースからインストールするというよ

りも、解凍可能なインストール済パッケージを含む zipファイルあるいは tar書庫を指すバイナリパッケージといったものがある。

パッケージはライブラリではない 1。ライブラリは Rのドキュメントにおいては、2つの意味で使われている。1つ目はパッケージがインストールされたディレクトリという意味である。e.g. /usr/lib/R/library: その意味で、ディレクトリはライブラリディレクトリあるいは ライブラリツリーとして言及される (ライブラリはそれ自身がディレクトリを持つ、パッケージを含んだディレクトリであるため)。2つ目の意味はオペレーティングシステムによって共有ライブラリ、静的ライブラリ、あるいは (特にWindows上の)2つ目の Lが ‘library’を略したものであるDLLとして使用されたというものである。インストールされたパッケージは、大部分の Unix系の環境では共有オブジェクトとして知られるコンパイルされたコード、Windows上ではDLLを含んでいる (かつてはUnix系の環境では共有ライブラリと呼ばれていた)。パッケージがリンクするコンパイルされたコードの集合である共有ライブラリ (MaxOS X上では動的ライブラリ) のコンセプトは、あるプラットフォームにおけるR自身のために利用されている。

ソースパッケージについては、明確に定義された操作がたくさんある。もっともあ

りふれたものはインストールで、ソースパッケージを受け取り、R CMD INSTALLまたは

install.packagesを利用してパッケージをライブラリに組み込むということがある。異

なったコンセプトとしては、ソースパッケージはビルドできるということがある。これは、

ソースディレクトリにあるビニェットから PDFドキュメントを作り出すといったことを含

1 しかし、これは一般的な誤用である。Sに由来する、Rパッケージと類似したものについて、正式にはライブラリセクション、後にチャプターとして知られており、大体ライブラリとして言及されている

Page 9: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 3

め、ソースディレクトリを取り込み、いつでも配布できるような tar書庫を作成することに関与する。ソースパッケージ (ほとんどの場合 tar書庫形式)はインストールテストがされたときと、(中に含まれる例を含め)テストされたときに、チェックされることがある。また、パッケージの内容については、一貫性と移植性のため、さまざまな方法でテストされる。

コンパイルはパッケージに対しては、正しい用語とはいえない。CやC++、あるいはFortranのコードを含むようなソースパッケージをインストールすることは、コードをコンパイルす

るということに関与する。R 2.13.0以降は、パッケージでR コードを (‘バイト’)コンパイルできる可能性がある (コンパイラパッケージの機構を利用する): 将来的には、パッケージをコンパイルするときに、これは定期的に行われる可能性があり、将来的にはパッケージの Rコードをコンパイルする意味になるかもしれない。

インストールされたパッケージを library()を利用してロードすることについて話題にす

ることについて、かつては曖昧さは無かったが、パッケージ名前空間の出現以来、はっきり

としなくなった: パッケージの名前空間をロードすること、それからパッケージをアタッチしてサーチパス上でパッケージを見えるようにすることについて、今ではしばしば話をするよ

うになった。library関数は両方のステップについて機能するが、パッケージの名前空間につ

いては、パッケージがアタッチされることなくロードされる (例えば、splines::nsのような呼び出しによる)。

コードやデータの遅延読み込みのオプションについては、何箇所かで触れられている。イ

ンストールの一部にあり、Rコード (R2.14.0以降) はいつでも選択されるが、データは任意である。インストールの際にパッケージのRオブジェクトが作成され、インストールされた‘ R’ディレクトリ中にあるデータベースに貯められ、セッションに初めてロードされるときにそのような仕組みが使われている。これによって、Rセッションの実行速度が向上し、(仮想)メモリの使用量が減る。

1.1 パッケージの構造

Rパッケージのソースは、DESCRIPTIONファイルを含むサブディレクトリ、R、data、demo、

exec、inst、man、po、srcと testsを含むサブディレクトリ群から構成されている (いくつかはパッケージ中になくてもよいが、空であってはいけないものもある)。パッケージのサブディレクトリは INDEX、NAMESPACE、configure、cleanup、LICENSE、LICENCEと NEWSも含

んでいるだろう。他の INSTALL (一般的なインストール手順ではないときのため)、READMEあ

るいは ChangeLogはRによって無視されるが、エンドユーザにとっては役立つかもしれない。

具体的に挙げられている場合を除き 2、パッケージはUnixスタイルの ‘隠し’ファイル/ディレクトリを含むべきではない (つまり、名前がドットで始まるもののことである)。

DESCRIPTIONと INDEXファイルは以下のサブセクションで説明されている。NAMESPACEファ

イルは、Section 1.6 [パッケージの名前空間], page 41の項目で説明されている。

オプションファイルの configureと cleanupは (Bourneシェル)スクリプトであり、それぞれUnix系の環境で、インストールの前と (--cleanというオプションが与えられたという条件で)インストールの後で実行されるものである。Section 1.2 [コンフィギュアとクリーンアップ], page 16を見よ。Windowsにおける同様のものは、configure.win and cleanup.winで

ある。

オプションファイル LICENSE/LICENCEはパッケージへのライセンスのコピーを含んでいる。配布する source にライセンスファイルを含めるのは自由であると感じるはずであろうが、一方で、GNU COPYINGあるいは COPYING.LIBファイルのもう一つのコピーを installする

2 現時点では、最上位層のファイル.Rbuildignoreと.Rinstignore、そして vignettes/.install_extras。

Page 10: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 4

準備は遠慮していだだき、http://www.r-project.org/Licenses/と Rディストリビューション (share/licensesディレクトリ内部にある)に含まれたコピーについて言及してほしい。LICENSE あるいは LICENCE という名前がついたファイルがインストールされることにな

るので、これらの名前を標準的なライセンスファイルの名前に用いてはならない。

GNUプロジェクトにおける、NEWSとChangeLogファイルに対する規則については、http://

www.gnu.org/prep/standards/standards.html#Documentationを見よ。

パッケージのサブディレクトリについては、パッケージと同じ名前が与えられるべきであ

る。特定のファイルシステム (例えばWindowsとMax OSの初期状態)においては大文字と小文字を区別しないことから、移植性を維持するため、大文字と小文字の違いでパッケージ

を区別しないよう強く推奨する。例えば、fooと名前の付いたパッケージを持っているのであ

れば、Fooという名前のパッケージを作ってはならない。

ファイル名がファイルシステムと、サポートするオペレーティングシステムにおいて妥当

であることを確実にするために、ASCII制御文字は ‘"’、‘*’、‘:’、‘/’、‘<’、‘>’、‘?’、‘\’と ‘|’と同様にファイル名に用いることは認められていない。加えて、ファイル名で、小文字に変換し

て、あり得る拡張子を取り除いたときに、‘con’、‘prn’、‘aux’、‘clock$’、‘nul’、‘com1’から‘com9’、‘lpt1’から ‘lpt9’を用いているものも拒否の対象となる (例えば ‘lpt5.foo.bar’)。また、同じディレクトリのファイル名は大文字小文字が違うだけのファイル名があってはならない

(直前の段落を見よ)。さらに ‘.Rd’のファイル名はURLに使われるかもしれないので、ASCII

とし、%を含んではならない。移植性の最大化のため、ファイル名はすでに除外されていない

文字であるASCII文字だけを含むようにする (つまり、A-Za-z0-9._!#$%&+,;=@^(){}’[] —多くのユーティリティではファイルパスの空白は受け入れられないので、空白は除外してい

る):英語に使われないアルファベット文字はすべてのロケールにおいてサポートされることは保証されない。シェルのメタ文字 ((){}’[]$)を避けるのはよい習慣になるであろう。

可能であれば、ソースパッケージはバイナリ実行形式ファイルを含むべきではない:それらは移植性がなく、条件に適したアーキテクチャにおいては、セキュリティリスクになる。R

CMD checkはパッケージのトップレベルにある BinaryFilesというファイルの一覧 (1行につき 1つのファイルパス)にない限り、それらのファイル 3について警告を行う。CRANはリストにないものについて、バイナリファイルを含む提出を今後受け入れなくなることに注意。Rの package.skeletonという関数は、新しいパッケージを作成することに役立つ可能性があ

る。詳しくは関数のヘルプのページを参照せよ。

1.1.1 DESCRIPTIONファイル

DESCRIPTIONファイルはパッケージに関する基本的な情報について、以下のようなフォーマッ

トで含んでいる:

3 偽陽性はありうるが、これまでは少数である

Page 11: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 5� �Package: pkgname

Version: 0.5-1

Date: 2004-01-01

Title: My First Collection of Functions

Authors@R: c(person("Joe", "Developer", role = c("aut", "cre"),

email = "[email protected]"),

person("Pat", "Developer", role = "aut"),

person("A.", "User", role = "ctb",

email = "[email protected]"))

Author: Joe Developer and Pat Developer, with contributions from A. User

Maintainer: Joe Developer <[email protected]>

Depends: R (>= 1.8.0), nlme

Suggests: MASS

Description: A short (one paragraph) description of what

the package does and why it may be useful.

License: GPL (>= 2)

URL: http://www.r-project.org, http://www.another.url

BugReports: http://pkgname.bugtracker.url 形式は ‘Debian Control File’のそれである (‘read.dcf’のヘルプと http://www.debian.

org/doc/debian-policy/ch-controlfields.htmlを見よ: R は UTF-8 のエンコーディングを要求しない)。継続行 (例えば、1行よりも長い記述)は空白、あるいはタブから始まる。‘Package’, ‘Version’, ‘License’,‘Description’, ‘Title’, ‘Author’, and ‘Maintainer’のフィールドは必須で、他のフィールドはすべて任意である。R 2.14.0以降では、‘Author’ and‘Maintainer’の項目は ‘Authors@R’から自動生成することができ、後者が提供されている場合、前者は除去するべきである (それとパッケージは R (>= 2.14)に依存する。詳しくは以下

を見よ): しかしながら、それらがASCII文字でない場合、提供することを推奨する。

移植性の最大化のため、DESCRIPTIONファイルの全体は ASCIIで書かれるべきである —もし、それが可能でなければ、‘Encoding’フィールドを含めなければならない (以下を見よ)。

必須の ‘Package’フィールドはパッケージ名を与える。フィールドには文字、数値とドットのみを含み、少なくとも 2文字以上であり、文字で始まり、かつドットで終わってはならないようにするべきである。

必須の ‘Version’フィールドはパッケージのバージョンを与える。これは少なくとも 2つ(通常 3つ)の非負の整数の列で、区切り文字が ‘.’ または ‘-’ である列である。標準形は以下のような例に見られるもので、‘0.01’ あるいは ‘0.01.0’といったバージョンは ‘0.1-0’として扱われる。

必須の ‘License’フィールドは標準化された書式によって、パッケージのライセンスについて明確に記述するべきである。選択肢は縦線によって示されている。個々の仕様は次のど

れかである。

• “標準的な”短い仕様の一つ

GPL-2 GPL-3 LGPL-2 LGPL-2.1 LGPL-3 AGPL-3 Artistic-1.0 Artistic-2.0

http://www.r-project.org/Licenses/を介して利用可能となっており、そして、Rソースまたはホームディレクトリのサブディレクトリのshare/licensesに含まれている。

• フリーあるいはオープンソースのソフトウェアの短縮された名前 (FOSS、例えばhttp://

en.wikipedia.org/wiki/FOSS)で Rのソースあるいはホームディレクトリの中にあるshare/licenses/license.dbというライセンスデータベースの中に含まれていることで

ライセンスしており、おそらくは (バージョン管理されたライセンスに対しては)‘(op v)’という形式のバージョン制限が続いているもの。opは比較演算子の ‘<’、‘<=’、‘>’、‘>=’、‘==’あるいは ‘!=’であり、バージョンを特定する v(‘.’によって非負の整数が区切られてい

Page 12: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 6

る文字列)はおそらく ‘,’によって結合されている (下の例を見よ)。バージョン管理されたライセンスに対しては、名前に続くバージョンで特定すること、あるいは存在している

省略形とバージョンを ‘-’を結合することもできる。さらに、フリー (http://www.fsf.org/licenses/license-list.htmlを見よ)あるいはオープンソフトウェア (http://www.opensource.org/licenses/bsd-license.phpを見よ)は必要があれば、データベースに追加されることもある。

• ‘file LICENSE’あるいは ‘file LICENCE’という文字列の 1つで、パッケージ (ソースあるいはインストール)のトップレベルにある LICENSEあるいは LICENCEと名づけられたファ

イルについてのことについて触れたもの。

• 配布に関する制限がないこと、(著作権法を含め)関連法規で課された制約以外に使用に制限がないということを意味する ‘Unlimited’という文字列

もし、パッケージが基となる FOSSライセンス (例えば、帰属条項を含む GPL-3あるいは AGPL-3 を使用しているとき) を拡張してライセンスしているのであれば、その拡張はLICENSEファイル (あるいは LICENCE)に置かれるべきであり、‘+ file LICENSE’という文字列 (あるいは ‘+ file LICENCE’のそれぞれに)を対応する個々のライセンスの仕様に沿って付けられるべきである。

標準化された仕様の例は以下のものがある。

License: GPL-2

License: GPL (>= 2) | BSD

License: LGPL (>= 2.0, < 3) | Mozilla Public License

License: GPL-2 | file LICENCE

License: Artistic-1.0 | AGPL-3 + file LICENSE

“Public domain”は法域によっては認知されていないものであることから、妥当なライセンスでないということについては、特に注意していただきたい。

ライセンスに関する情報を含めることは重要である。さもなければ、パッケージのコピー

を他人が再配布することすら合法的にならないかもしれない。‘License’フィールドは著作権情報に利用してはならない: 必要であれば、‘Copyright’フィールドを利用せよ。

選んだライセンスについては、パッケージの依存するもの (システム依存のものを含めて)についてもカバーすることを確かにしてほしい: 特に重要なのは依存するようなものの使用に関するすべての制限について、DESCRIPTIONファイルを読む人に明確にすることである。

必須の ‘Description’フィールドは、パッケージが何をするかという包括的な記述を与える。いくつかの (完全な)文を使えるが、1段落のみに限られる。

必須の ‘Title’フィールドは、パッケージについての短い記述である。いくつかのパッケージ一覧には、65文字でタイトルを切り捨てるものがある。文字は大文字にする必要があり、マークアップを使用せず、継続行を持たず、ピリオドで終わってはならない。

必須の ‘Author’フィールドは、誰がパッケージを書いたかということを表している。人間の読者を対象として意図されたプレーンテキストのフィールドであり、すべての自動的な処

理 (すべての貢献者一覧の Eメールアドレスを抽出するなど: ‘Authors@R’を使うため)は対象としていない。すべての重要な貢献者については含められているということに留意するこ

と: もし、srcディレクトリにある他の人の作成物に対するRラッパーを書いた場合、単独の作者にならない (そして恐らく主要な作者にすらならない)。

必須の ‘Maintainer’フィールドは、(バグレポートを送るためなどの理由で)山括弧に囲まれた有効な (RFC 2822)単名の名前からなる Eメールアドレスを与える。ピリオドやコンマで終わってはならない。公開するパッケージには personのメールアドレスを載せるべきであ

Page 13: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 7

り、メーリングリストや、企業体のメールではない: 現在も、パッケージの寿命の後も有効なメールアドレスであるようにせよ。

もし、適切な ‘Authors@R’フィールドが与えられていれば、‘Author’と ‘Maintainer’のフィールドは省くこともできる (R 2.14.0以降)。‘Authors@R’フィールドは、適切なRコードによって、(特にそれらの正確な役割を明確にする)“authors”パッケージの正確で、機械が読める記述を与えるのに使われることがある。役割は作者全員に対する ‘"aut"’ (author)、パッケージを維持する人に対する ‘"cre"’ (creator)、特に貢献した人に対する ‘"ctb"’ (contributor)がある。さらなる情報については、?personを見よ。初期状態では、役割が何もないことが

仮定されていることに注意せよ。自動生成されたパッケージの引用情報は次の仕様を利用し

ている: R 2.14.0かそれ以降では、‘Author’と ‘Maintainer’のフィールドは、ビルドやインストールの際に必要であれば、Rから自動生成される。

いくつかの任意のフィールドは logical values を取る。これらについては、‘yes’、‘true’、‘no’あるいは ‘false’によって明確になる:大文字になった値も受理される。

‘Date’フィールドは、現在のパッケージのバージョンがリリースされた日を与える。ISO8601の標準に従った、yyyy-mm-ddという形式を利用することを強く推奨する。

‘Depends’フィールドは、そのパッケージが依存しているパッケージの名前をコンマ区切りで一覧にしたものを与える。パッケージ名は丸括弧に書かれたコメントが任意に続いている

かもしれない。コメントは比較演算子、空白と有効なバージョン番号を含むべきである。ま

た、もしパッケージが特定のRのバージョンに依存しているというのであれば、‘R’という特別なパッケージ名を用いることもできる— 例えば、もしパッケージがR 2.11.0か、それ以降でしか動かない場合、‘Depends’フィールドには ‘R (>= 2.11.0)’を含める必要がある。また、R-develあるいはR-patchedに対し、特定の SVNの版を要求することもできる。例えば、‘R(>= 2.14.0), R (>= r56550)’は、(リリースされたバージョン 2.14.0も含めて)2011年 7月下旬のR-develよりも後のバージョンを必要とする。libraryとRパッケージのチェック機構はこのフィールドを利用している: ゆえに、不適切な文法の利用や、必要とされる他のパッケージに対するコメントである ‘Depends’フィールドの誤使用はエラーとなる。他の依存 (Rシステムの外部)については、‘SystemRequirements’フィールドに一覧にされるべきで、場合によっては、READMEファイルに詳しく説明されるかもしれない。R INSTALLという機構は、

インストールされようとしているパッケージに対し、使われているRのバージョンが十分最近のものであるか、現在のパッケージの前に明示されたパッケージが加えられるか (バージョン要件を確認した後)ということを、libraryが呼ばれたときと、インストールの間に遅延読

み込みを準備しているときにチェックする。

パッケージ (あるいは ‘R’)は、‘Depends’に 1度より多く現れることもあるが、2.7.0以前の Rのバージョンにおいては、最初に出現したものしか使われない: 今ではほとんど見かけることはないだろうが。

バージョンを特定することなく Rの依存関係を宣言することは意味が無いし、baseについてもそうである: これはRパッケージと baseはいつでも利用可能だからである。

‘Imports’フィールドは、名前空間がインポートされる (NAMESPACEファイルに明記されている)が、アタッチされる必要がないパッケージを一覧にしている。‘::’と ‘:::’演算子によってアクセスされた名前空間が一覧にされているはずで、そうでなければ、‘Suggests’あるいは ‘Enhances’にある (下記参照)。理想的には、このフィールドが使われている標準的なパッケージをすべて含んでおり、S4を利用したパッケージを含んでいることが重要である (クラス定義が変化しうることと、DESCRIPTIONファイルはそれが起こった際にどのパッケージを

再インストールするかということを決める際に利用されるため)。‘Depends’フィールドに示されたパッケージは ‘Imports’フィールドにも示されるべきではない。バージョン要件は明記さ

Page 14: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 8

れることもあるが、名前空間がロードされたときにはチェックされない (その一方で、R CMD

checkを用いればチェックされる)。

‘Suggests’フィールドは ‘Depends’と同様の文法を利用し、必ずしも必要としないパッケージを一覧にしている。ここでは例、テストあるいはビニェット (see Section 1.4 [パッケージのビニェットを書く], page 35)でのみ使われるパッケージを含め、関数の本体でロードされるパッケージを含める。例えば、fooパッケージの例が、barパッケージのデータセットを利用していると仮定しよう。すなわち、すべての examples/tests/vignettesを実行させたいと思わない限り、barに fooを使わさせることが必ずしも必要でない: barを持つことは役に立つが、必ずしも必要ではない。バージョン要件は明記されることがあり、R CMD checkによって使用さ

れる。examples/tests/vignettesを走らせたいと思っているある人が推奨されているパッケージを利用できないかもしれない (利用しているプラットフォームでインストールをすることすら可能ではないかもしれない)ので、推奨されたパッケージの使用が if(require(pkgname))

によって条件付きにされているかということが役に立つということを明記しておく。

最後に ‘Enhances’フィールドは、手元のパッケージによって “enhanced”されたパッケージを一覧にしている。例えば、それらのパッケージからクラスのためにメソッドを提供する

こと、あるいはそれらのパッケージからオブジェクトを扱う手段を提供することが挙げられ

る (パッケージはR固有の日時時刻関数を好むのだけれども、パッケージは chron (http://CRAN.R-project.org/package=chron)から日時時刻オブジェクトを扱えるので、いくつかのパッケージには ‘Enhances: chron’というものがある。)。バージョン要件は明確にされることもあるが、現在では利用されていない。そのようなパッケージはパッケージをチェックする

ようなことを要求されない: それらを使用する任意のテストはパッケージが存在していることが条件となる。(テストで例えば他のパッケージのデータセットを使うのであれば、‘Suggests’にそのことを含め、‘Enhances’に含めてはならない。)

ルールの概要は以下の通りである。

• パッケージの名前空間で、library(pkgname)を用いてパッケージをロードすることだけに必要とされるものは ‘Imports’フィールドに記入し、‘Depends’に記入してはならない。

• library(pkgname)を用いてパッケージをうまくロードするためにアタッチされる必要

があるパッケージは、‘Depends’フィールドのみに記載されていなければならない。

• パッケージに対し、R CMD checkをうまく走らせるのに必要 4 とされるすべてのパッ

ケージは ‘Depends’、‘Suggests’、あるいは ‘Imports’のどれかひとつに記載されていなければならない。条件付きで例やテストを実行する際に使われるパッケージ (例えば、if(require(pkgname))を用いて)は ‘Suggests’あるいは ‘Enhances’に記載されるべきである。(これにより、チェックするものは完全なチェックをするのに必要とされるすべてのパッケージがインストールされていることを確実にすることが可能になる。)

特に、例のためのデータやビニェット “だけ”を提供する大きなパッケージは、無駄のないインストールを可能にするため、‘Depends’よりも ‘Suggests’に入れるべきである。

パッケージをロードするときに libraryによって ‘Depends’フィールドのバージョン依存関係は利用され、install.packagesは、‘Imports’と (dependencies = TRUEの場合に

は)‘Suggests’フィールドのバージョンを確認する。

4 これは data(theirdata, package = "somepkg")という呼び出しから得られるデータと同様に libraryとrequireに直接呼ばれるすべてのパッケージも含む: R CMD checkはこれらのすべてについて警告を発する。しかし、発見できないようなわずかな利用がある: 例えば、もしパッケージ Aがパッケージ Bを利用し、パッケージ Bを示唆あるいは高めるようなパッケージ Cを使うパッケージ Bの機能を利用する場合、パッケージAのためにパッケージ Cを ‘Suggests’の一覧に入れる必要がある。含められたファイルでの宣言されていない使用は報告されないし、‘Enhances’に記載されたパッケージの無条件の利用も報告されない。

Page 15: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 9

これらのフィールドに書かれる情報は完全、かつ正確であることがますます重要となって

きている: 例えばそれは更新されたパッケージにどのパッケージが依存しているかということや、どのパッケージを平行してインストールしても安全であるかという計算するために利

用される。

‘URL’フィールドは、コンマあるいは空白で区切られた URLの一覧を与える。例えば、作

者のホームページや、ソフトウェアに関する追加資料があるページが見つけられるようにす

るためのものである。これらの URLは CRANのパッケージ一覧では、機能するハイパーリン

クに変換される。

‘BugReports’フィールドは、パッケージに関するバグ報告を提出する 1つだけからなるURLを含めることがある。パッケージを維持する人に Eメールを送る代わりに、この URLは

bug.reportsで利用される。

Baseと推奨されたパッケージ (例えば、Rのソース配布物に含まれているパッケージ、あるいは CRANから入手可能でかつRのすべてのバイナリ配布物に含めることが推奨されているパッケージ)は、‘Priority’というフィールドを持ち、‘base’ あるいは ‘recommended’のどちらかの値が入っている。このような優先度は他のパッケージで利用してはならない。

‘Collate’フィールドは、パッケージ中の Rコードのファイルがインストールで処理されるときの照合順序を制御する際に用いられる。初期設定では、‘C’ロケールに応じて照合が行われる。もしフィールドに値が存在するのであれば、照合仕様は (OS特有のサブディレクトリの可能性も考慮に入れて、Section 1.1.3 [パッケージのサブディレクトリ], page 11を参照せよ)空白文字で区切られた Rのサブディレクトリとの相対ファイルパスの一覧として、パッ

ケージ中のすべての Rコードのファイルを一覧にしなければならない。空白や引用符を含むパスは引用符で囲まれる必要がある。OS特有の照合フィールド (‘Collate.unix’あるいは‘Collate.windows’)が ‘Collate’に代わって用いられる。

‘LazyData’論理フィールドは、Rデータセットが遅延読み込みを使用するかどうかを制御する。‘LazyLoad’フィールドは、2.14.0以前のバージョンでは利用されていたが、今では無視される。

‘KeepSource’論理フィールドは、パッケージのコードが keep.source = TRUEあるいは

FALSEのどちらで供給されるかということを制御する。: keep.source = TRUEが常に選択さ

れることを意図されたあるパッケージでは例外的に必要とされることもある。

‘ByteCompile’論理フィールドは、パッケージのコードがインストールの際にバイトコンパイルされるかどうかを制御する。: 現在は初期設定ではしないようになっており、特にバイトコンパイルによって利益があることが知られているパッケージに対しては役に立つことが

あるだろう (バイトコンパイルは長時間かかる可能性があり、パッケージのインストール容量を増やす可能性がある)。

‘ZipData’論理フィールドは、自動のWindowsビルドがデータディレクトリを圧縮するかしないかを制御する: もしパッケージが圧縮されたデータのディレクトリと一緒に動作しないようであれば、‘no’を設定せよ。(他の値に設定することは非推奨であり、R 2.13.0からは利用されない: しかし、パッケージが Rの早い時期のバージョンの元でインストール可能であれば、まだフィールドは必要であるだろう。)

‘BuildVignettes’論理フィールドは、R CMD checkがビニェットをテストするのを防ぐの

ことと、ビニェットを R CMD buildによって再ビルドすることを止めるために、falseに設定することがある。これは例えば、パッケージのソースの一部ではないPDFが大きな図を必要とする場合など、例外的に使用されるべきである。

もし DESCRIPTIONのファイル全体がASCIIで書かれていない場合、エンコーディングを特

定する ‘Encoding’フィールドを含めるべきである。これは DESCRIPTIONのファイル自身と、

Page 16: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 10

Rと NAMESPACEのファイルのエンコーディング、および.Rdファイルのエンコーディングの初

期設定として用いられる。R CMD checkを走らせるとき、例はそのエンコーディングであるこ

とを仮定しており、CITATIONファイルのエンコーディングに用いられる。latin1、latin2、

および UTF-8という名前のエンコーディングのみが、移植性のあるものとして知られている。

(実際に必要でない限り、エンコーディングを特定してはならない: そのようにすることでパッケージの移植性が低くなってしまう。もしパッケージが特定のエンコーディングを持つので

あれば、そのエンコーディングを用いているロケールで R CMD buildなどを走らせるべきで

ある。)

‘OS_type’フィールドは、パッケージが意図されているOSを明記している。もしフィールドがあれば、それは unixあるいは windowsのどちらかにするべきであり、そのパッケージは

‘.Platform$OS.type’にその値を持つプラットフォームに限ってインストールされるということを示唆している。

‘Type’フィールドは、パッケージの種類を明記している。: see Section 1.11 [パッケージタイプ], page 57.

Note: パッケージ管理ツールによって加えられるので、‘Built’フィールドあるいは ‘Packaged’フィールドはあってはならない。

‘Classification/ACM’フィールド (the Association for Computing Machinery の theComputing Classification System を用いることによる,http://www.acm.org/class/)、‘Classification/JEL’フィールド (the Journal of Economic Literature ClassificationSystem, http: / / www . aeaweb . org / journal / jel_class_system . html)、あるいは‘Classification/MSC’フィールド (the Mathematics Subject Classification of the AmericanMathematical Society, http://www.ams.org/msc/)を用いたパッケージの内容に対して、主題の分類を追加することができる。主題の分類は、それぞれの分類コードに対してコンマ

で区切られたリストで与えられる。例えば、‘Classification/ACM: G.4, H.2.8, I.5.1’のようになる。

‘Language’フィールドはパッケージのドキュメントが英語でないときにそれを示すために用いられることを最後に述べておく: これは、現在 RFC 5646(http://tools.ietf.org/html/rfc5646, こちらも参照のこと http://en.wikipedia.org/wiki/IETF_language_tag)によって定義されているように、標準 (私的な利用でも、新しく決められた定義を適用除外されたものでもない)の IETF言語タグがコンマ区切りで一覧になったものである。すなわち、基本的に言語下位タグは ISO 639-1(http://en.wikipedia.org/wiki/ISO_639-1)の 2文字、あるいは ISO 639-3(http://en.wikipedia.org/wiki/ISO_639-3)にあるような 3文字の言語コードを使用せよ。

1.1.2 INDEXファイル

任意のファイルである INDEXはパッケージに含まれる十分に興味を引かれるオブジェクトに

ついて、その名前と説明を書いたものである (printメソッドのような関数は普段は明示的に呼ばれるものではないので、含められていない)。普通は、このファイルはなく、対応する情報はソースをインストールする時に、ドキュメントのソースから (tools::Rdindex()を使って)自動的に生成される。

パッケージに関してカスタマイズされた情報は、INDEXファイルを編集するというよりも、マニュアルの概要 (see Section 2.1.4 [パッケージのドキュメント化], page 66)、ビニェット (see Section 1.4 [パッケージのビニェットを書く], page 35)の両方、またはどちらか一方に加えておくことが望ましい。

Page 17: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 11

1.1.3 パッケージのサブディレクトリ

Rサブディレクトリは Rのコードのファイルのみを含んでいる。インストールされるコードファイルはASCII(大文字あるいは小文字)の文字あるいは数字で始まらなければならず、.R、

.S、.q、.r、あるいは.sという拡張子を 1つ持っている 5ものでなければならない。.Rとい

う拡張子は他のソフトウェアでは利用されていないように見受けられることから、我々はこ

の拡張子を利用することを推奨する。source()を用いることで、ファイルの内容を読むこと

が可能で、Rオブジェクトが割り当てることによって生成される。ファイル名と生成されるRオブジェクトとの間に何も関係がないことに注意。理想的には、Rコードのファイルは Rオブジェクトを直接割り当てるだけで、requireや optionsといった副作用を伴う関数は例

外なく呼び出してはならない。もしオブジェクトを生成するのに計算が必要となるのであれ

ば、計算ではパッケージ中の ‘earlier’というコード (‘Collate’フィールドを参照せよ)と、生成されたオブジェクトが名前空間のインポート以外で ‘Depends’パッケージに挙げられたパッケージに依存しないという条件で、‘Depends’パッケージの関数を加えて使うことができる。

2つの例外が許可されている: もしRサブディレクトリが sysdata.rdaというファイル (Rオブジェクトの保存されたイメージ: tools::resaveRdaFilesによって提案された適切な圧縮形式を利用してほしい)を含んでいる場合、これは 名前空間/パッケージ 環境に遅延読み込みされることになる – これはシステムデータセットに対し、dataを介してユーザがアクセ

ス可能になることを意図していないことを意味している。また、‘.in’で終わるファイルは、ディレクトリ R以下で、configureスクリプトに適切なファイルを生成することを可能にして

いる。

コードファイルでは、ASCII文字だけ (それとタブ、LFや CRなどの改行といった制御文字)が利用されるべきである。他の文字はコメントでは受け入れられるが、そうすると、コメントは例えばUTF-8ロケールの環境では読めなくなるかもしれない。オブジェクト中の非ASCII文字があると、通常 6はパッケージのインストール時に失敗する。引用符で囲まれた文

字列はどんなバイトでも許されるが、非-ASCII文字に対して\uxxxxというエスケープ文字

が使われるべきである 7。しかし、非ASCII文字列はいくつかのロケールでは使えないかも知

れないし、正しく表示されないかもしれない。

パッケージ中のさまざまなRの関数は初期化と片付けのために使われる。See Section 1.6.3[ロードフック], page 44。8

manサブディレクトリは R documentation (Rd)形式で書かれたパッケージ中のオブジェクトに対する文書ファイル (のみ)を含んでいる。文書のファイル名は、ASCII(小文字あるいは大文字の)文字あるいは数字から始まり、.Rd (初期設定)あるいは.rdという拡張子を持た

せなければならない。さらに、名前は ASCIIで ‘%’を含まないような、‘file://’という URL

5 .Sと.sの拡張子は本来は S(-PLUS)で書かれたコードに起因するが、一般にはアセンブラのコードに使われているものである。かつては暫定的に QPEと呼ばれていた拡張子.qが使われていた。

6 ‘C’ロケールで実装された OSでは当てはまる: Windowsの ‘C’ロケールの考えはWinAnsi文字セットを利用するというものである。

7 パッケージは R (>= 2.10)に依存している必要がある8 Rのバージョン 2.14.0以前では、名前空間のないパッケージでは.First.libと.Last.libという関数がこれらのタスクを処理していた。(現在の Rのバージョンではすべてのパッケージが名前空間を持っている。)古いパッケージの変換に役立てるため、ここに古いパッケージがどのように扱われていたかを載せておく: 慣習的にそれらの関数は zzz.Rと呼ばれるファイルの中にそのような関数を定義していた。もし、.First.libがパッケージ中に定義されているのであれば、パッケージがロード、取り付けされた後に、libnameと pkgname

の引数を伴って呼ばれていた。一般的な用途はコンパイルされたコードをロードするため、.First.lib内部にある library.dynamを呼び出すものであった: 他の用途には副作用を伴った関数呼び出しがあった。もし、パッケージ内部に.Last.libがあれば、取り外される直前にそれが (インストールされたパッケージの完全パスを引数に取った上で)呼ばれていた。

Page 18: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 12

において有効なものでなければならない 9。さらなる情報については、See Chapter 2 [Rのドキュメントを書く], page 58。パッケージ中のすべてのユーザレベルのオブジェクトは文書化されるべきであるということに注意; もしパッケージ pkgが “内部的な”利用のみのユーザレベルのオブジェクトを含んでいるのであれば、パッケージはそのようなオブジェクトのす

べての記載した pkg-internal.Rdというファイルを提供するべきであり、ユーザによって呼

ばれるものではないということを明確に述べるべきである。例えば例として、Rディストリビューション中の gridパッケージのソースを見よ。大規模に内部オブジェクトを利用するパッケージは、文書化する必要がない場合、それらの名前空間からオブジェクトを外部に出すべ

きではないということに注意 (see Section 1.6 [パッケージの名前空間], page 41)。

manに文書ファイルがないことで、インストールエラーが起きる可能性がある。

Rと manサブディレクトリは、unixや windowsといった、OS特有のサブディレクトリを含んでいることがある。

コンパイルされたコードのソースとヘッダは srcにあり、加えて、必要に応じて Makevars

あるいは Makefileというファイルが置かれている。R CMD INSTALLを用いてパッケージがイ

ンストールされたとき、makeはコンパイルを制御することと、Rにロードするための共有オブジェクトにリンクするために用いられる。これのために makeの変数とルールには初期値が

あり (Rが設定され、R_HOME/etcR_ARCH/Makeconfに記録されるときに決定される)、それぞれ.c、.ccあるいは.cpp、.f、.f90または.f95、.mと.mmあるいは.Mという拡張子で関連付

けられた、C、C++、FORTLAN 77、FORTLAN 9x10、Objective CとObjective C++11に対してサポートを提供している。ヘッダには.hという拡張子を使うことを推奨しており、C++12

と Fortran 9xのインクルードファイルにも利用を推奨している。(C++のファイルに対し、.C

の拡張子を使うことはもはやサポートされていない。)srcディレクトリにあるファイルは隠すべきではなく (ドットで始まるファイル)、Rのあるバージョンにおいては、隠しファイルは無視される。

1つのパッケージにすべてのこれらの言語を混ぜることは移植性がなく (そしてまったく可能がない場合がある)、C++と Fortran 9xの両方を用いることに対してサポートはしていない。R自身が Cと FORTRAN 77は一緒に利用し、Cと C++を混ぜることをしているため、幅広く成功しているということが分かっている。

もし書いているコードがプラットフォームに依存する必要があるならば、コードにはCかC++に使われるような特定の定義がある。すべてのWindowsビルド (64bitのものでさえも)においては ‘WIN32’が定義される: 64bitのWindowsビルドでは ‘WIN64’も定義され、Mac OSXでは、‘__APPLE__’と ‘__APPLE_CC__’が定義される。

初期設定のルールは src/Makevarsファイルにマクロ 13を設定することで微調整を行うこ

とができる。このメカニズムはパッケージ固有の src/Makefileに対する必要性を取り除くの

ほど十分一般的なものでなければならない。もし、そのようなファイルを配布するのであれ

ば、すべてのRのプラットフォームでそのファイルが全体的に十分に働くよう、かなりの注意

9 より厳密には、英語のアルファベットと数字、および ‘$ - _ . + ! ’ ( ) , ; = &’という記号を含めることができる。

10 Ratforはサポートされていない。もし Ratforのソースコードがあるならば、それを FORTLANへと変換する必要がある。FORTRAN 77(我々は大文字で書く) が唯一、すべてのプラットフォームでサポートしているものであるが、多くの場合 Fortran-95(我々はこれに対しタイトルケースを使う)もサポートしている。もし、Ratforソースファイルを出したいという場合、srcサブディレクトリにコードを入れ、メインのサブディレクトリに置かないようにしていただきたい。

11 特定のプラットフォームに置いては一方、あるいはどちらもサポートされていないかもしれない。12 いくらか人気がある.hppを使う方法は、移植性を保障できるものではない。13 POSIX用語では GNU makeによる ‘make variables’と呼ばれている。

Page 19: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 13

深さが必要とされる。もし仮にそれが任意のターゲットを持つのであれば、‘all’と名づけられた適切な最初のターゲットと、makeを走らせたことによって生成されたすべてのファイルを取

り除く (おそらく空の)‘clean’というターゲットを持つはずである (‘R CMD INSTALL --clean’と ‘R CMD INSTALL --preclean’によって使用される)。Windows上ではプラットフォーム特有のファイル名がある: src/Makevars.winは src/Makevarsに優先し、src/Makefile.win

を使われなければならない。makeプログラムには、makeファイルに改行を含む完全な最終行を必要とさせるものがある。

共有オブジェクトを作ること以外の目的で srcディレクトリを利用するパッケージもわ

ずかだがある (例えば、実行ファイルを作成するため)。そのようなパッケージには (Unix系の環境だけ、あるいはWindowsだけということを意図していない限り、)src/Makefileとsrc/Makefile.winというファイルがある。

とりわけ特別な場合のパッケージでは、srcディレクトリ内の共有オブジェクト/DLL以外にバイナリファイルを作るものがある。そのようなファイルは、R CMD INSTALL --libs-only

が複数のアーキテクチャを結合するために利用されることと、それが共有オブジェクト/DLLをコピーするだけであるということから、マルチアーキテクチャの設定ではインストールされ

ない。もしパッケージから他のバイナリ (例えば実行プログラム)をインストールしたいという場合、パッケージは共有オブジェクト/DLLをコピーするかわりに、インストールの一部で動作する src/install.libs.Rという srcのビルドディレクトリにRのスクリプトを提供するべきである。スクリプトは以下の変数を含む異なるRの環境で動作する: R_PACKAGE_NAME(パッケージの名前)、R_PACKAGE_SOURCE(パッケージのソースディレクトリへのパス)、R_PACKAGE_DIR(パッケージのインストール先ディレクトリへのパス)、R_ARCH(パスのアーキテクチャ依存部分)、SHLIB_EXT(共有オブジェクトの拡張子)、そして WINDOWS(TRUEはWindows上、FALSEは他の場所)。デフォルトの動作に近いものは、以下の src/install.libs.Rファイルを利用

して複製することができる:

files <- Sys.glob(paste("*", SHLIB_EXT, sep=’’))

libarch <- if (nzchar(R_ARCH)) paste(’libs’, R_ARCH, sep=’’) else ’libs’

dest <- file.path(R_PACKAGE_DIR, libarch)

dir.create(dest, recursive = TRUE, showWarnings = FALSE)

file.copy(files, dest, overwrite = TRUE)

dataサブディレクトリは、データファイルのためのものである: See Section 1.1.5 [パッケージ中のデータ], page 15

demoサブディレクトリは、パッケージのいくつかの機能性について実演する Rスクリプト (demo()を利用して走らせる)のためのディレクトリである。デモは対話式のものであるかもしれないし、自動的にチェックされるものでもないので、もしテストしたいということで

あれば、その達成のために testsディレクトリ中のコードを使うようにせよ。スクリプトの

ファイル名は (大文字あるいは小文字の)文字で始まり、.Rあるいは.rのどちらかの拡張子を

持たなければならない。もしそのようなファイルがあるのであれば、demoサブディレクトリ

には、各デモに対し 1行で、名前と、空白によって区切られた説明を与える 00Indexファイ

ルがある (この索引ファイルは自動的に生成することができないことに注意)。デモには指定されたエンコーディングはないため、ASCIIファイルにするべきである (see Section 1.7.1 [エンコーディングの問題], page 51)。

instサブディレクトリの内容は、再帰的にインストールディレクトリへとコピーされる。

instのサブディレクトリは、Rによって使用されるサブディレクトリ (現時点では R、data、

demo、exec、libs、man、help、htmlとMeta、そして初期のバージョンで利用していたlatex、

R-ex)の妨げになってはならない。instのコピーが起こるのは、srcがビルドされた後なので、

Page 20: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 14

srcの Makefileはインストールされるファイルを生成することができる。R 2.12.2以前では、ファイルはパッケージソースの権限を伴ってPOSIXプラットフォームにインストールされており、再帰が深くなりすぎないことを保証するために注意がとられていた: R CMD buildは適

切な調節を行う。インストールされたものからファイルを除外するために、ソースディレク

トリのトップレベルに.Rinstignoreという除外するパターンのリストを指定することができ

る。それらのパターンは Perlライクな正規表現であり (正確な詳細については、Rの regexp

のヘルプを参照すること)、ファイルとディレクトリのパスに対し、マッチさせる 14ものを 1行につき 1つ書く。例えば、doc/.*[.]png$は inst/docにある、すべての PNGファイルを(小文字の)拡張子に基づいて除外する。

INDEX、LICENSE/LICENCEとNEWSを除いて、パッケージのトップレベルにある情報ファイル

はインストールされないので、WindowsとMac OS Xのコンパイルされたパッケージのユーザには情報ファイルは知られない (そして tar書庫にR CMD INSTALLあるいはinstall.packages

を使う人には見られない)。そのため、エンドユーザに見てもらいたい情報ファイルは、inst

に含められるべきである。もし名前つきの例外が instで発生した場合は、instのバージョン

がインストールされたパッケージで見られるということに注意。

instに追加したいものの 1つに、citation関数に利用される CITATIONがあるかもしれ

ない。

testsサブディレクトリは、Rディストリビューションに付属している固有のテストに似た、追加的なパッケージ特有のテストコードのためのものである。テストコードは.Rファイ

ルから直接、あるいは.Rファイルに対応するファイルを生成するコードを含む.Rinファイル

のどちらかから提供することができる (例えば、パッケージ中のすべての関数オブジェクトを集め、変わった変数を伴ってそれらを呼ぶことによる)。.Rファイルを実行した結果は.Rout

ファイルに書き込まれる。もし.Rout.saveファイル 15に一致するものがあれば、.Routファ

イルと.Rout.saveファイルは、エラーを起こさず、違いを報告する形で比較される。tests

ディレクトリはチェックする領域にコピーされ、コピーされたものを作業用ディレクトリと

し、library(pkg_name)によって検査があると分かっている間、パッケージのコピーがインス

トールされていることを確かにするために R_LIBSが設定された上でテストは動作する。パッ

ケージ特有のテストは乱数シードを設定していない、普通の Rセッションで動作するので、乱数を利用するテストが再現可能な結果を得ようとするのであればシードを設定する必要が

ある (そして乱数を設定することは、すべての場合において、テストが動作する際に偶然の失敗を避けるために役に立つ)。

もし testsサブディレクトリが、pkg-Ex.Rout.saveというファイルを含んだ Examplesと

いうサブディレクトリを持つのであれば、後者がチェックされるときに、例を実行した出力

ファイルと比較される。

execサブディレクトリはパッケージが必要とする付加的な実行できるスクリプトを含んで

いることがあり、典型的なものはシェル、PerlあるいはTclといったインタプリタ型のスクリプトである。この機構は現在はごくわずかなパッケージのみが利用しているのみであり、ま

だ実験的なものである。注意:execの以下にあるファイルのみ (ディレクトリではない)がインストールされ (そしてドットで始まるファイル名は無視される)、それらはすべて POSIXプラットフォームにおいて、実行ファイルとして示されている (‘umask’によってモードは 775に

調節されている)。これはいくつかのプラットフォーム (Mac OS XとWindowsを含めて)が

14 Windowsでは大文字と小文字は区別しない。15 そのようなファイルを生成する最善の方法は、R CMD checkが上手くいった動作の結果から.Routをコピーすることである。もし、それとは別に生成したいということであれば、--vanilla --slaveというオプションと英語のメッセージを得るために LANGUAGE=enという環境変数を設定した上で Rを走らせよ。

Page 21: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 15

複数のアーキテクチャが同じインストールされたパッケージディレクトリを利用することを

サポートしているということから、実行可能なプログラムに対して適していないかもしれな

いことにも注意。

poサブディレクトリは現地語化に関連するファイルのために利用される: see Section 1.9[国際化], page 53。

1.1.4 パッケージバンドル

パッケージバンドルのサポートはR 2.11.0で廃止された。

1.1.5 パッケージ中のデータ

dataサブディレクトリは遅延読み込み、あるいは data()を用いることで使用可能となるデー

タファイルのためのディレクトリである。(その選択は DESCRIPTIONファイル中の ‘LazyData’フィールドによってされる: 初期設定ではそのようにしないことになっている。)これはパッケージが必要とする他のデータファイルに対して利用するべきではなく、そのようなファイ

ルに対しては、inst/extdataディレクトリを使用することが慣習になってきている。

データファイルは、拡張子によって 3つの種類のうちのどれであるかということが示される: プレーンな Rのコード (.Rあるいは.r)、テーブル (.tab、.txt、あるいは.csvである。

ファイルフォーマットについては?dataを参照せよ。そして.csvは標準的な 16CSV形式ではないことに注意)、あるいは save()イメージ (.RDataあるいは.rda)。ファイルは隠される (ドットで始まる名前を持つ)べきではない。データファイルはパッケージをロードする必要が無く利用できるようにするために、Rコードは “自給自足”であるべきで、パッケージから提供される追加の機能を利用するべきではない。

イメージ (拡張子は.RDataあるいは.rda)は、イメージを作成する際に使われたパッケージの名前空間への参照が含まれていることがある。データファイルにそのような参照がない

ことが望ましく、どのような場合においても、Dependsと Importsのフィールドに記載され

たパッケージになければならならず、そうでなければ、パッケージはインストールできなく

なるかもしれない。そのような参照を調べるには、普通のRセッションにイメージをロードし、loadedNamespaces()の出力を見よ。

もしデータファイルが大きく、かつ ‘LazyData’を用いていないのであれば、dataサブディ

レクトリに datalistファイルを与えることで、インストールの速度を上げることができる。

datalistファイルはdata()が見つける 1つのトピックにつき 1行からなり、もし、data(foo)が ‘foo’を提供しているのであれば ‘foo’という形式で、あるいは data(foo)が ‘bar’と ‘bah’を提供しているのであれば、‘foo: bar bah’という形式で書く。R CMD buildは tools::add_

datalist関数を用いることによって、自動的に 1MBを超える datalistファイルを dataディ

レクトリに加える。

テーブル (.tab、.txt、あるいは.csv)はgzip、bzip2あるいはxzによって圧縮され、必要

に応じて.gz、.bz2あるいは.xzという拡張子を持つ。しかしながら、そのようなファイルはR2.10.0かそれ以降のみで使用することができ、そのため、パッケージはそのDESCRIPTIONファイルに、適切な ‘Depends’エントリを持たなければならない。

もしパッケージが配布される予定なのであれば、ユーザに対し大きなデータセットのリ

ソースへの影響を考えるようにせよ: 大きなデータセットは、パッケージをロードするのに何秒もかかるようにする他にも、パッケージのダウンロードをとても遅くさせ、歓迎できな

いストレージ空間の量を使い尽くことができるようにしてしまう。大きなデータセットは、

16 e.g http://tools.ietf.org/html/rfc4180.

Page 22: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 16

save(, compress = TRUE)(デフォルト)によって準備された.rdaイメージとして配布するの

が通常は最善である: ASCIIコードでセーブされたものを配布することに言い訳の余地はない。bzip2あるいは xzを用いて圧縮することは、通常はパッケージの tar書庫とインストールされたパッケージの両方の容量を減らし、場合のよっては 2倍かそれ以上になる。しかしながら、そのような圧縮はR 2.10.0以降でのみ利用可能であり、そのためパッケージはそのDESCRIPTIONファイルに、適切な ‘Depends’エントリを持たなければならない。

toolsパッケージは、データイメージに役立つ 2つの関数を持っている: checkRdaFilesはイメージが保存された方法について報告し、resaveRdaFilesは特定のイメージに対し、最適

な種類を選択することを含めて、異なった種類で圧縮して再保存するであろう。

‘LazyData’を用いたいくつかのパッケージでは、インストールされた遅延読み込みデータベースでは gzip 以外の別の圧縮形式を用いることで恩恵があるだろう。これは R CMD

INSTALLに対して--data-compressオプションを付ける、あるいは DESCRIPTIONファイルの

‘LazyDataCompression’フィールドを使うことによって選択されるようになる。役立つ値はbzip2、xz、初期設定の gzipである。どれが最善であるかを見つける唯一の方法は、それら

を全部試して pkgname/data/Rdata.rdbファイルのサイズを見ることである。

遅延読み込みはとても大きなデータセット (シリアライズされたときに 2ギガバイトを超えるもの)に対してはサポートしていない。

1.1.6 パッケージ中の非Rスクリプト

コンパイルされる必要があるコード (C, C++, FORTRAN, Fortran 95 . . . )は srcディレクト

リに含められ、このドキュメントの中の他の場所でも議論されている。

execサブディレクトリはシェル (例えば arulesSequences (http://CRAN.R-project.org / package=arulesSequences))、BUGS、Java、JavaScript、Matlab、Perl(FEST (http: / / CRAN . R-project . org / package=FEST))、php (amap (http: / /

CRAN . R-project . org / package=amap))、Python あるいは Tcl、R さえ含んだインタプリタのスクリプトのために利用されることがある。しかしながら、例えば

AMA/inst/java、WriteXLS/inst/Perl、Amelia/inst/tklibs、CGIwithR/inst/cgi-

bin、NMF/inst/matlabそして emdbook/inst/BUGSのように、instディレクトリを利用す

ることがより一般的のように思われる。

もしパッケージがそれらのインタプリタの 1つや拡張を必要とするのであれば、そのことはパッケージの DESCRIPTIONファイルの ‘SystemRequirements’フィールドで宣言されるべきである。Windowsユーザは、RのWindowsインストーラに含められている Tclの拡張である ‘BWidget’と ‘Tktable’は拡張であり、宣言される必要があるということを知っているべきである。‘Tktable’はMac OS X用に CRANで配布されている Tcl/Tkの一部に乗り込んでいるが、ユーザにはその使い方を教える必要がある:

> addTclPath(’/usr/local/lib/Tktable2.9’)

> tclRequire(’Tktable’)

<Tcl> 2.9

1.2 コンフィギュアとクリーンアップ

この節はUnix系の環境に特化している: 後でRのWindowsの移植版に関するコメントについて見よ。

もしパッケージがインストール前にいくつかシステムに依存した構成を必要とするので

あれば、パッケージの中に configureという、他の動作の前に R CMD INSTALLによって (ファイルがあれば)実行される、実行可能な (Bourneシェル)スクリプトを含めることができる。

Page 23: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 17

Autoconfのメカニズムによって生成されたスクリプトもありうるが、自身で書かれたスクリプトであるかもしれない。パッケージがコンパイルあるいは利用されたときにエラーメッセー

ジを出すというよりも、インストール時にパッケージ中の対応するコードが利用可能でない

ような、非標準のライブラリがあるか検出するためにこれを利用せよ。要するに、Autoconfの最大限の力は拡張パッケージに利用可能である (変数の置換、ライブラリの探索など)。

Unix系の環境下に置いてのみ、実行可能な (Bourneシェル)スクリプト cleanupは、R CMD

INSTALLに--cleanオプションが与えられていた時と、ソースからビルドするパッケージを準

備しているときの R CMD buildによって最後に実行される。cleanupはパッケージソースツ

リーを綺麗にするために利用されることがある: 特に configureによて作成されたすべての

ファイルを取り除くはずである。

例として、(CまたはFORTRAN)ライブラリ fooによって提供されている機能を使いたい

ということを考えよう。Autoconfを利用することで、私たちはライブラリをチェックし、変数 HAVE_FOOが存在すれば TRUEという値を、そうでなければ FALSEを設定し、その値を出力

ファイルに代入する (HAVE_FOOという値を持つ入力ファイル中の ‘@HAVE_FOO@’というインスタンスを置き換えることによる)コンフィギュアスクリプトを作成することができる。例えば、もし barという名前が付けられた関数がライブラリ fooに対してリンクすることに利用

可能になるのであれば (つまり-lfooを使う)、configure.acの中でこのように使える。

AC_CHECK_LIB(foo, fun, [HAVE_FOO=TRUE], [HAVE_FOO=FALSE])

AC_SUBST(HAVE_FOO)

......

AC_CONFIG_FILES([foo.R])

AC_OUTPUT

(Autoconf 2.50以降であることを仮定する).

foo.R.in中の対応するRの関数の定義は次のようになる。

foo <- function(x) {

if(!@HAVE_FOO@)

stop("Sorry, library ’foo’ is not available"))

...

このファイルから、もし (目的の機能をもった) ライブラリ fooが見つからなかった場合、

configureは次に見られるような foo.Rという実際のRのソースファイルを生成する。

foo <- function(x) {

if(!FALSE)

stop("Sorry, library ’foo’ is not available"))

...

この場合、上のRのコードは関数を事実上、利用不可能にする。

また、利用可能な機能と失われた機能のそれぞれに対して、異なったファイルの断片を利

用することができるだろう。

configureテストでは、Rあるいはパッケージをコンパイルしているときのように、同じCコンパイラとコンパイラフラグが使われていることを確実にすることが必要となるであろう。Unix系の環境下では、configure.acの初期に以下の断片を加えることによってこれを

達成することができる。

Page 24: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 18

: ${R_HOME=‘R RHOME‘}

if test -z "${R_HOME}"; then

echo "could not determine R_HOME"

exit 1

fi

CC=‘"${R_HOME}/bin/R" CMD config CC‘

CFLAGS=‘"${R_HOME}/bin/R" CMD config CFLAGS‘

CPPFLAGS=‘"${R_HOME}/bin/R" CMD config CPPFLAGS‘

(単に ‘R’よりもむしろ ‘${R_HOME}/bin/R’を使うことが R CMD INSTALLの一部としてスクリ

プトを走らせるときに正しいバージョンのRを使用するために必要であり、‘${R_HOME}’に続く引用符は空白を含んでいるかもしれない。)

もし、コードが負荷チェックを行う場合、次のものが必要になるであろう。

LDFLAGS=‘"${R_HOME}/bin/R" CMD config LDFLAGS‘

そして、C++で書かれたパッケージは C++コンパイラの詳細を得る必要があり、以下のコードによって、現在の言語を C++に切り替える必要がある。

AC_LANG(C++)

たとえば Cヘッダーは C++プログラムに対して利用可能でなく、C++の名前修飾を避けるために書かれていないということから、後者は特に重要である。

基本的な設定変数あるいはヘッダの値を得るため、それとRに対してリンクする際に必要となるライブラリフラグの値を得るために R CMD configを利用することができる。詳しくは

R CMD config --helpを見よ。

公式な Autoconf Macro Archiveからの ACX_BLASマクロを利用する外部の BLASライブラリをチェックするには、単に以下のようにすれば可能である。

F77=‘"${R_HOME}/bin/R" CMD config F77‘

AC_PROG_F77

FLIBS=‘"${R_HOME}/bin/R" CMD config FLIBS‘

ACX_BLAS([], AC_MSG_ERROR([could not find your BLAS library], 1))

Rによって決定される FLIBSは、すべてのRプラットフォームにおいて、FORTRAN 77のコードが動くことを確実にするために利用されなければならないことに注意が要る。FLIBS

を上書きするであろう Autoconfマクロ AC_F77_LIBRARY_LDFLAGSを呼ぶことは利用しては

ならない (そして、そのため例えば ACX_BLASから除外されている。(実際、Autoconfの最近のバージョンでは、すでに設定された FLIBSがFORTRANリンカフラグのテストのために上書きすることを認めている。またRの最近のバージョンは外部の BLASと LAPACKライブラリを検出することができる。)

コンフィギュアスクリプトはWindowsシステムで利用されないということは念頭におくべきである。もしパッケージが一般に入手可能になるのであれば、非Unix系のプラットフォームのユーザが手動で設定できるよう十分な情報を与えるか、そのプラットフォームで利用さ

れるような configure.winというスクリプトを提供するようにして欲しい。(必要に応じてcleanup.winがある可能性がある。両方のスクリプトとも Bourneスタイルの shの最小バー

ジョンである ashによって実行されるシェルスクリプトであるべきである。)configure.winが実行されるとき、R_HOME(ファイルの区切り文字として ‘/’を利用する)と R_ARCHが環境変

数に設定されるであろう。R_ARCHは 64-bitビルド (その値は ‘/x64’がある)であるかどうかを決めるため、そしてDLLを正しい場所 (${R_HOME}/libs${R_ARCH})へインストールするために利用せよ。R_ARCH_BINは binディレクトリ以下の正しい場所を見つけるために利用せ

よ。例えば、${R_HOME}/bin${R_ARCH_BIN}/Rscript.exeである。

Page 25: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 19

まれな状況においては、コンフィギュアとクリーンアップのスクリプトはパッケージが

インストールされた位置を知る必要がある。この例として、Cコードを利用し、2つの共有オブジェクト/DLLを作成するパッケージがある。通常、Rによって動的に読み込みされるオブジェクトは 2番目の依存オブジェクトに対してリンクされる。あるシステムでは、Rによって動的に読み込まれるオブジェクトに、この依存オブジェクトの位置を加えることがで

きる。これは各ユーザが LD_LIBRARY_PATH(か同等な)環境変数の値を設定する必要がなく、2番目のオブジェクトが自動的に参照されるということを意味している。別の例として、パッケージが実行時に必要となるサポートファイルをインストールするとき、それらの位置はイ

ンストール時に Rのデータ構造に代入されるということがある (これは Omegahatの SJavaパッケージ中の Java Archiveファイルで起こる)。最上位のライブラリディレクトリの名前(つまり ‘-l’引数で指定可能である)とパッケージ自身のディレクトリ名は 2つのシェル/環境変数 R_LIBRARY_DIRと R_PACKAGE_DIRによってインストールスクリプトで利用可能にな

る。加えて、インストールされているパッケージ名 (例えば、‘survival’、あるいは ‘MASS’)は環境変数 R_PACKAGE_NAMEから利用可能である。(現時点では、 R_PACKAGE_DIRの値は常に

${R_LIBRARY_DIR}/${R_PACKAGE_NAME}であるが、これはバージョン管理されたインストー

ルが許されていたときは当てはまらなかった。主な用途は外部のソフトウェアのDLLのインストールパスのための configure.winスクリプト中である。)R_PACKAGE_DIRの値は空白や、他のシェルに優しくない文字を含んでいるかもしれないので、makefileとコンフィギュアスクリプトでは、その値は引用符で囲うべきである。

さらに難しい作業の 1つがヘッダと外部ソフトウェアのライブラリに見られる。Unix系の(Max OS Xではない)環境で、これをするためにますます利用可能になってきているツールが pkg-configである。configureスクリプトはコマンド自身の存在に対してテストをする必

要があり (例えばCairo (http://CRAN.R-project.org/package=Cairo)を見よ)、そしてもし存在しているのであれば、例えば以下のように、ソフトウェアがインストールされている

場合、適切なバージョンとコンパイル/リンクフラグからなっているか尋ねることができる。

$ pkg-config --exists ’QtCore >= 4.0.0’ # check the status

$ pkg-config --modversion QtCore

4.7.1

$ pkg-config --cflags QtCore

-DQT_SHARED -I/usr/include/QtCore

$ pkg-config --libs QtCore

-lQtCore

pkg-config --libsはそのライブラリ (通常は動的ライブラリ)の既定のバージョンにリンクするのに必要となる情報を提供し、もし静的ライブラリが利用されるのであれば pkg-config

--staticが必要となることに注意。

pkg-configに知られているソフトウェアの名前は期待しているものではないことがある

(例えば 2.22なのに ‘gtk+-2.0’)。完全なリストを得るためには、以下のものを利用せよ。

pkg-config --list-all | sort

1.2.1 Makevarsを使う

Makevarsファイルを提供することによって、ときおり configureスクリプトを書くことを回

避することができることがある: また configureスクリプトのもっとも一般的な利用の 1つに、Makevars.inから Makevarsを作成するということがある。

Makevarsファイルはmakefileであり、R CMD SHLIB(srcディレクトリ中のコードをコンパイルするための R CMD INSTALLによって呼ばれる。)によって、いくつかのmakefileの 1つと

Page 26: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 20

して利用される。可能であれば移植可能な形式で書くべきであり、特に (Makevars.winを除いて)GNU拡張を使用することなく書かれるべきである。

最も一般的な Makevarsファイルの利用は、C/C++のファイルに対し、PKG_CPPFLAGSを経由して追加のプリプロセッサのオプション (例えばインクルードのパス)を設定することと、C、C++、FORTRANあるいは Fortran 9xのそれぞれに対し PKG_CFLAGS、PKG_CXXFLAGS、

PKG_FFLAGSあるいは PKG_FCFLAGSという追加のコンパイラフラグを設定するというもので

ある (see Section 5.5 [共有オブジェクトの作成], page 104)。

注意:インクルードパスはプリプロセッサオプションであり、コンパイラオプションではない。そして他のプラットフォーム特有のパスに優先するように、インクルードパスは PKG_

CPPFLAGSに設定されなければならない。

Makevarsはリンカにフラグを設定するのにも利用される。例えば PKG_LIBSを用いた ‘-L’と ‘-l’オプションがある。

パッケージの Makevarsファイルを書くということは配布を意図しているので、ファイル

が使用しているコンパイラ特有のものにならないことを確実にするよう、注意を払うように

せよ: -O2 -Wall -pedanticのようなフラグはすべてGCCに固有である。

R自身のビルドを構成中の間に設定され、R_HOME/etcR_ARCH/Makeconfに保存されてい

るマクロ 17がある。そのmakefileは Makevars[.win]の後ろに Makefileとして含められて

おり、それが定義するマクロはマクロの割り当てと、後者についてはmakeコマンドラインで利用することができる。これらは以下のものを含んでいる。

FLIBS FORTRANコードにリンクするのに必要なライブラリの集合を含んだマクロである。これは PKG_LIBSに含められることが必要になるかもしれない: もしパッケージが FORTRANのソースファイルを含むのであれば、普通は自動的に含められるであろう。

BLAS_LIBS

Rをビルドするときに使用される BLASライブラリを含むマクロである。これは PKG_LIBSに含められる必要がある。もし、それが空であれば、R実行ファイルはすべての倍精度と倍精度複素数のBLASルーチンを含むことになり、短精度と複素数のルーチンは含まないことに用心せよ。もし BLAS_LIBSが含まれている

場合は、大部分のBLASライブラリが少なくとも部分的には FORTRANで書かれているので、FLIBSはそれに追従するように含められる 18必要がある。

LAPACK_LIBS

Rをビルドするときに使われる LAPACKライブラリ (と適切なパス)を含むマクロである。これは PKG_LIBSに含められる必要があるかもしれない。それはRをビルドするのに必要となる倍精度複素数のLAPACKとBLASのルーチンと同様に、すべての倍精度の LAPACKルーチンを含んでいる動的ライブラリ libRlapack

を指し示しているかもしれない。あるいは外部の LAPACKライブラリを指し示しているかも知れないし、また外部のBLASが LAPACKも含んでいれば空白になるかもしれない。

[LAPACKライブラリはすべての倍精度、倍精度複素数ルーチン以上のものを提供する保証はなく、すべての補助ルーチンを提供しないものもある。]

17 POSIXの用語では: GNU makeがこれらの ‘make変数’を呼ぶ18 少なくとも Unix系の環境上では: Windowsビルドは、現在は Rblas.dllが構築されるときに、静的 FOR-

TRANライブラリに対するそのような依存関係を解決している。

Page 27: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 21

移植性のために、BLAS_LIBSと FLIBSのマクロは常に LAPACK_LIBSの後ろに (その順序で)含められるべきである。

SAFE_FFLAGS

FORTRANコードの過度な最適化を避けるために必要なフラグを含んだマクロである。gfortranを利用するときの ‘ix86’プラットフォームにおける ‘-g -O2

-ffloat-store’が典型的である。これは PKG_FFLAGSの一部として使用される

付加的なフラグではないが FFLAGSを置換し、しかも FORTRAN 77コンパイラ‘F77’を意図しており、Fortran 90/95コンパイラ ‘FC’を必ずしも意図していない。この節の後ろにある例を見よ。

Makevarsにあるマクロを設定することは、R CMD SHLIBがそのようなマクロを設定するこ

とを防ぐことになる: 特に、もし Makevarsが ‘OBJECTS’を設定するのであれば、makeコマン

ドライン上にそれは設定されないであろう。これは他の種類のソースコードがコンパイルさ

れ、共有オブジェクトに含められるという暗黙のルールと合わせると有用である。また src中

のファイルを除く、あるいはサブディレクトリ中のファイルを含めるというどちらかによって、

コンパイルされるファイルの集合を制御することにも利用される。例えば次の通りである。

OBJECTS = 4dfp/endianio.o 4dfp/Getifh.o R4dfp-object.o

Makevarsは既定のmakefileの前に含められており、makeは規定のmakefile中の allを意

図して最初のターゲットを呼ぶということから、Makevarsは通常はターゲットを含めるべき

ではないということに注意。もし、本当にそれを避ける必要があるのであれば、適切な (偽の)ターゲット allを Makevars.[win]中で任意の実際のターゲットが出てくる前に利用せよ:例えばパッケージ fastICA (http://CRAN.R-project.org/package=fastICA)は次のようなものを持つ。

PKG_LIBS = @BLAS_LIBS@

SLAMC_FFLAGS=$(R_XTRA_FFLAGS) $(FPICFLAGS) $(SHLIB_FFLAGS) $(SAFE_FFLAGS)

all: $(SHLIB)

slamc.o: slamc.f

$(F77) $(SLAMC_FFLAGS) -c -o slamc.o slamc.f

LAPACKルーチンが無限ループすることなくいくつかの定数を見つけることを確実にしておく必要とされている。Windowsの同等表現は次の通り。

all: $(SHLIB)

slamc.o: slamc.f

$(F77) $(SAFE_FFLAGS) -c -o slamc.o slamc.f

(他のマクロはすべてWindowsプラットフォームでは空であるため、Rの内部の BLASは利用されていない)。Makevarsの最初のターゲットが呼ばれるが、後方互換性のため、最もよい名前は allであることに注意。

もし作成してライブラリにリンクしたいのであれば、サブディレクトリのコードを利用す

ることを示し、以下のようなものを使用せよ。

.PHONY: all mylibs

all: $(SHLIB)

$(SHLIB): mylibs

mylibs:

(cd subdir; make)

Page 28: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 22

allの依存関係は特定の順序で動作する (そして、CRANのビルドマシンには複数の CPUとmakeの並列処理を利用するものがある)保証がないということから、すべての必要な依存関係を生成しているか注意せよ。

Windows上では、Makevars[.win]が DLLを生成することが必要となることに注意: これはDLLのビルドが成功することを保証するための唯一信頼できる方法として必要とされている。もしDLLをビルドすること以外の別の目的で srcディレクトリを利用したいというの

であれば、Makefile.winファイルを利用せよ。

Makevarsあるいは Makevars.winに ‘clean’というターゲットを持たせるのはときおり有益である: R CMD buildがパッケージのソース (のコピー)を一掃するために利用されるであろう。buildによって ‘clean’が走るとき、特にファイル自身が設定しない限り、$(SHLIB)でも、$(OBJECTS)でもない 2、3のマクロが設定される。--cleanと--precleanというオプション

を伴った R CMD INSTALLと R CMD SHLIBによって動作するターゲット ‘shlib-clean’に役割を加えることも可能である。

もしRのコードを Makevarsの中で走らせたい: 例えば設定情報を見つけるのであれば、R

あるいは Rscriptの正しいコピーを使用することを確実にしてほしい: パスの中に 1つもないかも知れないし、誤ったバージョンやアーキテクチャであるかもしれない。これを正しく

行うには次のように行えばよい。

"$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" filename

"$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" -e ’R expression’

$(R_ARCH_BIN)は現在のところ、Windowsにおいてのみ必要とされる。

環境/make変数は 32ビットと 64ビットのコードで異なるマクロを選択するために利用される。例えば (Windows上で許されたGNU makeの文法は)次のように書く。

ifeq "$(WIN)" "64"

PKG_LIBS = value for 64-bit Windows

else

PKG_LIBS = value for 32-bit Windows

endif

Windows上では通常、インポートライブラリへのリンクか、DLLへ直接リンクするかの選択がある。可能であれば、後者がより信頼できる: インポートライブラリは特定のツールチェインに結び付けられており、特に 64ビットWindowsにおいては、2つの異なる慣習が一般的に利用されている。そのため、例えば、

PKG_LIBS = -L$(XML_DIR)/lib -lxml2

の代わりに、以下のものを使うことができる。

PKG_LIBS = -L$(XML_DIR)/bin -lxml2

その理由として、Windows上では-lxxxは以下の順に探すためである。

libxxx.dll.a

xxx.dll.a

libxxx.a

xxx.lib

libxxx.dll

xxx.dll

最初と 2番目は慣習的にはインポートライブラリであり、3番目と 4番目はしばしば静的ライブラリ (Visual C++を対象とした.libがついている)であるが、インポートライブラリである

Page 29: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 23

かもしれない。例として http://sourceware.org/binutils/docs-2.20/ld/WIN32.html#

WIN32を見よ。

玉にキズなのは、DLLは libxxx.dllと名づけられないかもしれず、事実 64ビットWin-dows でのビルドでは libxml2-2.dllと呼ばれている DLL が、32 ビット Windows では、libxml2.dllとなっているのである。インポートライブラリを使うことはこれらの違いを覆

うことができるが、同じような困難を起こすことがある。

もし静的ライブラリが利用可能であれば、ランタイムが DLLの発見をすることに関する多くの問題を省くことができる。特にバイナリのパッケージが配布されるとき、両方のアー

キテクチャをサポートするときは尚更である。DLLを使うことが避けられないときは、DLLをパッケージのDLLとして同じディレクトリに送り込む用意を行う (configure.winを利用して)のが通常である。

1.2.1.1 OpenMPのサポート

R 2.13.0からは OpenMPを使いたい 19という要望のあるパッケージに対するサポートがあ

る。makeマクロは以下のものが src/Makevarsあるいは src/Makevars.winの中において利

用可能である。20

SHLIB_OPENMP_CFLAGS

SHLIB_OPENMP_CXXFLAGS

SHLIB_OPENMP_FCFLAGS

SHLIB_OPENMP_FFLAGS

PKG_CFLAGSや PKG_CPPFLAGSなど、また PKG_LIBSにも適切なマクロを含めるようにせよ。

OpenMPの利用を条件付けられる必要がある C/C++のコードはヘッダ Rconfig.hの内部で

定義されたマクロ#ifdef SUPPORT_OPENMPの内側で利用される。(see Section 6.13 [プラットフォームとバージョン情報], page 150): しかしながら、OpenMPの利用は、‘#pragma’ステートメントによって最もよく示唆されている。

例えばOpenMPのために Cのコードで書かれたパッケージは src/Makevarsの中に次の

行をもたせるべきである。

PKG_CFLAGS = $(SHLIB_OPENMP_CFLAGS)

PKG_LIBS = $(SHLIB_OPENMP_CFLAGS)

どのOpenMPのバージョンがサポートされているかということについては、何もいうことがない: バージョン 3.0(2008年 5月)は主要なプラットフォーム (だが、Mac OS Xバイナリはバージョン 2.5をサポートするコンパイラを用いて、現在は 10.5のための構築をしている)の最近のバージョンではサポートされているが、ポータブルパッケージはエンドユーザが最近のバージョンを持っていることを仮定できず (何年も前の Linuxを使っていることもある)、バージョン 2.5を仮定するのがもっとも安全であろう。

OpenMPを用いるために書かれたC/C++のコードは ompプラグマと他のOpenMP固有のコードを#ifdef _OPENMP ... #endifの中に含めるべきである。

OpenMPサポートはR 2.15.0のために使われたツールチェインにおいてWindows上で利用可能であり、これらのマクロは適切に設置される。R 2.14.2以前ではWindows上で利用可能ではない。

19 http://www.openmp.org/,http://en.wikipedia.org/wiki/OpenMP,https://computing.llnl.gov/tutorials/openMP/

20 しかしWindows上で、R 2.14.2以前に使われていた既定のツールチェインを使っているものは OpenMPサポートは利用可能ではない

Page 30: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 24

OpenMPのパフォーマンスはプラットフォーム間でかなり変化する。Mac OS XとWindowsの実装はかなりのオーバーヘッドがあり、もしかなり大きな処理を平行して走らせる場合に

おいてのみ有益である。

スレッド化されたコードからR APIのいずれかを呼ぶのは ‘専門家のみに限る’: 専門家はソースコードを読んで、それがスレッドセーフか判断する必要がある。特に、スタックチェッ

ク機構を利用するコードはスレッド化されたコードから呼ばれてはならない。

1.2.1.2 pthreadsを使う

POSIXスレッド (より一般的には pthreadsとして知られている)に対する直接のサポートはない: それを追加することを考えるまでに、いくつかのパッケージはそれを無条件に利用していたので、今ではPOSIXオペレーティングシステムで普遍的に利用可能であるように思われる (したがってWindowsではない)

gccの比較的新しいバージョンに対する正しい明記は次の通り

PKG_CPPFLAGS = -pthread

PKG_LIBS = -pthread

(そして複数のバージョンがいくつかのシステム/バージョンで受け入れられている)。他のプラットフォーム用の明記は次の通り

PKG_CPPFLAGS = -D_REENTRANT

PKG_LIBS = -lpthread

(そしてライブラリ名は唯一であることに注意)。これが-pthreadがすべての知られた現在の

プラットフォームですることである (OpenBSDの初期のバージョンでは異なったライブラリ名を用いているが)。

チュートリアルは https://computing.llnl.gov/tutorials/pthreads/を参照せよ。

POSIXスレッドはスレッドの独自のコンセプトを持つWindowsで通常は使われていない。しかしながら、pthreads-w32と winpthreadsという、Windows上で pthreadsを実装してい

るプロジェクトがある (MinGW-w64プロジェクトの新しい部分である)。どちらもlibptheads

をDLLのインポートライブラリとして実装している。

Windowsのツールチェインがpthreadsを実装しているかどうかは、ツールチェインプロバ

イダ次第である。1つの問題はライセンスである: pthreads-w32はソースコードを利用できることを要求するLGPLの元でライセンスされている。R 2.14.2以前にコンパイルのために利用されていたツールチェインはpthreadsを含んでいないが、いくつかの場合ではpthreads-w32

が改造したものを含んでいることがある。R 2.14.2からは make変数 SHLIB_PTHREAD_FLAGS

が利用可能である: これは PKG_CPPFLAGS(あるいはFortran、F9xと同等のもの)と PKG_LIBS

のどちらにも含められるべきである。

pthreadsの実装の有無は、あなた自身がテストしないことには明確に判断することはで

きない: しかしながら、C/C++のコード中に ‘_REENTRANT’が定義されている 21ことはよい指

標である。

OpenMPの下でのスレッドセーフとパフォーマンスに関するコメントも参照せよ: すべての知られた Rプラットフォーム上で、OpenMPは pthreadsを用いて実装されており、既知

のパフォーマンスの問題は後者である。

21 Windowsのツールチェインには ‘_REENTRANCE’というタイプミスを代わりしているものもある

Page 31: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 25

1.2.1.3 サブディレクトリでのコンパイル

例えば、もしRのインタフェースである独立した外部のソフトウェアの部品を含めたいというときには、パッケージの作者はかなりよくコードを srcのサブディレクトリに整理したい

と思っている。

簡単な 1つの方法は、OBJECTSをサブディレクトリを含め、コンパイルされる必要があるすべてのオブジェクトに単に設定することである。例えばCRANパッケージのRSiena (http://CRAN.R-project.org/package=RSiena)は次のようになっている。

SOURCES = $(wildcard data/*.cpp network/*.cpp utils/*.cpp model/*.cpp model/*/*.cpp model/*/*/*.cpp)

OBJECTS = siena07utilities.o siena07internals.o siena07setup.o siena07models.o $(SOURCES:.cpp=.o)

このアプローチによる 1つの問題は GNU make拡張が利用されない限り、ソースファイルは一覧にされ、最新のものに保たれている必要があるということである。CRANパッケージlossDev (http://CRAN.R-project.org/package=lossDev)では以下のようになっている。:

OBJECTS.samplers = samplers/ExpandableArray.o samplers/Knots.o \

samplers/RJumpSpline.o samplers/RJumpSplineFactory.o \

samplers/RealSlicerOV.o samplers/SliceFactoryOV.o samplers/MNorm.o

OBJECTS.distributions = distributions/DSpline.o \

distributions/DChisqrOV.o distributions/DTOV.o \

distributions/DNormOV.o distributions/DUnifOV.o distributions/RScalarDist.o

OBJECTS.root = RJump.o

OBJECTS = $(OBJECTS.samplers) $(OBJECTS.distributions) $(OBJECTS.root)

サブディレクトリは適切なmakefileを持つ自己完結型のコードであり、最善のアプローチは以下のようなものである。

PKG_LIBS = -LCsdp/lib -lsdp $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)

$(SHLIB): Csdp/lib/libsdp.a

Csdp/lib/libsdp.a

@(cd Csdp/lib && $(MAKE) libsdp.a \

CC="$(CC)" CFLAGS="$(CFLAGS) $(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)")

引用符に注意: マクロは例えば gcc -m64 -std=gnu99のように、空白を含むことがある。パッ

ケージの作者の何人かは並列makeについて忘れてしまっている: サブディレクト中の静的ライブラリは共有ライブラリが作られる前に作られなければならず、後者に依存しなければな

らない。位置独立コードである必要性を忘れている者もいる。

src/Makevarsの代わりに src/Makefileを使うことは本当に推奨しておらず、上の例が示

しているように、必ずしも必要なものでもない。

1.2.2 コンフィギュアの例

configureスクリプトを使って src/Makevarsファイルを生成する拡張例を与えることは役立

つかもしれない: これはRODBC (http://CRAN.R-project.org/package=RODBC)パッケージにあるものに基づいている。

configure.acファイルは以下のようである: configureは (configure.acを含んでいる)パッケージディレクトリのトップレベルにある autoconfファイルを実行することによって

configure.acから生成される。

AC_INIT([RODBC], 1.1.8) dnl package name, version

dnl A user-specifiable option

odbc_mgr=""

Page 32: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 26

AC_ARG_WITH([odbc-manager],

AC_HELP_STRING([--with-odbc-manager=MGR],

[specify the ODBC manager, e.g. odbc or iodbc]),

[odbc_mgr=$withval])

if test "$odbc_mgr" = "odbc" ; then

AC_PATH_PROGS(ODBC_CONFIG, odbc_config)

fi

dnl Select an optional include path, from a configure option

dnl or from an environment variable.

AC_ARG_WITH([odbc-include],

AC_HELP_STRING([--with-odbc-include=INCLUDE_PATH],

[the location of ODBC header files]),

[odbc_include_path=$withval])

RODBC_CPPFLAGS="-I."

if test [ -n "$odbc_include_path" ] ; then

RODBC_CPPFLAGS="-I. -I${odbc_include_path}"

else

if test [ -n "${ODBC_INCLUDE}" ] ; then

RODBC_CPPFLAGS="-I. -I${ODBC_INCLUDE}"

fi

fi

dnl ditto for a library path

AC_ARG_WITH([odbc-lib],

AC_HELP_STRING([--with-odbc-lib=LIB_PATH],

[the location of ODBC libraries]),

[odbc_lib_path=$withval])

if test [ -n "$odbc_lib_path" ] ; then

LIBS="-L$odbc_lib_path ${LIBS}"

else

if test [ -n "${ODBC_LIBS}" ] ; then

LIBS="-L${ODBC_LIBS} ${LIBS}"

else

if test -n "${ODBC_CONFIG}"; then

odbc_lib_path=‘odbc_config --libs | sed s/-lodbc//‘

LIBS="${odbc_lib_path} ${LIBS}"

fi

fi

fi

dnl Now find the compiler and compiler flags to use

: ${R_HOME=‘R RHOME‘}

if test -z "${R_HOME}"; then

echo "could not determine R_HOME"

exit 1

fi

CC=‘"${R_HOME}/bin/R" CMD config CC‘

CPP=‘"${R_HOME}/bin/R" CMD config CPP‘

CFLAGS=‘"${R_HOME}/bin/R" CMD config CFLAGS‘

CPPFLAGS=‘"${R_HOME}/bin/R" CMD config CPPFLAGS‘

AC_PROG_CC

AC_PROG_CPP

if test -n "${ODBC_CONFIG}"; then

RODBC_CPPFLAGS=‘odbc_config --cflags‘

Page 33: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 27

fi

CPPFLAGS="${CPPFLAGS} ${RODBC_CPPFLAGS}"

dnl Check the headers can be found

AC_CHECK_HEADERS(sql.h sqlext.h)

if test "${ac_cv_header_sql_h}" = no ||

test "${ac_cv_header_sqlext_h}" = no; then

AC_MSG_ERROR("ODBC headers sql.h and sqlext.h not found")

fi

dnl search for a library containing an ODBC function

if test [ -n "${odbc_mgr}" ] ; then

AC_SEARCH_LIBS(SQLTables, ${odbc_mgr}, ,

AC_MSG_ERROR("ODBC driver manager ${odbc_mgr} not found"))

else

AC_SEARCH_LIBS(SQLTables, odbc odbc32 iodbc, ,

AC_MSG_ERROR("no ODBC driver manager found"))

fi

dnl for 64-bit ODBC need SQL[U]LEN, and it is unclear where they are defined.

AC_CHECK_TYPES([SQLLEN, SQLULEN], , , [# include <sql.h>])

dnl for unixODBC header

AC_CHECK_SIZEOF(long, 4)

dnl substitute RODBC_CPPFLAGS and LIBS

AC_SUBST(RODBC_CPPFLAGS)

AC_SUBST(LIBS)

AC_CONFIG_HEADERS([src/config.h])

dnl and do substitution in the src/Makevars.in and src/config.h

AC_CONFIG_FILES([src/Makevars])

AC_OUTPUT

src/Makevars.inは単に次のようになるであろう。

PKG_CPPFLAGS = @RODBC_CPPFLAGS@

PKG_LIBS = @LIBS@

ユーザは以下のようなオプションによって、ODBCドライバマネージャファイルの位置を特定する通知を受けられるようになる (可読性のため改行している)。

R CMD INSTALL \

--configure-args=’--with-odbc-include=/opt/local/include \

--with-odbc-lib=/opt/local/lib --with-odbc-manager=iodbc’ \

RODBC

あるいは環境変数 ODBC_INCLUDEと ODBC_LIBSを設定することによってもできる。

1.2.3 F95のコードを使う

Rは.fという拡張子を持つソースファイルは FORTRAN 77であると仮定しており、‘F77’によって規定されているコンパイラにそれらのコードを渡す。コンパイラはすべてではないが、

大部分のプラットフォームでは Fortran 90/95のコードを受け入れる: いくつかのプラットフォームでは、Fortran 90/95で別のコンパイラを持ち、わずかな (今ではかなり珍しい 22)プラットフォームでは Fortran 90/95のサポートはない。

22 Cygwinは g77を 2011年まで利用し、いくつかの Unix OS用の Rのプレビルドバージョンはまだ g77を使用している。

Page 34: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 28

これが意味するのは、移植可能なパッケージは正しい FORTRAN 77で書かれる必要があり、Fortran 95でもまた妥当であるよう書かれる必要があるということである。参照用の情報資源としては http://developer.r-project.org/Portability.htmlを見よ。特に自由

形式の F95のコードは移植可能ではない。

特定のシステムでは、代替のF95コンパイラが利用可能である: gccファミリーから、これは gfortranあるいは g95であるだろう。Rを設定することで、どれが (その名前から)Fortran90/95のコンパイラであるかを見つけようと試み、マクロ ‘FC’にそれを設定する。そのようなコンパイラは完全に (あるいは部分的にさえ)Fortran 90/95に準拠しているかを確認しているわけではないことに注意。Fortran 90/95の特徴を利用するパッケージは、ソースファイルに対し、.f90あるいは.f95の拡張子を利用しなければならない: 変数 PKG_FCFLAGSは使用され

る任意のの特別なフラグを明記している。コンパイルされた Fortran 90/95のコードは、他の任意のコンパイルされたコードに混ぜることや、Rのビルドがそのようなパッケージをサポートするということに対し、何の保証も無い。

マクロ ‘FC’によって明記されたすべてのコンパイラは Fortran 2003と 2008のコードを受け入れるであろう。gfortranを利用するプラットフォームでは、-std=f2003あるいは-

std=f2008を PKG_FCFLAGSに含める必要があるかもしれない: 既定値は非標準の拡張を伴った ‘GNU Fortran’である。Solarisの f95コンパイラは ‘いくつかの Fortran 2003の特徴を受け入れる’。そのようなコードは、まだファイルの拡張子は.f90あるいは.f95を使用するべき

である。

1.3 パッケージのチェックとビルド

これらのツールを使う前に、パッケージがインストールとロードできるということを確認して

欲しい。R CMD checkはとりわけこれを行うが、直接確認することで、より詳細なエラーメッ

セージを得ることができるかもしれない。

もしパッケージが DESCRIPTIONファイルにエンコーディングを明記しているのであれば、

そのエンコーディングを利用しているロケールにおいてこれらのツールを実行するべきであ

る: 他のロケールではまったく動かない、あるいは正しく動かないかもしれない。

注意: --vanillaをつけて R CMD check and R CMD buildと Rを動作させたとき、ユーザのスタートアップファイルは読まれない。もし、R_LIBSが (非標準ライブラリ中のパッケージを見つけるため) 設定される必要があれば、環境にそれを組み込むことができる: またチェックとビルドの環境ファイル (環境変数 R_CHECK_ENVIRONと R_BUILD_ENVIRONによって明記される; もし環境変数が設定されていないのであれば、2 つのファイル 23~/.R/check.Renvironと

~/.R/build.Renvironが使用される。)をこれらの用役を使うときに環境変数を設定するために使うことができる。

Windowsユーザへの注意: R CMD buildはWindowsのツールセット (“Rのインストールと管理”のマニュアルを参照せよ)をインストールすることと、パスを通すことを要求するかもしれず、R CMD checkはもしツールセットがあるのであ

れば利用するであろう。TMPDIRをパスに空白を含まない、書き込み可能である適

切なディレクトリを指すように設定する必要があるかもしれない – セパレータとしてフォワードスラッシュを利用せよ。また、ディレクトリは大文字・小文字

を区別するファイルシステム上にある必要がある (ネットワーク上のマウントされたファイルシステムでは必要がないものもある)。

23 サブアーキテクチャを使うシステム上では、~/.R/check.Renviron.i386のようなアーキテクチャ特有のバージョンが優先される。

Page 35: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 29

1.3.1 パッケージのチェック

Rのパッケージをチェックする R CMD checkを使うことで、Rパッケージのソースがうまく動作するかテストすることができる。R CMD checkは 1つ以上のディレクトリ、あるいは.tar.gzあ

るいは.tgzという拡張子がつけられた gzipで圧縮されたパッケージの tarアーカイブ 24に対

して動作する。(いくつかのプラットフォームでは、別形式での圧縮と、.tar.bz2と.tar.xz

という拡張子を許しているものもある。)

これは以下を含めた一連の確認の動作である。

1. パッケージがインストールされる。ヘルプファイル中の相互参照の不足と重複したエイリアスについて警告する。

2. ファイル名がファイルシステム間で有効かつオペレーティングシステムプラットフォームがサポートするものであるか確認される。

3. ファイルとディレクトリが十分な権限を持っているか確認される (Unix系のもののみ)。

4. もし利用可能であるのであれば、fileの適切なバージョンを利用して、ファイル中のバ

イナリファイルがチェックされる 25。(擬陽性になることは稀であろう。)

5. DESCRIPTIONファイルが完全であるか、そのエントリのいくつかが正しいものであるか

ということが確認される。インストールテストが飛ばされない限り、もしパッケージの

依存関係が実行時に解決できない場合、チェックは中止される。(依存パッケージが別のライブラリツリーにある場合、R_LIBSを設定する必要があるかもしれない。)チェックの1つにはパッケージ名が標準パッケージのそれではなく、現存していない標準パッケージ (‘ctest’, ‘eda’, ‘lqs’, ‘mle’, ‘modreg’, ‘mva’, ‘nls’, ‘stepfun’ and ‘ts’)の 1つでもないということがある。別のチェックとしては、library、require、NAMESPACEファイル

がインポートするものとして述べられているもの、あるいは::か:::から呼び出される

パッケージのすべてが (‘Depends’、‘Imports’、‘Suggests’あるいは ‘Contains’の中に)一覧になっているかということである: これは実際のインポートの網羅的なチェックではない。

6. 索引情報の使用可能性 (特にデモとビニェットに対して)は完全性のためにチェックされる。

7. パッケージのサブディレクトリは適切なファイル名か、そして空白でないかを調べられる。ファイル名に対するチェックは--check-subdirs=valueというオプションによって

制御される。これは ‘default’を既定値とし、それは tar書庫に対してのみ確認の動作をする: 既定値は ‘yes’あるいは ‘no’という値を明示することによって上書きされる。さらに、srcディレクトリのチェックは、パッケージが configureスクリプト (‘yes-maybe’という値に対応する)を含まず、src/Makefileや src/Makefile.inがない場合に限って動

作する。

configureスクリプトファイルが適切なファイルを生成するようにするために、Rディレ

クトリではファイル名が ‘.in’で終わることが許されるであろう。

A warning is given for directory names that look like R package check directories –many packages have been submitted to CRAN containing these.

8. Rファイルは文法エラーをチェックされる。非 ASCIIバイトは警告として報告されるが、

パッケージがいつも同じロケールで使用されるということが分かってない限りエラーと

みなされるべきである。

9. まず通常のデフォルトパッケージを伴ってパッケージがロードされるか、そして baseパッケージだけがロードされている状態でパッケージがロードされるかチェックされる。名

24 これは GNU tarを必要とするかもしれない: 使用されるコマンドは環境変数 TARを使用して設定できる。25 適切な file.exeはWindowsツールセットの一部である。

Page 36: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 30

前空間は、base名前空間だけがロードされた空のセッションでロードされるかチェックされる。(名前空間とパッケージは、デフォルトパッケージが利用可能になる前の、セッションのごく初期の段階でロードされることがあるので、そのためパッケージは動作し

なければならない。)

10. Rのファイルは library.dynamの呼び出しが正しいかチェックされる。パッケージを起

動する関数は正しい引数リストであるか、検索パスを変更してしまう、あるいは不適切

なメッセージを生成する (正しくない) 関数呼び出しかをチェックする。R のコードはcodetools (http://CRAN.R-project.org/package=codetools)を用いたときに起こりうる問題に対してチェックされる。加えて、S3メソッドは対応する汎用のすべての引数を持っているか、置換関数の最後の引数が ‘value’と呼ばれているかをチェックする。すべての外部パッケージの呼び出しは PACKAGE引数を持っているか見るためにテストされ、

もし引数がなければ適切なDLLがパッケージの名前空間から推論されるだろう。他の呼び出しは報告される。(チェックは寛容であり、特に PACKAGE引数をいつも使うことを意

図している場合、ユーザはこれを tools::checkFF("mypkg", verbose=TRUE)の出力を

確認することによって補完したいと思うかもしれない。)

11. Rdファイルは文法とメタデータが正しいか、必須のフィールド (\name、\alias、\titleと\description)を含めてチェックされる。Rdの名前とタイトルは空でないか確認され、相互参照 (リンク)が欠けていないかという確認がある。

12. パッケージ中のユーザレベルのオブジェクトに関する公式ドキュメントがないような、ドキュメントのエントリが欠けていないかというチェックがある。

13. 関数、データセットと S4クラスのドキュメントは対応するコードに対する整合性をチェックされる。

14. Rdファイルの\usageセクションで与えられているすべての関数の引数が、対応する

\argumentsセクションにおいて文書化されているかチェックされる。

15. dataディレクトリが非ASCII文字かチェックされ、理にかなった水準の圧縮を使用しているかチェックされる。

16. C、C++と FORTRANのソースとヘッダファイル 26 は移植可能な (LFに限る)行末であるかテストされる。もし Makefile、Makefile.in、Makevarsあるいは Makevars.in

ファイルが srcディレクトリ以下にあるのであれば、移植可能な行末と ‘$(BLAS_LIBS)’と ‘$(LAPACK_LIBS)’の正しい使用をチェックされる。

コンパイルされたコードは、R を終了する、あるいはコンソールの代わりに

stdout/stderrへ書き込むような関数に対応するシンボルであるかチェックされる。後者はシンボルが外部ライブラリに引き込まれ、呼ばれない可能性があることから擬陽性

になるかもしれないことに注意。Windows27ユーザは FortranとC++のランタイムライブラリはそのような外部ライブラリの例であるということに注意するべきである。

17. inst/docディレクトリの内容からいくつかのチェックが作られる。これらは常に余り物

のように見えるファイルに対するチェックを含み、そしてもし (qpdfのような)適切なツールが利用可能であれば、PDFドキュメントが最小サイズであることを確認する。

18. パッケージのドキュメントによって提供されている例が実行される。(\examplesを使って実行可能な例のコードを生成することに関する情報は see Chapter 2 [Rのドキュメントを書く], page 58を見よ。)もし tests/Examples/pkg-Ex.Rout.saveというファイル

があるのであれば、例を実行した出力はそのファイルを比較される。

26 ‘win’あるいは ‘Win’と記載されたサブディレクトリは例外になる。27 大部分のプラットフォームではランタイムライブラリは動的であるが、ツールチェインが OSの標準的な一部ではないということから、静的ライブラリは現在のところWindowsで利用されている。

Page 37: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 31

もちろん、リリースされたパッケージは少なくとも自身の例を動作させられるはずであ

る。各例は ‘クリーンな’環境 (つまり先に出てきた例が動作したことを仮定できない)で動作し、Tと Fという変数が例の中で設定されない限り、エラーを生成するために再定義

される: See Section “Logical vectors” in An Introduction to R.

19. もしパッケージソースが testsディレクトリを含むのであれば、そのディレクトリに明

記されたテストが動作する。(典型的には.Rソースファイルと目標となる出力ファイル

.Rout.saveから構成されているであろう。)エンドユーザのロケールにおいて比較が行われるので、目標となる出力ファイルはできるだけASCIIにするべきである。

20. パッケージのビニェット (see Section 1.4 [パッケージのビニェットを書く], page 35)中のコードは実行され、ビニェットの PDFはソースの完全性のチェックとして、ソースから再生成される (パッケージ中の DESCRIPTIONファイルの ‘BuildVignettes’フィールドにfalseが指定されていない限りは)。もし、ビニェットのソースディレクトリに目標となる出力ファイル.Rout.saveがあるのであれば、そのビニェットのコードを実行してえられ

た出力は目標となる出力ファイルと比較され、すべての違いが報告される (ただしログファイルに記録はされない。)。(もしビニェットのソースが非推奨の位置である inst/doc

にあるときは、.Rinstignoreにそのような目標となる出力ファイルがインストールされ

ないように印をつけよ。)

もしビニェット foo.extの中にあるRコードの実行中にエラー 28があれば、ログファイ

ル foo.ext.logがチェックディレクトリに作成される。ビニェットのPDFはチェックディレクトリにある vign_testサブディレクトリのパッケージのソースのコピーで再生成さ

れるので、エラーの更なる情報については、pkgname/vign_test/inst/docディレクト

リをみよ。(エラーあるいは環境変数_R_CHECK_CLEAN_VIGN_TEST_が falseに設定されている場合に限って情報は保持される。)

21. パッケージのマニュアルの PDF版が生成される (Rdファイルが上手く変換できることを確認するため)。これは LATEXと適切なフォントと LATEXパッケージをインストールする必要がある。さらなる詳細については、‘R Installation and Administration’マニュアルの ‘Making the manuals’を見よ。

これらのすべてのテストは Cロケールに設定する照合作業を伴って動作し、例とテストに

ついては、環境変数 LANGUAGE=enを伴って動作する: これはプラットフォーム間での違いを最小化するためである。

Rパッケージチェッカの使用方法についてさらなる情報を得るためには R CMD check --

helpを使用せよ。確認段階の部分集合はコマンドラインオプションを加えることで選択する

ことができる。‘R Internals’ に記述されているように、環境変数_R_CHECK_*_:を設定することでカスタマイズすることも許されている: これらのカスタマイズの集まりは CRANで使用

されるものと同様に、オプション--as-cranによって選択することができる。(インターネットへのアクセスが利用できる場合に最もよく動作する 29。)

パッケージがもし非 ASCII文字を含んでいるのであれば、適切なロケールでパッケージが

チェックされるように保証しなければならない。そのようなパッケージは Cロケールにおける

いくつかのチェックでは失敗しそうなものであり、R CMD checkは問題に気付くと警告するで

あろう。どのパッケージもUTF-8ロケール (利用可能であれば)で確認できるはずである。C

28 あるいはオプション--use-valgrindが使用されているか、環境変数_R_CHECK_ALWAYS_LOG_VIGNETTE_

OUTPUT_が trueに設定されているか、目標となる出力ファイルとの違いがある場合29 プロキシの後ろにいるWindowsユーザは環境変数 R_WIN_INTERNET2を非空白の値に設定したくなるかもしれない。e.g. ~/.R/check_environ。Windowsユーザの中には R_WIN_NO_JUNCTIONSを非空白の文字に設定する必要がある人もいるかもしれない

Page 38: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 32

ロケールはコンソールではほとんど使われないが、離れた場所からのログインあるいはバッ

チ処理の場合、Cロケールは既定値になっているかもしれないことに注意せよ。

複数のサブアーキテクチャ: 複数のサブアーキテクチャをサポートするシステム (主にWindows と Mac OS X) では、R CMD checkはすべてのサブアーキテ

クチャで利用可能なコンパイルされたコードを含むパッケージのインストール

とチェックを行うであろう。(コンパイルされたコードがないパッケージ、そうでなければ主なサブアーキテクチャでのみチェックされたパッケージに対して

は、これを強制するためにオプション--force-multiarchを使用せよ。)これはロードテスト、例と testsディレクトリをインストールされた各サブアーキテク

チャで順に実行し、もし失敗すればエラーを出す。環境変数 (おそらく PATHを

含め)が各サブアーキテクチャで異なって設定される必要がある場合、これらはR_HOME/etc/i386/Renviron.siteのようなアーキテクチャに特有なファイルに

設定することができる。

別のアプローチは第一のサブアーキテクチャに対しチェックするために、R CMD

check --no-multiarchを使い、次にサブアーキテクチャとは異なるだけの追

加のサブアーキテクチャだけをチェックする動作のために、R --arch=x86_64

CMD check --extra-archや (Windows)/path/to/R/bin/x64/Rcmd check

--extra-archのようなものを使用するということがある。

1.3.2 パッケージの tar書庫をビルドする

パッケージは “tarballs”(.tar.gzファイル)というソース形式、あるいはバイナリ形式で配布されるだろう。ソース形式は適切なツールと共にすべてのプラットフォームにインストール

することができ、Unix系のシステムでは通常の形式である; バイナリ形式はプラットフォームに特有で、WindowsやMacプラットフォームにおいては、より一般的な配布形式である。

R CMD build、Rパッケージビルダーを用いることで、Rパッケージの tar書庫をソースからビルドすることができる (例えば後続のリリースのため)。

実際にパッケージを標準的な gzipで圧縮された tarファイル形式でビルドする前に、2~3の診断チェックとクリーンアップが行われる。特に、オブジェクトの索引が存在しているか、オ

ブジェクトが最新のものであると見なせるかどうかがテストされるC、C++と FORTRANのソースファイルと関係のあるmakefileはテストされ、必要であれば行末は LFに変換される。

パッケージが正しく動作するかどうかのランタイムチェックは最後のビルド手順を起動す

る前に R CMD checkを用いて行われる。

ファイルがパッケージに入れられるのを除外するために、ソースディレクトリの最上位の

.Rbuildignoreというファイルに除外するパターンの一覧を明記することができる。これら

のパターンは Perlライクな正規表現 (正確な詳細についてはRの regexpのヘルプを見よ)にするべきで、パッケージのソースディレクトリに相対的なファイル名 30に対してマッチ 31さ

せたいものを 1行につき 1つ書く。加えて、ソース管理システム 32あるいは eclipse33が提

供するディレクトリ、.Rcheckで終わる名前、あるいは Old、oldという名前を持つディレク

トリ、GNUMakefileと Read-and-delete-meというファイル、あるいは ‘.#’で始まるか、始まりと終わりが ‘#’であるか、終わりが ‘~’、‘.bak’あるいは ‘.swp’である基底ファイル名は初期

30 R 2.13.0からはディレクトリ名を含む: それより前のバージョンでは、空でないディレクトリの名前を受け入れていた。

31 Windowsでは大文字小文字の区別をしない。32 CVS、.svn、.arch-ids、.bzr、.git(.gitと呼ばれるファイルではない)、あるいは.hgと呼ばれている。33 .metadataと呼ばれている

Page 39: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 33

設定では除かれる。さらに R CMD checkでフラグが立てられた R、demoと manディレクトリの

中にあるファイルで、妥当でない名前を持つものは除外される。

Rパッケージビルダーの使用方法についてより詳細な情報を得るためには R CMD build

--helpを使用せよ。

R CMD buildが--no-vignettesというオプション 34 を伴って起動しない限り、パッケー

ジ中のビニェット (see Section 1.4 [パッケージのビニェットを書く], page 35)を再ビルドしようとする。そうするために、一時的なライブラリツリーに現在のパッケージをインストール

するが、任意の依存パッケージは利用可能なライブラリツリーにインストールされている必

要がある (この節の最初の注意を見よ)。

同様に、もし.Rdドキュメントファイルが任意の\Sexprマクロ (see Section 2.12 [動的なページ], page 73)を含んでいるのであれば、パッケージは一時的にインストールされ実行されるであろう。ビルド時のマクロを含むそれらのページの実行後のバイナリのコピーは

build/partial.rdbに保存される。もし、インストール時あるいはレンダリング時のマクロ

があるのであれば、パッケージマニュアルの.pdf版はビルドされ、build/サブディレクトリ

にインストールされる。(これにより CRANや他のリポジトリがパッケージをインストールで

きなくても、それらがマニュアルを表示することを許す。)これは--no-manualというオプ

ション、あるいはパッケージの記述に ‘BuildManual: no’あるいはそれと同様なものによって抑制することができる。

R CMD buildの動作に関するチェックの 1つに空のソースディレクトリがある。大抵そのような場合 (だがすべてではない)は意図していないものであるが、もし意図的なものであれば、オプション--keep-empty-dirsを使用せよ (あるいは環境変数_R_BUILD_KEEP_EMPTY_

DIRS_を ‘TRUE’に設定するか、DESCRIPTIONファイルの ‘BuildKeepEmpty’フィールドを trueにせよ)。

--resave-dataオプションは dataディレクトリに保存されたイメージ (.rdaと.RDataファ

イル)の大きさを最適化することができる。また表形式のファイルを圧縮し、.Rファイルを

イメージに変換する。no、gzip(オプションが提供されていないときの既定値で、環境変数_R_BUILD_RESAVE_DATA_を設定することによって変更できる)、best(値を指定せずに与えるのと同等)という値をとることができ、もっとも効率的な圧縮を選ぶ。もし他のファイルに対し、bzip2あるいは xzの圧縮が選択されているのであれば、bestを使うことは R(>= 2.10)へ

の依存を DESCRIPTIONファイルに加える。もしこれが望ましくないと考えられているのであ

れば、--resave-data=gzip(オプションが提供されていないときの既定値)を用いることでgzipがするような圧縮を行うでしょう。パッケージはどのようにパッケージのデータが保存

されるかを DESCRIPTIONファイル中の ‘BuildResaveData’フィールド (この段落の早い段階で与えられた値の中の 1つを伴って)を与えることで制御することができる。

--compact-vignettesオプションは inst/doc(とそのサブディレクトリ)中の PDFに対し可逆圧縮をする tools::compactPDFを動作させる。これは既定値では可能ではな (環境変数_R_BUILD_COMPACT_VIGNETTES_によって選択することができる)く、利用可能にするためには qpdf(http://qpdf.sourceforge.net/)が必要である。

構築された tar書庫に R CMD check --check-subdirs=yesを実行することは、内容に対

する最終確認として役に立つことができる。

R 2.13.0以前では、R CMD buildは供給されたソースディレクトリの中でいくらかの後片

付けをしていたが、これは文書化されておらず、現在ではされていないことに注意。

34 あるいはパッケージの記述に ‘BuildVignettes: no’あるいは似たようなものを含んでいる

Page 40: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 34

R CMD buildは圧縮された tar書庫を生成することができる、適切な tarプログラムを必要

とする: ほぼ確かにUnix系の環境上 (とプログラムを含むWindowsのツールセット)ではRを設定するときに見つけられるであろうが、もし問題があるのであれば、環境変数 TARを適切

なプログラムのパスに通すか、もしどれも利用可能でないということであれば、"internal"

を設定せよ。

1.3.3 バイナリパッケージをビルドする

バイナリパッケージはパッケージのインストールされたバージョンの圧縮されたコピーであ

る。バイナリパッケージはC、C++あるいは Fortranのソースコードというよりもむしろ、コンパイルされた共有ライブラリを含み、Rの関数はインストールされた形式に含まれている。フォーマットとファイル名はプラットフォームに特有なものである; 例えば、Windows用のバイナリパッケージは通常は.zipファイルとして供給されており、Macプラットフォームではバイナリパッケージの拡張子の既定値は.tgzである。

パッケージをビルドする推奨された方法は次のものを利用することである。

R CMD INSTALL --build pkg pkgはソースとなる tar書庫の名前 (通常は.tar.gz形式)か、ビルドするパッケージのソースがあるディレクトリの位置のどちらかである。

R CMD INSTALL --buildはまずパッケージをインストールし、それから特定のプラットフ

ォームに対し、インストールされたバイナリを適切なバイナリパッケージに詰め込む動作を

する。

初期設定では、R CMD INSTALL --buildは、ローカルインストールの場合、既定値のライ

ブラリツリーにパッケージをインストールしようとする。これは 2つのことを意味している:

• もしインストールが成功すれば、存在している同じパッケージのすべてを上書きする。• 既定値のライブラリツリーは書き込み権限を持たなければならない; もしもっていなければ、パッケージはインストールされず、バイナリは作成されない。

現在動いているインストールしたものが変更されるのを防ぐため、あるいは書き込みアクセ

ス権があるインストールロケーションを与えるためには書き込みアクセス権を持った適切な

位置のディレクトリを作成し、選択した位置にパッケージをビルドするよう-lというオプショ

ンを使用せよ。すなわち、使用方法は次のようになる。

R CMD INSTALL -l location --build pkg

ここで、locationは書き込みアクセス権をもつ選ばれたディレクトリである。パッケージは

locationのサブディレクトリとしてインストールされ、パッケージのバイナリは現在のディ

レクトリに作成される。

R CMD INSTALLの他のオプションは R CMD INSTALL --helpを使うことで見つけることがで

き、プラットフォーム特有の特別な場合 (e.g. Mac OS Xで Fortranのソースを扱うこと)は、プラットフォーム特有の FAQで議論されている。

Rの初期のバージョンでは、R CMD build --binaryはパッケージのバイナリバージョン

をビルドすることができたが、今ではこの手法は R CMD INSTALL --buildが支持されており、

推奨されていない。

最後に、少なくとも 1つのwebをベースにした、(チェックされた)ソースコードからバイナリパッケージをビルドするサービスが利用可能である: WinBuilder(http://win-builder.r-project.org/を見よ)はWindowsバイナリをビルドすることができる。これはWindowsにアクセスできないが、Windowsのプラットフォームにバイナリを提供したいと思っている開発者を意図したものであることに注意。

Page 41: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 35

1.4 パッケージのビニェットを書く

Rd形式で書かれたヘルプファイルに加え、Rパッケージは任意の他の形式のドキュメントを含めてもよいことになっている。それらの標準的な配置はソースパッケージのサブディレクトリ

inst/docであり、パッケージがインストールされたときに、内容はサブディレクトリ docに

コピーされる。パッケージのヘルプインデックスからインストールされたドキュメントへのポ

インタが自動で生成される。inst/docの中にあるドキュメントは任意の形式でよいが、しか

しながら、PDF形式で提供することを推奨しており、そのためほぼすべてのプラットフォームのユーザは容易にそれらを読むことができる。ドキュメントがブラウザからのアクセスで

きることを確実にするために (HTMLの索引が提供されるので)、ファイル名は ASCII文字で

始まり、全体はASCII文字、数字、ハイフン、あるいはアンダースコアから構成されるように

するべきである。

特別な場合に、Sweave 形式のソースを使用した package vignettes と呼ばれる PDF ドキュメントがある。R 2.14.0以降の Sweaveソースの好ましい位置は、ソースパッケージのvignettesサブディレクトリであるが、Rの初期のバージョンとの互換性のため、ビニェットのソースが vignettesに存在しない場合、inst/docも探索される。

ビニェットのソースは、通常は.Rnwあるいは.Rtexという拡張子が与えられているが、歴

史的な理由から、.Snwと.Stexという拡張子 35もビニェットとして認識されている。Sweaveは LATEXドキュメントの統合を認めている: 詳細は文書形式で書かれた Rの Sweaveのヘル

プページとパッケージ utilsの Sweaveビニェットを見よ。パッケージのビニェットは、R CMD

checkがビニェットが含むすべてのRコードの塊を実行することでテストされる (eval=FALSEというオプションがつく場合は除く)。R CMD checkの最中のすべてのビニェットのテストに対

するRの作業ディレクトリは、ビニェットのソースディレクトリの copy である。Rコードを走らせる必要があるビニェット中のすべてのファイル (データセット、. . . )はソースパッケージの inst/docの階層に置くか、あるいは system.file()の呼び出しのどちらかによりアク

セス可能にするようにせよ。ビニェットの PDFを再生成するのに必要とされる他のすべてのファイル (LaTeXスタイルファイルやBiBTeX入力ファイル、ビニェットの中にあるコードを実行しても生成されない画像ファイルのようなもの)はビニェットのソースディレクトリになければならない。

R CMD buildは自動的に 36パッケージソースと一緒に配布するためのビニェットのPDF版を inst/docに作る。パッケージソースの中に PDF版を含めておくことで、インストール時にビニェットの PDFを再ビルドする必要がない。つまりパッケージの作者は当人のマシン上でのみ利用可能な、私的な Rパッケージ、スクリーンのスナップショットと LATEXの拡張機能を使うことができる。37

初期設定では、R CMD buildは、vignettesにある Sweave形式のすべてのファイルについて Sweaveを実行し、あるいはもし vignettesフォルダが無いようであれば、inst/docにあ

るファイルに対してそれを実行する (ただし、サブディレクトリに対しては実行しない)。もし inst/docディレクトリに Makefileが見つからなければ、tools::texi2dvi(pdf = TRUE)

がすべての処理されたビニェットに対して実行される。Makefileが見つかるときはいつも、R

CMD buildは Sweaveを実行した後に makeを実行しようとするであろう。Makefileの最初の

ターゲットはPDFファイルの生成と始末の両方について注意するべきである (Sweaveの後を

35 大文字と小文字を区別しないファイルシステムにまつわる問題を回避するため、これらすべての拡張子が小文字のバージョンも認識される

36 DESCRIPTIONファイルに ‘BuildVignettes: no’と書いて抑制しない限り37 ただしパッケージのライセンスの条件が満たされている場合に限る: 多くの人はこれらはオープンソースライセンスと不適合であると感じるであろう。

Page 42: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 36

含む)。つまり、最後のパッケージアーカイブに現れないすべてのファイルを削除するということである。もし makeの段階でRを実行するのであれば、環境変数 R_LIBSと R_HOMEの値を

尊重するよう気をつける必要がある 38。最後に、もし Makefileがあり、それに ‘clean:’ターゲットがあるのであれば、make cleanが実行される。

Makefileを含むことについて、すべての普通の警告が当てはまる。移植可能であり (GNU

拡張はなし)、並列 makeを利用しても動作しなければならない: あまりも多くのパッケージの作者が以下のように書いてしまっている。

## BAD EXAMPLE

all: pdf clean

pdf: ABC-intro.pdf ABC-details.pdf

%.pdf: %.tex

texi2dvi --pdf $*

clean:

rm *.tex ABC-details-*.pdf

これはソースファイルを除去することを始める一方で、pdflatexが動作している。

inst/docにビニェットから生成されるRコードのファイルを含めることは、パッケージがインストールされる際にそれらを再生成するので無意味 (でありファイルが古くなるかもしれず潜在的に誤解を招く)であるということに注意 (ビニェットがRのコードを生成しない場合を除いても、無意味で、誤解を招く)。

メタデータ行はソースファイル中に置くことができ、前文のLaTeXコメントにあるのが好ましい。そのようなものの 1つに\VignetteIndexEntryという次のようなフォームがある。

%\VignetteIndexEntry{Using Animal}

他 に 見 る か も し れ な い も の は\VignettePackage(現 在 は 無 視 さ れ て い る)、\VignetteDependsと\VignetteKeyword(\VignetteKeywordsか ら 置 き 換 わった) が

ある。これらはパッケージのインストール時に Meta/vignette.rdsという保存された

データフレームを生成するために処理されるが、今のところ\VignetteIndexEntryと

\VignetteKeywordの命令のみが使用されている。

インストール時に、パッケージ中のすべてのビニェットに対するHTMLのインデックスは、

inst/docディレクトリに index.htmlファイルが存在しない限り、\VignetteIndexEntryと

いう命令から自動的に生成される。このインデックスはパッケージのHTMLヘルプのインデッ

クスからリンクされている。もし inst/doc/index.htmlを供給するのであれば、docディレ

クトリにインストールされたファイル、おそらく (本当にインデックスではない)HTMLヘルプファイル、あるいは DESCRIPTIONファイルに限った相対リンクを含むべきである。

Sweave/Stangleはそれぞれのコードの塊に対し、1つのRファイルを生成するために、ドキュメントに split=TRUEというオプションを明記することを許している: オプションは各ビニェットソースが.Rにビニェットの拡張子が置き換えられるファイルを生成すると仮定されて

いるビニェットに対しては動作しない。

PDFが大きくなりすぎないことを監視するようにせよ – CRANパッケージにあったものに

は 72MBに達するものがあった!これは通常は PDFビューアでも上手く描写されないような

38 R 2.13.0以降、Makefile中の Rあるいは Rscriptが現在実行しているバージョンの Rを使用することができるように、R_HOME/binは PATHの先頭に付けられている

Page 43: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 37

過度に精細な図を含んでいることによって引き起こされる。ときにはかなり高解像度のビッ

トマップ (PNG、JPEG)を生成し、それらを PDFドキュメントとして含めるのがよりよいということもある。

R CMD buildがビニェットPDFをビルドしたときには、それらと vignettesディレクトリ

からのビニェットソースを inst/docにコピーされる。vignettesディレクトリからの他のファ

イルをインストールするためには、Perlライクな正規表現で 1行あるいはそれ以上の行で明記した vignettes/.install_extrasというファイルを含めるようにせよ。(完全な詳細については.Rinstignoreファイルの記述を参照せよ。)

1.4.1 エンコーディングとビニェット

PDFのビニェットは通常は説明文、Rの入力、Rの出力と図、ファイルと参考文献を含んだLATEXを含んでいる。これらは非ASCII文字を含むかもしれないので、エンコーディングの扱いがとても複雑になりうる。

ビニェットソースファイルはASCIIで書かれるか、あるいはエンコーディングの宣言を含むべきである (以下を見よ)。これは Sweave()がオプションとメタデータの行を探すためにコ

メントを処理するので、ソースファイルのコメントに対しても適用される。Sweave()あるい

は Stangle()がビニェットソースで呼ばれたとき、ソースは現在のRセッションのエンコーディングに変換 39されるであろう。

Stangle()は現在のロケールのエンコーディングでRのコードファイルを作成する: ファイルの先頭にあるコメントに記録されている、非ASCIIのビニェットのためである。

Sweave()は現在のロケールのエンコーディングで.texファイルを作成する。これはLATEXに対し以下のような行を利用して宣言する必要がある。

\usepackage[utf8]{inputenc}

R CMD checkはこのような宣言が含まれていないと分かった任意の非ASCIIのビニェットに対して警告するであろう。この問題は事前には分かることができないということで、PDFのビニェットはパッケージの作者自身のマシンにおいてのみ再生成が可能であるということであ

る。R CMD checkはこのような宣言が含まれていないと分かった任意の非ASCIIのビニェットに対して報告するであろう。(これはより最近の ‘inputenx’ LATEXパッケージを使うことでもできる。)

Sweave()は各Rコードの塊を解釈、評価することもする。Rの出力も現在のロケールになり、‘inputenc’宣言によってカバーされているべきである。人々がよく忘れることの 1つに、Rの出力は、多くの可能性がある理由から、RのソースがASCIIであったとしてもASCIIにならないということがある。一般的なことの 1つに、‘凝った’引用の利用がある: Rのヘルプの sQuoteを見よ: そのような引用符をカバーしようとして UTF-8あるいは CP1252を宣言することは、引用符のエンコーディングが Sweave()を実行するために使用されたロケールに

依存しているので、移植可能にはならないということに、慎重に注意せよ: これはビニェットに options(useFancyQuotes="UTF-8")を設定することによって回避することができる。

図のエンコーディングに関わる最後の問題 – これはPDFの図にのみ当てはまり、PNGなどには当てはまらない。PDFの図はエンコーディングの宣言を含んでいるが、Sweaveのオプション pdf.encodingは適切に設定される必要がある: pdf()グラフィックスデバイスのヘルプを参照せよ。

複雑なことの実際の例として、fortunes (http: / / CRAN . R-project . org /

package=fortunes)パッケージのバージョン ‘1.4-0’を考える。そのパッケージはエンコー

39 ただし、エンコーディングが分かっているという場合に限る: 現在のところ、もしエンコーディングが分かっていない場合は Latin-1であると推測される。

Page 44: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 38

ディングが宣言されておらず、ビニェットは ASCII で書かれている。しかしながら、パッケージが表示するデータは UTF-8の CSVファイルから読み込まれており、現在のエンコーディングであることが仮定されているので、fortunes.texは任意のロケールで UTF-8になるであろう。read.tableがデータが UTF-8であると教えられていたら、fortunes.texは

ロケールのエンコーディングになっていたであろう。

1.5 CRANにパッケージを提出する

CRANはRディストリビューションと有用なコード、特にRのパッケージを保持するWWWサイトのネットワークである。Rのユーザは共同プロジェクトに参加することとパッケージを CRANに提出することを奨励されている。

mypkgを提出する前に、http://CRAN.R-project.org/web/packages/からリンクされ

た CRANのポリシーを読むことと、パッケージを提出するまでに、パッケージがそのポリシーに適合していることを確認していることに注意せよ。もし CRANにとって新しいパッケージであれば、提出メールでポリシーを読んで、それに同意することを確認せよ。

次に、パッケージが完全でインストールが適切にすることをテストする以下のステップを

実行せよ。(mypkgをサブディレクトリとして含むディレクトリから実行せよ。)

1. リリースする.tar.gzファイルを作る R CMD buildを実行せよ。

2. .tar.gzファイルに対しパッケージがインストールと例を実行し、ドキュメントが完全

で処理できるものであるかを確認するための R CMD check --as-cranを実行せよ。もし

パッケージがコンパイルされる必要があるコードを含んでいるのであれば、例えばGCC、GNU Compiler Collectionからのツールの-Wall -pedanticのように、コンパイル時に

理にかなった量の診断メッセージ ((“warnings”)を有効にしようとせよ。もし Rがそれに応じて設定されなかったら、それを個人の Makevarsファイルによって達成することが

できる。

C++のコードに-Wall -pedanticを使うのは特に重要であることに注意: GNU C++コンパイラは他のコンパイラがサポートしていないような拡張を持っており、それらのいく

つかを報告してくる (可変長配列の誤用など)。もし可能であれば、C++コードを標準に準拠したコンパイラでチェックせよ。

C++標準の 2011年バージョンがあるのだが、まだ実装されておらず (何年かは広く使われることはないであろう)、移植性のある C++のコードは 1998年の標準に従う必要がある (そして C99からの特徴は使用しない)。

同様に、2011年の Cの標準は数年の間は広く実装されないであろう。

3. ファイル mypkg.Rcheck/mypkg-Ex.Routにある、例を実行した出力を検討せよ。しばし

ば警告は実際のエラーを示唆しており、(Rの開発者はあなたのために問題に取り掛かっているということを注意する)間違いについての警告は、ユーザに対し困らせる、あるいは混乱させるだけであろう。

もし、パッケージがテストあるいはビニェットを持つのであれば、それらの出力につい

ても検討せよ。

4. ヘルプファイルの変換に関わる問題について探せ。例えば以下のようなことをするべきである。

• R CMD checkによって生成された、mypkg.Rcheck/mypkg-manual.pdfにある PDFマニュアルを読み通る、あるいは R CMD Rd2pdf mypkgによって生成された別のコ

ピーを作成する。

• R内部からテキストで書かれたヘルプページの描画を見る。

Page 45: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 39

R 2.10.0ではヘルプの描画の多くの面で変化があり、特にコメント行の解釈が変わっている (空行として描画されるので、コメント行をテキストの段からの途中に置いてはならない)。

5. パッケージソースが不必要に大きくならないことを確実にせよ。特に、R CMD checkは

5Mbを超えるパッケージ、1Mbを超えるディレクトリの詳細について報告 40するであ

ろう。R CMD checkはデータの非効率な圧縮について警告する: R CMD build --resave-

dataは、できる限りデータを圧縮する。

inst/doc中の不必要なファイルについて注意せよ: R CMD checkはインストールされた

であろう種類のファイルに注意するが、PDFの図と PDFのドキュメントの区別はできない。もし inst/docに入れる必要はあるが、インストールする必要がないファイルがあ

れば、.Rinstignoreファイルを利用せよ。

CRANのポリシーは docディレクトリは 5Mbを超えるべきではなく、dataディレクトリを 5–10Mbより大きくする必要があるというものであり、データだけを含む個別のパッケージに対し、考慮がなされるべきである。(外部のデータディレクトリ、インストールする必要がある大きな jarファイルと他のライブラリについても同様である。)

ビニェットのようなPDFファイルのサイズを小さくする方法については以下を参照せよ。

6. パッケージのチェックが必要とされているよりも時間がかからないことを確実にせよ(CRANのチェックファームは数千のパッケージに共有されている資源である)。

パッケージのチェックにおいてかなりの時間がかかっている箇所を見つける方法につい

ては以下を参照せよ。

理解しており、取り除く必要がない警告のみからなる一連の手順を確実に実行できるように

していただきたい。原則として、パッケージは R CMD checkを警告、あるいはメインのCRAN

パッケージエリアで認められている重要な注意事項なしでパスしなければならない。もし警

告や取り除けない注意事項がある場合 (例えば、警告や注意事項が誤っていると思っている場合)、カバーする電子メールの一部に注記を送付せよ。

すべてのテストがされたら、ログイン名に ‘anonymous’、パスワードに自身の e-mailのアドレスを使って ftp://CRAN.R-project.org/incoming/にログインして.tar.gzをアップロー

ドし (注意: このサーバへの接続には ‘sftp’ではなく、‘ftp’41を利用し、パッシブ ‘ftp’がよりしばしば成功する)、[email protected]にそのことについてメッセージを送付する (パッケージの名前とバージョンを “CRAN submission ‘package’‘version’”という形式の subjectに含めて。emailで提出するのはやめていただきたい)。新しい提出であれば、メッセージにCRANのポリシーを読んだことと同意したことを記録して欲しい。

CRANのメンテナは提出物をオンラインに置く前にこれらのテストを実行する。(メンテナはRの最新の開発版を利用するであろうから、もし可能であれば、自身でもそのようにするべきである。)

[email protected]へのメールが伴わない提出は処理されないであろうということ、

CRANチームのメンバーへの個人的な emailの送付はするべきではないということに注意していただきたい。

40 POSIXに準拠する duプログラムがシステム上に見つかった場合に限る: 他の duプログラムは実際のサイズの 2倍の値を誤って報告してくる可能性がある。これは_R_CHECK_PKG_SIZE_を falseに設定することによって無効にすることができる。

41 Windowsユーザにとって Internet Explorerでその URLを開くのに一番単純と思われる方法であり、(バージョンに依存して)フォルダとして URLを見るための指示に従い、それからフォルダに提出物をコピーする。

Page 46: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 40

LATEXを実行するために、Debian GNU/Linux CRANチェックシステムはDebian TeXLive42

ディストリビューション (http://packages.debian.org/en/sid/texlive)を使っていることにも注意せよ; Fedoraと Solarisのチェックシステムは現在の TexLiveを使っている;Windows CRANビルダは比較的新しいバージョンのMikTeXを使っている (MikTexが直接に利用可能なパッケージをすべて含む); Mac OS Xビルダは現在のTeXLiveをすべて含んだMacTeXの現在のフルバージョンを利用している。TEXパッケージあるいはこれらのディストリビューションに (まだ)含まれていないスタイルファイルを使うビニェットが欲しい開発者はスタイルファイルをパッケージのサブディレクトリ vignettes(あるいは従来のレイアウトのために inst/doc)に加えるべき 43である。

1.5.1 PDFのサイズ

Adobe Acrobat(Readerではない)、AppleのPreview44、qpdf (http://qpdf.sourceforge.net/)とGhostscript(PDFを次のコマンドで別の PDFに変換する

ps2pdf options -dAutoRotatePages=/None in.pdf out.pdf

そして、適したオプションは次のようであろう。

-dPDFSETTINGS=/ebook

-dPDFSETTINGS=/screen

も、商用、シェアウェアのWindowsプログラムも含め、PDFファイルのサイズを小さくするためのツールはいくつかある (画像のダウンサンプリングに対し、さらにそのようなものやオプションを検討するには http://www.ghostscript.com/doc/9.04/Ps2pdf.htmを参照せ

よ)。これらはすべて同様のサイズ削減戦略を取ろうとはせず、Acrobatと ps2pdfは、埋め

込まれたビットマップ画像のサイズをもっとよく減らすことができることもあり、ps2pdfは

PDFオブジェクト圧縮をしようしないということには注意 (下記参照)。

qpdfはかなり容易に利用できる (例えば、Windows用のバイナリとDebian/Ubuntuにはパッケージがあり、Rの CRAN Max OS Xディストリビューションの一部としてインストールされている)ため、R CMD buildには、inst/doc以下にあるPDFファイルに対して qpdfを

実行するための--compact-vignettesというオプションがあり、少なくとも 10Kbのファイルサイズがあれば置き換えられ、10%以上圧縮される。qpdfコマンドの完全パスは、環境変

数 R_QPDFとして供給される (コマンドはMac OS X用のCRANのRバイナリにある)。このオプションは ‘qpdf’(既定値)の他にも、‘gs’あるいは ‘both’という値をサイズを厳しく減らそうとする目的でとることができる。これらは 250Kbを超える PDFファイルがあるパッケージに対し、CRANに提出する前に必ず試すべきである: ‘gs’はビットマップ画像のダウンサンプリングのように不可逆変化をするかもしれないので、結果を確認し、必要があれば ps2pdf

あるいは tools::compactPDFを直接利用せよ。

これまでに見てきたものでサイズの大きな PDFの大半は、例えば Rの複雑な図 (.pngの画像がより適切であり、R 2.14.0より前では pdf()は PDFの圧縮をしていないため、PDFファイルを再生成するのは役立つかもしれない)や画面のダンプといった図を含んでいるから大きいというのが理由である。しかしながら、pdftexの設定が不必要に大きくしていると

いうものもある。今のデフォルトはPDF圧縮とPDFオブジェクト圧縮 (2003年以降のPDFバージョン 1.5を必要とする)の両方を使う: これは大部分のTEXディストリビューションでは初期設定であるが、MikTeXではそうではない。設定は Sweaveあるいは LATEXファイルの

42 現在では長く時代遅れな TeXLive 200943 もしライセンスが許すのであれば: これはしばしば対応する.dtxファイルを含めることを要求する。44 ‘Save as’を選択し、‘Quartz filter’メニューから ‘Reduce file size’を選択せよ: アクセスするにはいくつかの方法があり、例えば Automatorによる方法がある。

Page 47: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 41

前文にあるコードによって上書きできる: これがどのようにされるかは、Rリファレンスのhttps://svn.r-project.org/R/trunk/doc/manual/refman.topを見よ。

1.5.2 パッケージの計時

チェックの過程において、どこで時間が使われているかを見つけるにはいくつかの方法があ

る。環境変数_R_CHECK_TIMINGS_を ‘0’に設定して開始せよ。これは各サブアーキテクチャにおいて適切な場合、インストールと例、テスト、ビニェットの動作に対するCPU時間の合計(Windowsではない)と経過時間を報告する。テストとビニェットに対しては、それぞれと合計の時間を報告する。

_R_CHECK_TIMINGS_を非 0の値に設定することは、計時の報告に対する閾値 (経過時間の秒数)を設定することになる。

もし例に対する計時の詳細を見る必要があるのであれば、R CMD checkに--timingsとい

うオプションを使用せよ。これは mypkg.Rcheck/mypkg-Ex.timingsと呼ばれる、各ヘルプ

ファイルに対する計時を含むファイルを生成する (system.time()によって与えられる)。更なる分析のためRで読めるよう、タブ区切りのファイルになっている。

テストとビニェットの計時は対応するログファイルの一番最後で与えられる。上手くいっ

たビニェットの実行に対するログファイルは、_R_CHECK_ALWAYS_LOG_VIGNETTE_OUTPUT_が

trueに設定されている場合に限って保持される。

1.5.3 Windowsの外部ソフトウェア

CRANはコンパイル済みのバイナリの提出をセキュリティ上の懸念から受け付けず、ソース

パッケージ中のバイナリ実行形式を許していない。CRANにあるパッケージのWindowsバイナリに追加のソフトウェアを必要としているメンテナは、以下の 3つの選択を持つ。

1. 例えばパッケージCairo (http://CRAN.R-project.org/package=Cairo)がしているように、インストールするパッケージがURLから外部のソフトウェアをダウンロードするように準備する。

2. WinBuilder に追加コンポーネントをホストしてくれるよう Uwe Ligges に交渉し、configure.winに追加コンポーネントをインストールするよう書く。例えばパッケージ

rgdal (http://CRAN.R-project.org/package=rgdal)のように、多くの例がある (しかしながら、最近 CRANはGDALのように均一なクロスコンパイルアプローチを使うことを好んでいる)。

3. BRugsのバージョン versions 0.5-xがそうされたように、Brian Ripleyに CRAN extrasにパッケージをホストしてくれるよう交渉する。

すべての場合においてライセンス用件は満たされる必要があり、追加のコンポーネント (および、パッケージがGPLのようなライセンスを持つ場合)のためにソースを用意する必要があるかもしれないということに注意せよ。

Windows用の Rの 32と 64ビットのビルドは両方ともバイナリパッケージを組み合わせたディストリビューションなので、CRANチームは 1つのアーキテクチャでのみ動作するようなパッケージのサポートはしたがらないということにも注意せよ。

1.6 パッケージの名前空間

Rはパッケージ中のコードに対する名まえ空間管理システムを持つ。このシステムはパッケージの書き手に、パッケージのどの変数をエクスポートしてパッケージユーザが利用できるよ

Page 48: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 42

うにするかと、他のパッケージからどの変数をインポートするべきかということを明記する

ことを許している。

パッケージの名前空間を明記する仕組みは NAMESPACEファイルをパッケージディレクトリ

の一番上に置くことである。このファイルは名前空間のインポートとエクスポートを記述す

る名前空間ディレクティブを含んでいる。付加的なディレクティブはロードされた任意の共

有オブジェクト、提供されているすべての S3スタイルのメソッドを登録する。ファイルはRコード (としばしばRスタイルのコメントを持っている)のように見えるのだが、Rのコードとして処理されないことに注意。ほんとうに簡単な if文の条件処理だけが実装されている。

libraryあるいは requireの呼び出すことによってパッケージはロードされ、サーチパス

にアタッチされる。エクスポートされた変数だけが、アタッチされたフレームに配置される。

他のパッケージから変数をインポートするパッケージをロードすると、他のパッケージも同様

にロードされる (既にロードされていない限り)が、これらの暗黙的なロードでは、パッケージはサーチパスに配置されることはない。

名前空間は一旦ロードされると密封される。密封というのは、インポートとエクスポート

されたものは変えられず、内部変数のバインディングが変えられないということを意味する。

密封は名前空間機構に対し、より簡単な実装戦略を可能にする。また密封はコード分析とコ

ンパイルツールが関数本体のグローバル変数の参照に対応する定義を正確に確認することを

可能にしている。

名前空間はパッケージにある関数によって使われている変数を探索する戦略を制御してい

る。もしローカルに見つからなければ、Rはパッケージ名前空間を最初に探索し、インポートしたもの、baseの名前空間、通常のサーチパスの順に探索する。

もし NAMESPACEファイルが存在していなければ、NAMESPACEはパッケージがビルドあるい

はインストールされたときに自動的に生成され、すべてのオブジェクトがエクスポートされ、

DESCRIPTIONファイル中にある ImportsあるいはDependsフィールドにあるすべての一覧にあるパッケージがインポートされる。これはパッケージは NAMESPACEファイルを持つよう変

換され、やがて削除される間の一時的な措置のみを意図している。NAMESPACEファイルを持

たない既存のパッケージは手作りの NAMESPACEファイルを加える必要がある。

バージョン 2.14.0より前では、名前空間はパッケージ内で任意であった。そのようなパッケージでは、非ローカル変数の探索はサーチパスから始めるので、パッケージ独自の関数は

先に現れたパッケージによって覆い隠される可能性があった。

R 2.14.0からすべてのパッケージは名前空間を持ち、ソースのなかに NAMESPACEファイル

がなければ、インストール中に初期設定の NAMESPACEが生成されるようになった。しかしな

がら、すべてのRのバージョンが、パッケージにRコードが含まれていなければ NAMESPACE

を読むわけではない。

1.6.1 インポートとエクスポートの指定

エクスポートは NAMESPACEファイルに exportの指示を書くことで指定される。以下の指示

export(f, g)

は変数 fと gがエクスポートされることになることを指定している。(変数名は引用符で囲まれるかもしれず、予約語と [<-.fractionsのような非標準的な名前は引用符で囲われなけれ

ばならないことに注意。)

多くの変数を持つパッケージにとって、exportPatternを用いて正規表現でエクスポート

する名前を指定するのは便利である。次の指示

exportPattern("^[^\\.]")

Page 49: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 43

はピリオドで始まらないすべての変数をエクスポートする。しかしながら、そのような広い

パターンは作成したコードに対して推奨されない: すべてのエクスポートするもの、あるいは狭く範囲で定義されたグループを利用することを勧める。(R 2.13.0からはこのパターンはS4クラスにも適用するが、Rの初期のバージョンでは適用しない。)ピリオドで始まる名前を含むパターンには気をつけよ: これらのいくつかは内部でのみ使われる変数で、決してエクスポートされるべきではないものである。例えば ‘.__S3MethodsTable__.’が該当する。(そのようなオブジェクトはRの最近のバージョンではパターンマッチから除外されており、そのようなパターンはR 2.14.0以降を使った場合に対してのみ、パッケージにとってより安全なものとなっている。)

パッケージは暗黙のうちに baseの名前空間をインポートする。名前空間を持つ他のパッケージからエクスポートされた変数は importと importFromの指示を利用して明示的にイン

ポートされる必要がある。import命令は明記されたパッケージをからエクスポートされた変

数をすべてインポートする。従って、次のような指示

import(foo, bar)

はパッケージ fooと barの中にあるすべてのエクスポートされた変数がインポートされるということを明記している。パッケージからエクスポートされた変数のいくつかが必要となる

ときのみ、importFromを使ってインポートすることができる。以下の指示

importFrom(foo, f, g)

はパッケージ fooのエクスポートされた変数 fと gがインポートされるということを明記して

いる。

他の名前空間からインポートされた名前空間をエクスポートすることができる。

もしパッケージが他のパッケージからの 2、3のオブジェクトを必要とするのであれば、正式なインポートの代わりに、コード内の完全修飾された変数への参照を使うことができる。

パッケージ fooの中にある関数 fへの完全修飾の参照は foo::fという形式である。これはわ

ずかに正式なインポートよりも効率が低く、NAMESPACEファイルにあるすべての依存関係を

すべて記録することの利点を失うので、このアプローチは通常は推奨されていない。foo::f

を評価することは、パッケージ fooが、もし既にロードされていなければ、ロードされることを引き起こすが、アタッチはされない—これはほとんど使われないパッケージのロードを遅らせるということで利点となりうる。

foo::fの代わりに foo:::fを使うことは、エクスポートされていないオブジェクトへのア

クセスを許可する。エクスポートされていないオブジェクトの動作はパッケージの作者の定

期的なメンテナンスによって変えられるかもしれないので、これは一般的にはは推奨されて

いない。

1.6.2 S3メソッドの登録

S3スタイルの UseMethodがディスパッチする標準的な方法は、インポートされているが検索

パスにアタッチされていないパッケージの中で定義されたメソッドを見つけることに失敗す

るかもしれない。これらのメソッドが利用可能であることを確実にするため、メソッドを定

義しているパッケージは、ジェネリクスがインポートされ、S3method命令を使ってメソッド

を登録することを保証せよ。もじパッケージが fooというクラスの printメソッドとして使

われることを意図して print.fooという関数を定義しているのであれば、以下の指示

S3method(print, foo)

で、メソッドが登録され、UseMethodディスパッチが利用可能であり、関数 print.fooはエク

スポートされる必要がないことを保証する。総称的な printは baseで定義されているので、明示的にインポートする必要がない。

Page 50: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 44

(関数名とクラス名は引用符で囲まれるかもしれず、予約語と [<-や functionのような非

標準的な名前は引用符で囲まれなければならないことには注意。)

1.6.3 ロードフック

パッケージがロード、アタッチ、デタッチ、アンロードされるときに呼ばれるフックがいくつ

もある。詳細は help(".onLoad")を参照せよ。

ロードとアタッチは異なった操作であるので、それぞれに対して別のフックが提供され

る。これらのフック関数は.onLoad、.onAttachと呼ばれている。これらは共に libnameと

pkgnameという引数を取る; 名前空間に定義されるが、エクスポートされてはならない。

パッケージで detachが呼ばれたときに、パッケージは.Last.lib関数を使う (名前空間からエクスポートされているとする)。インストールされたパッケージのフルパスという 1つの引数を伴って呼ばれる。名前空間がアンロードされた (おそらくは detach(unload=TRUE)に

よって呼ばれた unloadNamespaceへの呼び出しから)ときに、引数にインストールされたパッケージディレクトリのフルパスを取って呼ばれる.onUnloadというフックもある。.onUnload

は名前空間で定義され、エクスポートされないべきであるが、.Last.libはエクスポートさ

れる必要がある。

パッケージは.onAttachを必要としそうに無い (おそらく起動時のバナーを除いては); オプションを設定し、共有オブジェクトをロードするコードは.onLoad関数に配置されるか、次

に示されている useDynLibディレクティブを利用するべきである。

ユーザレベルのフックも利用可能である: 関数 setHookのヘルプを参照せよ。

1.6.4 useDynLib

NAMESPACEファイルには、共有オブジェクトがロードされるようにする 1つ以上の useDynLib

ディレクティブを含めることができる。45ディレクティブ

useDynLib(foo)

は、library.dynamにロードするために共有オブジェクト foo46を登録する。パッケージの

コードがロードされた後と、ロードフック関数が動作する前に登録された共有オブジェクト

がロードされることが発生する。共有オブジェクトをロードするのにロードフック関数だけ

が必要となるパッケージは、useDynLibディレクティブを代わりに用いることができる。

useDynLibディレクティブはインタフェース関数.C、.Call、.Fortranと.Externalを通

して、Rで使われるであろうネイティブルーチンの名前を受け入れる。これらはディレクティブへの追加の引数として与えられ、例えば次のようになる。

useDynLib(foo, myRoutine, myOtherRoutine)

useDynLibディレクティブでこれらの名前を指定することで、パッケージがロードされ、シ

ンボルを識別するRの変数がこれらの名前と一緒に名前空間に加えられたときに、ネイティブシンボルは解決される。これらはルーチン名と PACKAGE引数の代わりに.C、.Call、.Fortran

と.Externalの呼び出しで使用される。例えば、Rからルーチン myRoutineを

.Call(myRoutine, x, y)

と呼ぶのではなく、次のように呼ぶことができる。

45 備考: Rのすべてのバージョンで NAMESPACEファイルは、パッケージの Rディレクトリに Rコードを含んでいるときにだけ読まれる。

46 これは共有オブジェクトのベース名であり、適切な拡張子 (.soあるいは.dll)が付け加えられるであろう。

Page 51: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 45

.Call("myRoutine", x, y, PACKAGE = "foo")

このアプローチには少なくとも 2つの利点がある。第一に、シンボルの探索が、ルーチンが呼び出されるたびではなく、各シンボルに対し 1度で済むということである。第二に、いくつかのコンパイルされたDLLにあるであろうシンボルの解決の際に曖昧さがなくなるということがある。

いくつかの環境において、ネイティブシンボルと同じ名前でパッケージ中の変数が存在

しているであろう。例えば、パッケージ中に myRoutineと名づけられたRの関数があったとする。この場合、ネイティブシンボルを異なったRの変数名に写像する必要がある。これはuseDynLibディレクティブで名前付き引数を用いることでできる。例えば、ネイティブシン

ボル名 myRoutineをRの変数 myRoutine_symに移したい場合、次のものを利用する。

useDynLib(foo, myRoutine_sym = myRoutine, myOtherRoutine)

そうすることで、次のコマンドを使ってRからそのルーチンを呼び出すことができる。

.Call(myRoutine_sym, x, y)

明確な名前がないシンボルは、その名前でRの変数に割り当てられる。

いくつかの場合では、パッケージの名前空間内でネイティブルーチンを特定するRの変数を作らないことが好ましいということがある。もし多くのルーチンが使われないのであれば、

パッケージがロードされたときに多くのルーチンに対してRの変数を求めるのにコストがかかりすぎるだろう。この場合、DLLを使って正しくシンボル解決できるが、ルーチンが呼ばれるたびにこれを行う。例えば dllと、Rの変数としてDLLへの参照が与えられると、ルーチン myRoutineを次の式で呼び出すことができる。

.Call(dll$myRoutine, x, y)

$演算子は getNativeSymbolの呼び出しを使って、DLL内の指定された名前のルーチンを解決する。これは上にあるパッケージがロードされたときにシンボルを解決する計算と同じ

である。唯一の違いは、dll$myRoutineの場合はこれが毎回行われるということである。

この動的なアプローチを使うためには (例えば dll$myRoutine)、パッケージ内のRの変数としてDLLへの参照が必要となる。上で利用されたシンボルをRの変数へ写す variable =

dllNameという形式を使うことによって、DLLは変数に割り当てられる。例えば、もし上の例にある fooというDLLに変数 myDLLというDLLの参照を割り当てたいのであれば、NAMESPACEファイルで以下のディレクティブを使う:

myDLL = useDynLib(foo, myRoutine_sym = myRoutine, myOtherRoutine)

そうすれば、Rの変数 myDLLはパッケージの名前空間中にあり、ロード時に明示的に解決

していないルーチンにアクセスする myDLL$dynRoutineのような呼び出しが利用できる。

もしパッケージに登録の情報があれば (Section 5.4 [ネイティブルーチンの登録], page 100を参照せよ)、NAMESPACEファイルの useDynLibディレクティブに再度シンボルの一覧を指定

するのではなく、直接それを利用することができる。登録情報中の各ルーチンは、ルーチン

がルーチンのアドレスやパラメータの数と型のすべての情報と共に指定される名前を与える

ことで指定する。useDynLibの.registration引数を使うことで、名前空間のメカニズムに

そのシンボルに対する Rの変数を作るよう指示を出すことができる。例えば、myDLLと名づ

けられたDLLに対する以下の登録情報を持つと仮定しよう:

R_CMethodDef cMethods[] = {

{"foo", (DL_FUNC) &foo, 4, {REALSXP, INTSXP, STRSXP, LGLSXP}},

{"bar_sym", (DL_FUNC) &bar, 0},

{NULL, NULL, 0}

};

Page 52: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 46

R_CallMethodDef callMethods[] = {

{"R_call_sym", (DL_FUNC) &R_call, 4},

{"R_version_sym", (DL_FUNC) &R_version, 0},

{NULL, NULL, 0}

};

すると、NAMESPACEファイル中の指示

useDynLib(myDLL, .registration = TRUE)

はDLLをロードし、Rの変数 foo、bar_sym、R_call_symと R_version_symをパッケージ

の名前空間中に定義する。

R変数の名前は登録情報のエントリから取得され、ネイティブルーチンの名前と同じにする必要がないことに注意。これは登録情報の作成者が、ネイティブシンボルをRで競合しない変数名に対応付けることを可能にする。例えば、使用のために、次のようにしてRの関数内で R_versionを R_version_symに対応付ける。

R_version <- function()

{

.Call(R_version_sym)

}

引数.fixesを使うことで、既存のパッケージと一緒に動作するときに役立つ可能性がある、

登録されたシンボルに自動的に接頭辞をつけることができる。例えば、パッケージKernSmooth(http://CRAN.R-project.org/package=KernSmooth)の

useDynLib(KernSmooth, .registration = TRUE, .fixes = "F_")

はRの変数を FORTRANのシンボル F_bkdeなどに対応させており、名前空間でRのコードが原因によるクラッシュを避けている。

1.6.5 例

例として、foo、barと名づけられた 2つのパッケージを考えよう。ファイル foo.Rにあるパッ

ケージ fooのRのコードは次の通りである。� �x <- 1

f <- function(y) c(x,y)

foo <- function(x) .Call("foo", x, PACKAGE="foo")

print.foo <- function(x, ...) cat("<a foo>\n") CコードではDLL foo(適切な拡張子を伴って)にコンパイルされるCの関数を定義しているものがある。このパッケージに対する NAMESPACEファイルは次の通りである。� �

useDynLib(foo)

export(f, foo)

S3method(print, foo) 2番目のパッケージ barは次のようなコードのファイル bar.Rを持つ。

Page 53: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 47� �c <- function(...) sum(...)

g <- function(y) f(c(y, 7))

h <- function(y) y+9 そして NAMESPACEは次の通りである。� �

import(foo)

export(g, h) library(bar)を呼ぶと barがロードされ、サーチパスにパッケージのエクスポートしたものがアタッチされる。パッケージ fooもロードされるが、サーチパスにはアタッチされない。g

への呼び出しは次の結果を生成する。

> g(6)

[1] 1 13

これは 2つの設定にある cの定義と一致している: barでは関数 cは sumと同じになるよう定

義されているが、fooでは変数 cは baseの標準関数 cを参照するようにしている。

1.6.6 要約 – 既存のパッケージの変換

要約すると、2.14.0より前のパッケージを名前空間を使用するよう変換することは、いくつかの簡単な段階を伴う。

• 公開する定義を確認し、それらを exportディレクティブに配置する。

• S3スタイルのメソッドの定義を確認し、対応する S3method宣言を書く。

• 依存関係を確認し、importディレクティブによる任意の require呼び出しを置き換える

(そしてDESCRIPTIONファイルのDependsとImportsのフィールドを適切に変える)。file).

• .First.lib関数を.onLoad/.onAttach関数、あるいは NAMESPACEファイル中で

useDynLibディレクティブを使う。

これらの最初の二つは自動的にされるが、パッケージの作者は通常、Rの推測を改良することができる。

R CMD buildは基本的な NAMESPACEファイルをパッケージに加える。もしこれが編集され

たら、最初の行を取り除くようにせよ (ファイルのコメントが言うように)。

1.6.7 S4クラスとメソッドの名前空間

規則に従った (S4 スタイルの) クラスとメソッドを使うパッケージにはいくつかの追加のステップが必要である (これらが純粋に内部で使用されていない限り)。パッケージはそのDESCRIPTIONファイルに Depends: methodsを持たなければならず、NAMESPACEファイルでは

エクスポートされる任意のクラスとメソッドを宣言する必要がある。例えば、stats4パッケージでは NAMESPACEファイルは次のようになっている。

export(mle)

importFrom("graphics", plot)

importFrom("stats", optim, qchisq)

## これらに対し、メソッドや暗黙のジェネリック (AIC, BIC, nobs)を定義する:

importFrom("stats", AIC, BIC, coef, confint, logLik, nobs, profile,

update, vcov)

exportClasses(mle, profile.mle, summary.mle)

Page 54: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 48

## インポートされたジェネリクスのためのすべてのメソッド:

exportMethods(coef, confint, logLik, plot, profile, summary, show, update, vcov)

## implicit generics which do not have any methods here

export(AIC, BIC, nobs)

パッケージの外部で使われるすべての S4クラスは exportClassesディレクティブに一覧にし

ておく必要がある。代わりに、exportPatternと同様の形式の exportClassPatternを使っ

て指定することができる。47他のパッケージからジェネリクスに対するメソッドをエクスポー

トするには、exportMethodsディレクティブが使える。

名前空間中のジェネリックのメソッドをエクスポートすることは、ジェネリックをエクス

ポートすることであり、名前空間のジェネリックをエクスポートすることは、そのメソッド

をエクスポートすることもあるということに注意。もし総称的関数がこのパッケージに対し

て局所的でない場合、それは総称的関数としてインポートされたか、あるいは非ジェネリッ

クなバージョンが単に S4メソッドを加えるために総称的にしたかのどちらかである (上の例にある plotのような関数として)。総称的関数は exportと exportMethodsの一方、あるいは

両方を通して宣言されるが、後者がよりはっきりしている (そして上の stats4でも使用されている)。特にプリミティブ関数に対する総称的関数はないので、exportはプリミティブをエ

クスポートすることに意味はない。一方で、もしジェネリックがパッケージに対して局所的

であれば、関数自身を export()を使ってエクスポートすることはより自然であり、これはも

し暗黙のジェネリックが、それに対するメソッドの設定なしに作成されていたら、これをし

なければならない (stats4の AICにあるように)。

非ローカルな総称的関数は、関数の呼び出しが、パッケージからメソッドを送り出すこと

を確実にするためだけにエクスポートされる (メソッドがプリミティブ関数に対するものであるとき、これは実行されない、もしくは必要とされない)。このため、そのような暗黙のうちに生成される総称的関数を文書化する必要はなく、パッケージ tools中の undocはそのような

総称的関数を報告しない。

もしパッケージが他のパッケージからエクスポートされた S4クラスとメソッドを使っているが、名前空間の全体をインポートしていないのであれば、それぞれメソッドと一体になっ

たクラスと関数を一覧にする指示

importClassesFrom(package, ...)

importMethodsFrom(package, ...)

を使ってクラスとメソッドを明示的にインポートする必要がある。2つの小さなパッケージAとBがあり、BがAを使っていると仮定しよう。すると、それぞれの NAMESPACEファイルは� �

export(f1, ng1)

exportMethods("[")

exportClasses(c1) と

47 R 2.13.0 からは、これは exportPatternと同様の様式を既定値としている: これを上書きするにはexportClassPattern("^$")のようなものを使用せよ。

Page 55: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 49� �importFrom(A, ng1)

importClassesFrom(A, c1)

importMethodsFrom(A, f1)

export(f4, f5)

exportMethods(f6, "[")

exportClasses(c1, c2) とすることができる。

importMethodsFromも、それらのメソッドの名前空間で定義された任意のジェネリクスを

インポートすることに注意。

もし S4メソッドをエクスポートするのであれば、対応するジェネリクスが利用可能であることが重要である: これに関する要求は R 2.15.0以降厳格になっている。例えば、あなたは見えている関数を暗黙のジェネリックに変換するために graphicsから plotをインポートす

る必要があるかもしれない。しかし stats4によってエクスポートされたジェネリクスを使うことがよい習慣である。これは複数のパッケージがジェネリクスにメソッドを曖昧さなしに

設定することを可能にするからである。

1.7 移植可能なパッケージを書く

移植性のあるパッケージは簡潔なファイル名にすべきである: 英数字のASCIIと.のみを用い、

上で述べられたWindowsで許可されていない名前を避けよ。

R CMD checkは検査の基本的な集まりを提供するが、しばしばCRANに提出されたパッケー

ジのインストールと使用を試みたときに、さらなる問題が出現することがある – それらの多くはコンパイル済みコードが関係している。ここではパッケージの移植性を高めるために自

身でできる、更なる検査を以下に列挙する。

• もしパッケージに configureスクリプトがあるのであれば、Windows で使われるconfigure.winを提供せよ。Windows用の CRANバイナリパッケージは自動的に構築

され、もしパッケージが介入なくビルドされないのであれば、多くの Rユーザにとって、そのパッケージは容易に利用可能とはならないであろう。

• もしパッケージに Makevarsまたは Makefileファイルがあるのであれば、移植性のある機

能だけを使っていることを確認せよ。そのようなファイルは (ファイルの最終行も含め)LFで終わっていなければならず、GNU拡張を使用してはならない。よく誤って使われるGNU拡張は、条件付き取り込み (ifeqとそれに似たもの)、${shell ...}と${wildcard

...}、そして+=と:=の使用である。また、暗黙のルール以外での$<の使用はGNU拡張である。残念なことに、GNU拡張を使うmakefileはしばしば他のプラットフォームでも動作するが、意図した結果にはならない。

${shell ...}の使用はバッククォートを使うことにより回避できる。例えば:

PKG_CPPFLAGS = ‘gsl-config --cflags‘

はRで使われることが知られている makeのすべてのバージョン 48で動作する。

もし本当にGNU makeを仮定しなければならないのであれば、それは DESCRIPTONファ

イル中に次のようにして宣言する。

SystemRequirements: GNU make

Windowsで実行可能なmakeはGNU makeだけであるので、ファイル Makevars.winま

たは Makefile.winでGNU拡張を使うことは許容される。

48 GNU make、FreeBSD上の BSD make、Darwin上の bsdmake、Solarisで実装された AT&T make

Page 56: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 50

• コードが標準規格に準拠しているか検査するため、コンパイラの能力を利用せよ。例えば潜在的な問題を警告するために、gccにオプション-Wall -pedanticをつけることがで

きる。これは特に C++で重要で、g++ -Wall -pedanticは他の大部分の C++コンパイラでコンパイルに失敗するGNU拡張の使用を警告する。Rはバージョン 2.12.0以降 C99コンパイラを仮定しているが、もし以前のバージョンにパッケージを移植可能にしたい

のであれば、C90で書くべきである。(実際、C99は 2007頃以来、多くのプラットフォームで利用可能であるが、gccの古いバージョンはR 2.11.xでまだ利用されている。)

もし FORTRAN 77を使っているのであれば、ftnchek(http://www.dsm.fordham.edu/~ftnchek/)は規格に一致しているか徹底的な検査を与える。

• R、Cと FORTRANコードの間で引数を渡すことにはよく注意せよ。特に Cの longは

(CRANメンテナの大部分が使うのも含め、)大部分のRプラットフォームで 32-bitであるが、多くの現代のUnixとLinuxでは 64-bitである。Cコード中の longの使用が熟考さ

れているとは考えにくい: もし intより長い型が必要であれば、例えば int_fast64_t(そしてそれが駄目であれば long long49)と、自身の型の longや long longへの typedefのようなC99の型に対する configureの検査をするべきである。もしくは別の適切な型 (例えば size_t)を使うべきである。

longとポインタ型が同じ大きさであると仮定するのは安全ではなく、64-bit Windowsでも同じではない。もしポインタと整数間で変換する必要があれば、C99の整数型 intptr_

tと uintptr_t(これらはヘッダ<stdint.h>に定義されており、C99標準で実装されることは必要とされていない)を使用せよ。

FORTRAN中の integerはすべてのRプラットフォーム上で Cの intに対応しているこ

とに注意。

• どのような環境でも自身のコンパイル済みコードは abortや exitを絶対に呼んではいけ

ない: これらはかなり高い確率ですべての保存していない作業を含め、ユーザの Rプロセスを終了してしまう。abortが呼び出せる 1つの使用方法は、製品コード中では決して動作させてはならない、CまたはC++の関数中の assertマクロである。動作させない

ことを確実にする通常の方法は、マクロ NDEBUGを定義することで、R 2.15.0以降では R

CMD INSTALLはそれをコンパイルフラグの一部としてそれを行う。もし開発中に assert

を使いたいのであれば、PKG_CPPFLAGSに-UNDEBUGを含めることができる。サブディレ

クトリ中にある自身の src/Makefileや makefikeも NDEBUGを定義する必要があること

に注意。

これは自身のコードだけでなく、コンパイルしたあるいはリンクした任意の外部のソフ

トウェアにも適用される。

• コンパイル済みコードは stdoutまたは stderrへの書き出しをすべきではなく、C++とFortran I/Oを使うべきではない。前の項目と同様に、そのような呼び出しは外部のソフトウェアからくる可能性があり、そして決して呼ばれない可能性がある。

• メモリ割り当てと配列の外部での読み/書きにおけるエラーは一部のマシンでクラッシュ(例えばセグメンテーションフォールト)のよくある原因となる。原因を探すために使うツールについては Section 4.3.2 [valgrindを使う], page 90を参照せよ。

• 多くのプラットフォームはコンパイル済みコード中の不十分なエントリポイントがあることを許可しているが、もし使われていればアプリケーション (ここではR)をクラッシュさせる。許可しないプラットフォームもある (特にWindows)。

49 ただし long longは標準的な C++の型ではなく、厳密に検査するよう構成された C++コンパイラはそれを拒絶するであろう。

Page 57: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 51

nm -pg mypkg.so # あるいは例えば.slのような拡張子

の出力を見ることと、Uとマークされた任意のシンボルが予測されていないものかどうか

検査することはクラッシュを避ける良い方法である。

• DLLのシンボル間の矛盾はまさにプラットフォーム固有の方法で処理される。問題を避ける良い方法は、PACKAGE引数を使ったことを確実にすることだけでなく、可能な限り

多くのシンボルを staticにすること (nm -pgで検査する)と、一般的でない名前を使うことである。

• Rや他のパッケージから、.Internal、.C、.Fortran、.Callや.Externalを通してコ

ンパイル済みコードを呼び出すことは移植性がない。そのようなインタフェースは予告

なく変化しがちであり、自身のコードがRプロセスを終わらせてしまう結果になってしまうだろう。

• (ハードないしシンボリック)ファイルリンクをパッケージソースの中で使ってはならない。R CMD buildは間接参照先のリンクに記録されている-h tarフラグを取得して tar書庫を梱包するため、これは通常は問題にならない。しかし GNU tarのバージョン 1.24以降、R CMD INSTALLによって適切に処理されないハードリンクへのリンクに間接参照

してしまう。

• もしWindowsシステムを持たないのであれば、配布 (CRANへの提出を含む)の前にWin-Builder(http://win-builder.r-project.org/)にソースパッケージを提出せよ。

1.7.1 エンコーディングの問題

もしパッケージに ASCIIでないテキストを含んでおり、特に複数のロケールで使われること

を意図しているのであれば注意が必要である。DESCRIPTIONファイルと.Rdファイルには、こ

のマニュアルの他で議論されているように、使われているエンコーディングを示すことがで

きる。

最初に本当に ASCIIでないテキストが必要か注意深く考えよ。Rユーザの多くは自国の言語グループ (例えば西ヨーロッパ言語、東ヨーロッパ言語、簡字体中国語)と ASCIIで書かれ

たテキストしか正しく見ることができない。他の文字はまったく描画されない、不正確に描画

される、あるいは自身のRコードにエラーを引き起こす可能性がある。ドキュメントについては、エンコーディングを示すこととASCII翻字を含めることは合理的な仕事であろう。一般

にサポートされている文字集合は 2000年ごろよりも幅広くなっているが、非ラテンアルファベット (ギリシャ語、ロシア語、グルジア語、. . . )はまだしばしば問題となり、倍幅文字 (中国語、日本語、韓国語)はしばしば正しく描画するために特殊なフォントを必要とする。

いくつかのCRANパッケージはフランス語 (とわずかにドイツ語)で書かれたメッセージがRコード内にある。これに対応する良い方法はこのマニュアルの他で議論されている国際化機能を使うことである。

パッケージ tools中の関数 showNonASCIIfileはファイル中の非 ASCIIバイトを見つける

ことに役立てることができる。

R 2.10.0から、\uxxxxエスケープとして Unicodeでそれらを供給するという、自身の Rコードにある文字列 (だけ)に任意のテキストを持たせる移植性のある方法がある。もし現在のエンコーディングに文字がなければ、構文解析器は文字列をUTF-8にエンコーディングして、その文字列にそのようなことを印付ける。これはデータセット中の文字列に対しても適

用される: 文字列は UTF-8ロケールで\uxxxxエスケープを用いて用意されるか、UTF-8にエンコードされる。あるいは ‘iconv()’を通してUTF-8に変換される。もしそのように変換するなら、DESCRIPTIONファイルの ‘Depends:’フィールドは ‘R (>= 2.10)’(あるいはそれ以降)とせよ。

Page 58: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 52

UTF-8ロケールでない環境で実行している Rセッションは可能であれば、表示のためにそのような文字列を再エンコードせよ (これは例えばWindows上の RGuiによって行われる)。例えば ‘X11()’や ‘windows()’のようなコンソール/ターミナルとグラフィックデバイスの両方で、適切なフォントが選択されるか利用可能にする必要がある。‘postscript’または ‘pdf’を使うとUTF-8ロケールの言語に依存した 8-bitエンコーディングの既定値を選択し、ユーザはどのように ‘encoding’引数を選択する方法を教えてもらう必要があるだろう。

もしUnix系で DESCRIPTIONファイルにパッケージのエンコーディングを設定しているパッ

ケージについて R CMD checkを実行したいのであれば、環境変数 R_ENCODING_LOCALESを通

して適切なロケールを指定する必要があるだろう。初期設定値は次の値に等しい。

"latin1=en_US:latin2=pl_PL:UTF-8=en_US.UTF-8:latin9=fr_FR.iso885915@euro"

(これは glibcに基づくシステムに対して適切である)。ただし、現在のロケールがUTF-8で、そしてパッケージのコードが構文チェックのためUTF-8に変換されている場合を除く。

1.7.2 バイナリの配布

もしWindowsやMac OS X向けにパッケージのバイナリ版を配布したいのであれば、自身で更にする必要があることは、移植できるか検査することである: 自身のマシン上で他の人が持たない外部のソフトウェアに依存するのは全面的に簡単すぎる。

Windows では、自身のパッケージが他の何の DLL に依存しているかを検査せよ (DLLツールの用語では ‘imports’)。そうするための便利な GUI に基づくツールは ‘DependencyWalker’(http://www.dependencywalker.com/)で、32-bitと 64-bit DLLの両方に対して使える – これは例えば R.dllや Rblas.dllのような R自身のDLLへの行方不明のリンクとして報告する。32-bit DLLだけは、コマンドラインツール pedump.exe -i(Rtools*.exeにある)が利用可能であり、勇敢な人向けに、適当なツールチェインにある objdumpツールもど

の DLLがインポートされたかを明らかにするであろう。もし R開発者以外から提供されたツールチェインや自身のmakefileを使うのであれば、特に例えば libgfortran、libstdc++

と libgcc_sのような、ツールチェインのランタイムDLLの依存関係に気をつけよ。

Mac OS Xに対して、libs以下のパッケージの共有オブジェクトに R CMD otool -Lを使

用すると、共有オブジェクトが何に依存しているかを示す: /usr/local/lib中のすべて、特に libgfortran.2.dylibの依存関係に注意せよ。

1.8 診断メッセージ

今や診断メッセージは翻訳することができ、一貫したスタイルでそれを書くことが重要であ

る。次のセクションに示したすべてのメッセージを抽出するためのツールを使うことで、一

貫性 (あるいは一貫性の無さ)の有用な概観が得られる。

指針は次の通りである。

• メッセージは文の断片であり、孤立して表示せれない。そのため、単語の最初を大文字にしないことと、ピリオド (あるいは他の句読点)で終わらないことが慣習となっている。

• メッセージを細かく分割しないようにせよ。Cのエラーメッセージでは、メッセージ中のすべての英単語を含む単一の書式文字列を使用せよ。

Rのエラーメッセージでは、pasteを使ってメッセージを作成せず、stop、warningに複

数の引数を与えることを通じて、または gettextfを通じてメッセージを作成せよ。

• 例えば “can’t”や “don’t”のような口語表現を用いてはならない。

Page 59: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 53

• 可能であれば、異なる言語が異なる慣習を持つように、引用符をメッセージの一部にせよ。Rのメッセージ中では、これは引数が変数である場合を除いて、sQuoteまたは dQuote

を使っていないことを意味する。

慣習的に、単一引用符は次のような引用に対して使われる。

’ord’ must be a positive integer, at most the number of knots

そして二重引用符は例えば次のように、Rの文字列に触れるときに使われる。

’format’ must be "normal" or "short" - using "normal"

ASCIIは方向のある引用符を含まないので、‘’’を使うのが最善であり、(自動翻訳も含め)翻訳機には利用可能であれば、方向性のある引用符を使用させよ。引用のスタイルの範

囲は広大である: 残念なことに、それらを移植可能な texinfoドキュメントの内部で複製

することはできない。しかし毒味役として、いくつかの言語は左/右引用符ではなく ‘上’と ‘下’(コンマ)引用符を使うものがあり、二重山括弧を使う言語もある (そして開始のためにAdobeが ‘guillemotleft’と呼んでいるものを使う言語もあり、それを終わりのために使う別の言語もある)。

• ときどき、メッセージは単数形または複数形 (そして他の言語ではそのような概念がない、あるいはいくつかの複数形がある可能性がある – スロベニア語は複数形が 4種類ある)にする必要がある。そのため、かつて libraryで使われていたような次のような構造

を避けよ。

if((length(nopkgs) > 0) && !missing(lib.loc)) {

if(length(nopkgs) > 1)

warning("libraries ",

paste(sQuote(nopkgs), collapse = ", "),

" contain no packages")

else

warning("library ", paste(sQuote(nopkgs)),

" contains no package")

}

そして構造は次のようなものに換えられた。

if((length(nopkgs) > 0) && !missing(lib.loc)) {

pkglist <- paste(sQuote(nopkgs), collapse = ", ")

msg <- sprintf(ngettext(length(nopkgs),

"library %s contains no packages",

"libraries %s contain no packages"),

pkglist)

warning(msg, domain=NA)

}

他の言語では ‘There is no package in library %s’ または ‘There are no packages inlibraries %s’と言わなければならない可能性もあるので、ここにあるように完全な句を持つことがより優れているということに注意。

1.9 国際化

RとCレベルのエラーと警告に関するメッセージを変換する仕組みがある。それはRがNLSの支援 (configureのオプション--enable-nlsにより依頼される初期設定)付きでコンパイルされた場合にのみ利用可能である。

Page 60: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 54

手続きではGNU gettextの一部である msgfmtと xgettextを使い、GNU gettextはイン

ストールする必要がある: Windowsユーザは予めコンパイルされたバイナリを http://www.

stats.ox.ac.uk/pub/Rtools/goodies/gettext-tools.zip にて、poEditパッケージと

一緒に梱包されたものは (http://poedit.sourceforge.net/download.php#win32)にて入手できる。

1.9.1 Cレベルのメッセージ

翻訳を有効にする手順は次の通り。

• 翻訳すべきメッセージを含むすべてのCファイルでインクルードされるヘッダファイルで次のものを宣言する。

#include <R.h> /* Rconfig.hを含めるため */

#ifdef ENABLE_NLS

#include <libintl.h>

#define _(String) dgettext ("pkg", String)

/* 必要に応じて pkgを置換する */

#else

#define _(String) (String)

#endif

• 翻訳すべき各メッセージに対し、それを_(...)で包む。例えば次のようにする。

error(_("’ord’ must be a positive integer"));

もし単数形と複数形で異なるメッセージを使いたいのであれば、次のコード

#ifndef ENABLE_NLS

#define dngettext(pkg, String, StringP, N) (N > 1 ? StringP : String)

#endif

を加え、文字列を次のようにマークする必要がある。

dngettext(("pkg", <singular string>, <plural string>, n)

(これはR 2.10.0以降のみでサポートされているため、dngettextを使うパッケージは R

(>= 2.10)に依存する必要がある。)

• パッケージの srcディレクトリ内で次のものを実行する。

xgettext --keyword=_ -o pkg.pot *.c

ファイル src/pkg.potはテンプレートファイルであり、習慣的にこれは po/pkg.potと

して送り出される。他の言語への翻訳機は、いわゆる ll.poを生成するために、ファイル

src/pkg.potをコピーして編集する (gettextマニュアルを見よ)。ここで翻訳機が使われる言語に対するコードである。(ll.poはpoディレクトリに送り出されるであろう。)次にll.moを作

成するために ll.poに msgfmtを実行し、作成したものを inst/po/ll/LC_MESSAGES/pkg.mo

にコピーする。これでパッケージがインストール後にロードされたとき、(LANGUAGE環境変数、またはロケールの設定を用いて)ユーザが優先するものに一致した任意の言語 langに対し、po/lang/LC_MESSAGES/pkg.moファイル中にあるメッセージの翻訳したものを探すであ

ろう。

1.9.2 Rのメッセージ

Rの stop、warningと messageメッセージの自動翻訳をサポートため仕組みも用意されてい

る。Cレベルのメッセージと同様の方法でメッセージの一覧を使用しているが、pkgではな

Page 61: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 55

くドメイン R-pkgを使っている。stop、warningと messageの呼び出し内での文字列の翻訳

は、gettextや gettextfへの呼び出しに含まれた他のメッセージと同様に、自動的に有効に

なる。(これを抑えるには、引数 domain=NAを使用せよ。)

R-pkg.potファイルを準備するためのツールが tools内で提供されている: xgettext2potは gettext/gettextf、stop、warningと messageの呼び出し内部で生じる全ての文字列か

らのファイルを作成する。それらのいくつかは偽者であるため、ファイルは手作業の編集が

必要であろう。xgettextは実際の呼び出しを抽出するため、エラーメッセージを整理する際

により役立つ。

単数形あるいは複数形になるメッセージの翻訳はとても複雑になることがある: 言語は 4つの異なる形態を持つ可能性がある。Rの関数 ngettextは同名の C関数へのインタフェースを提供し、その最初の引数 nの値に応じて選択された言語に対し、適切な単数形または複

数形を選択する。ngettextの呼び出しでは明示的に domain="R-pkg"を使うのが最も安全で

あり、ngettextの呼び出しがパッケージ中で関数からの直接の呼び出しでない限り、Rの以前のバージョンでは domain="R-pkg"を使うことが必要である。

1.9.3 翻訳の設定

一度テンプレートファイルが作成されると、翻訳を作成することができる。慣習的な翻訳ファ

イルの拡張子は.poである。翻訳ファイルは ‘ll.po’または ‘R-ll.po’という、それぞれコード‘ll’を持つ言語への Cと Rのメッセージの翻訳に対応したどちらかの名前を持ち、パッケージの poサブディレクトリにの配置される。

言語コードの詳細については ‘Localization of messages’ in ‘R Installation and Adminis-tration’を参照せよ。

一旦パッケージがインストールされると、翻訳を使えるようにするため、準備と inst/po/

へのインストールが必要となる。これを行うために、パッケージの最上位ディレクトリから

次の適切な行を使用せよ。

mkdir -p inst/po/ll/LC_MESSAGES

msgfmt -c --statistics -o inst/po/ll/LC_MESSAGES/R-pkg.mo po/R-ll.po

msgfmt -c --statistics -o inst/po/ll/LC_MESSAGES/pkg.mo po/ll.po

-cを使うことは正当性の検査に役立ち、--statisticsはカバレッジに言及する。

1.9.4 Makefileのサポート

Rソースの poディレクトリではmakefileのサポートがある。テンプレートファイルを作成するために、これを使うには次のコマンドを使用せよ。

mkdir -p pkgdir/po

ここで pkgdirはパッケージソースの最上位ディレクトリである。もしパッケージがその src

ディレクトリに翻訳の目印がつけられたCソースファイルを持つのであれば、ダミーのテンプレートファイルを作成するために、次のコードを使用せよ。

touch pkgdir/po/pkg.pot

そして、

cd R_BUILD_DIR/po

make pkg-update PKG=pkg PKGDIR=pkgdir

はRメッセージのテンプレートファイルを作成し、Cメッセージの任意のテンプレートを更新する。これはもし選択された解釈が適切な (例えば UTF-8)ロケールで方向付きの形式の

Page 62: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 56

(単一または二重)引用符で囲うならば、‘en@quot’という偽の言語に対して翻訳の用意と設定も行う。

新しい言語の翻訳が pkgdir/poディレクトリに加えられたとき、同じ makeコマンドを実

行すると、翻訳の検査とそれから設定を行う。

もしパッケージのソースが更新されたのであれば、同じ makeコマンドはテンプレートファ

イルを更新し、翻訳の.poファイルに変更をマージし、その結果、更新された翻訳が設定され

る。マージすると ‘fuzzy’として翻訳に印付けされるのをしばしば見ることになり、これはカバレッジ統計情報で報告されるであろう。曖昧な翻訳が使われないように、これは翻訳ファ

イルが人間の注意を必要とすることを示している。

これはUnix系のみでサポートされており、少なくとも 1台のMac OS Xシステムで正しく動作しなかった。

1.10 CITATIONファイル

CITATIONと名づけられたインストール済みファイルは citation()関数により使用される。

(インストールされるには、ファイルはパッケージソースの instサブディレクトリにある必

要がある。)

CITATIONファイルは R コードとして構文解析される (パッケージの宣言済みエンコーディング、あるいは何も宣言されていなければ ASCII で。)。もしそのようなファイルが存在しなければ、citationはパッケージの DESCRIPTIONメタデータから引用情報を自動

生成し、CITATIONファイルのように見える具体的な例は推奨パッケージ nlme (http: / /CRAN.R-project.org/package=nlme)に見られる (以下を参照せよ): 推奨パッケージ boot(http://CRAN.R-project.org/package=boot)、cluster (http://CRAN.R-project.org/package=cluster)とmgcv (http://CRAN.R-project.org/package=mgcv)はさらなる例を持つ。

CITATIONファイルは関数 bibentry(新しい形式であり、R 2.12.0以降でのみ動作する)、あるいは関数 citHeader、citEntryと (任意に)citFooter(昔の形式)への呼び出しを含む。

ここに再整形した nlme (http: / / CRAN . R-project . org / package=nlme) に対するCITATIONファイルを示す:

citHeader("To cite package ’nlme’ in publications use:")

year <- sub(".*(2[[:digit:]]{3})-.*", "\\1", meta$Date, perl = TRUE)

vers <- paste("R package version", meta$Version)

citEntry(entry="Manual",

title = "nlme: Linear and Nonlinear Mixed Effects Models",

author = personList(as.person("Jose Pinheiro"),

as.person("Douglas Bates"),

as.person("Saikat DebRoy"),

as.person("Deepayan Sarkar"),

person("R Core Team")),

year = year,

note = vers,

textVersion =

paste("Jose Pinheiro, Douglas Bates, Saikat DebRoy,",

Page 63: Rの拡張を書く (R 2.15.2)

Chapter 1: Rのパッケージを作る 57

"Deepayan Sarkar and the R Core Team (",

year,

"). nlme: Linear and Nonlinear Mixed Effects Models. ",

vers, ".", sep=""))

更新する必要があるかも知れない情報が DESCRIPTIONファイルから取り出されている方法

に注意 – そのような情報をハードコードする気にさせているが、するとそのような情報は通常は時代遅れになってしまう。提供されている情報の詳細については?bibentryを参照せよ。

CITATIONファイルは sourceになったときに、それ自身は何も出力してはならない。

1.11 パッケージタイプ

DESCRIPTIONファイルは、欠落がこの章でこれまで議論してきた拡張の一種である Packageと

仮定される任意のフィールドTypeを持つ。現時点で、1つの別の型が認識される; Translation型というのもあった。

1.11.1 フロントエンド

これは、例えばかつての gnomeGUIパッケージのように新しいフロントエンドを加えるために設計された、かなり一般的な仕組みである (CRANの ‘Archive’エリアを参照せよ)。もしconfigureファイルがパッケージの最上位ディレクトリで見つかるとそれは実行され、そし

てもし Makefileが見つかると (しばしば configureによって生成される)、makeが呼び出さ

れる。もし R CMD INSTALL --cleanが使われると make cleanが呼び出される。他の動作は起

こらない。

R CMD buildはこの種の拡張をパッケージにすることができるが、R CMD checkは型を検査

して、それを飛ばすであろう。

この種類の多くのパッケージはRのインストールディレクトリへの書き込み権限を必要とする。

1.12 サービス

Rプロジェクトのメンバーの何人かは、特にRパッケージを公開配布する人を意図した、パッケージを書く人を支援するサービスを設定している。

win-builder.r-project.org (http://win-builder.r-project.org)はよくテストされたソースパッケージから (32/64-bit)Windowsバイナリの自動的な準備を提供する。

R-Forge (R-Forge.r-project.org (http: / / R-Forge . r-project . org)) と RForge(www.rforge.net (http://www.rforge.net))は似たような名前を持つ、似たようなサービスである。両方とも SVN、日々のビルドと検査、メーリングリストと install.packages

を経由してアクセス可能なリポジトリを通じたソースコード管理を提供する (これらはsetRepositoriesとそれを用いたGUIにより選択することができる)。パッケージの開発者はプロジェクトのウェブサイトやニュース告知に基づいて現在の活動を表現する機会があ

る。メーリングリスト、フォーラムや wikiは開発者および/または興味のあるユーザ間で議論と情報交換するための便利な道具である。

Page 64: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 58

2 Rのドキュメントを書く

2.1 Rd書式

Rのオブジェクトは “R documentation”(Rd)書式で書かれたファイルで文書化されている。これはかなりの部分は (La)TEXに似た簡素なマークアップ言語であり、LATEX、HTMLと平

文を含め、さまざまな形式へと処理することができる。翻訳は R_HOME/binにあるスクリプト

Rdconvとパッケージのインストールスクリプトによって呼び出される toolsパッケージにある関数によって実行される。

Rディストリビューションはそのようなファイルを 1300より多く含み、それらはRのソースツリーの src/library/pkg/manディレクトリに見ることができる。ここで pkgは、標準的なRディストリビューションに含められる標準的なパッケージの 1つを表している。

例として、R 関数 loadを文書化した src/library/base/man/load.Rdの単純化された

バージョンを見てみよう。� �% File src/library/base/man/load.Rd

\name{load}

\alias{load}

\title{Reload Saved Datasets}

\description{

Reload the datasets written to a file with the function

\code{save}.

}

\usage{

load(file, envir = parent.frame())

}

\arguments{

\item{file}{a connection or a character string giving the

name of the file to load.}

\item{envir}{the environment where the data should be

loaded.}

}

\seealso{

\code{\link{save}}.

}

\examples{

## すべてのデータを保存するsave(list = ls(), file= "all.RData")

## 保存された値を現在の環境に復元するload("all.RData")

## 保存された値をワークスペースに復元するload("all.RData", .GlobalEnv)

}

\keyword{file} Rdファイルは 3つの部分からなる。ヘッダはファイル名、文書化されたトピック、タイト

ル、内容を記述する短い説明と文書化されたオブジェクトのRの使用情報に関して基本的な情報を与える。本体はさらなる情報を与える (例えば、上にあるような関数の引数や返り値)。最後にキーワード情報を持つ任意のフッタがある。ヘッダは必須である。

Page 65: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 59

情報は標準的な名前 (とユーザ定義のセクションも許可されている)を持つ一連の sectionsの内部で与えられている。特別の指定がない限り 1、それらは Rdファイルの中で 1度だけ現れるべきであり (順序は任意)、処理するソフトウェアは警告を出して、ファイルの標準的なセクションの最初の出現だけを保持する。

パッケージの書き手にとって役立つであろう、Rd形式で文書を書くための指針については

“Guidelines for Rd files” (http://developer.r-project.org/Rds.html)を参照せよ。Rの総称的関数 promptは手動での編集の準備が整った必要最小限の Rdファイルを構築するため

に使われる。文書化する関数 (適切な関数と引数名を書き入れる)とデータフレームに対してメソッドが定義される。Rdファイルの他の型に対しては関数 promptData、promptPackage、

promptClassと promptMethodsもある。

Rdファイルの一般的な構文は以下に要約される。現在の Rd構文に関する詳しい技術的な

議論については、“Parsing Rd files” (http://developer.r-project.org/parseRd.pdf)を見よ。何年にも渡って Rd形式は数多く変更があることに注意。これはもしパッケージがRの初期のバージョンで使われることを想定しているのであれば重要となりうるものである: もしパッケージがR 2.10.0より前で使われることを意図しているのであれば、このマニュアルの以前のバージョンを参照せよ。

Rdファイルは 3種類のテキスト入力からなる。もっとも一般的なのはマークアップの接頭辞として使われるバックスラッシュ、引数を示すために使われるブレースを伴う LATEX系である。最も一般的でないテキストは逐語的なテキストであり、どのマークアップも処理され

ない。3番目の種類は R系であり、Rコードを対象としているが、いくつかの組み込みマクロが許可している。R系テキストの内部にある引用符は特別に処理される: 例えば\nのよう

な、通常の文字エスケープはそのまま入力することができる。\l(例えば\link)や\v(例えば\var)で始まるマークアップだけが引用符の内部で認識される。ほとんど使われない垂直タブ\vは\\vと入力されなければならない。

各マクロは引数の入力の型を定義している。例えば、ファイルは最初に LATEX系構文を使用している。これは\descriptionセクションでも使われているが、\usageセクションではR系の構文、\aliasマクロでは逐語的構文を使用している。コメントはすべてのテキストの種

類で、パーセント記号%からその行末まで実行される (loadの例の最初の行にあるように)。

バックスラッシュ、ブレース、パーセント記号は特別な意味を持つことから、それらをテ

キストに入れることはバックスラッシュを使ってエスケープすることがときおり要求される。

一般的に対応の取れたブレースはエスケープする必要はないが、パーセント記号はいつもエ

スケープする必要がある。完全なマクロの一覧とエスケープの規則については “Parsing Rdfiles” (http://developer.r-project.org/parseRd.pdf)を参照せよ。

2.1.1 関数のドキュメント化

Rオブジェクト (特に関数)の文書化に使われる基本的なマークアップコマンドはこのサブセクションで与えられている。

\name{name}

nameは一般的には 2、文書を含む Rdファイルの基本名である。これはファイル

によって表される Rdオブジェクトの名前であり、パッケージ内で一意でなければ

ならない。パッケージマニュアルの索引付けに関する問題を避けるため、名前に

‘!’、‘|’、‘@’を含んではならない。そしてHTMLヘルプシステムに関して起こり

1 例えば\alias、\keywordと\noteのセクション2 例外がありうる: 例えば Rdファイルはドットで始まることが不可能であり、大文字小文字を区別しないファイルシステムにおいて一意的に名づけられていなければならない。

Page 66: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 60

うる問題を避けるため、名前に ‘/’、空白を含むべきではない。(LATEXの特殊文字は許可されるが、それらは索引で正しい順に並ばないかもしれない。)ファイル中に\nameエントリは 1つだけ存在することができ、それは任意のマークアップを含んではならない。パッケージマニュアルのエントリは\nameエントリのア

ルファベット 3順になるであろう。

\alias{topic}

\aliasセクションではファイルドキュメントのすべての “話題”を指定する。この情報はオンラインヘルプシステム (と平文や HTML)により、検索のための索引データベースに集められる。topicは空白を含むこともできるが、(歴史的な理由から)先頭と最後尾の空白は除去される。パーセントと左ブレースはバックスラッシュでエスケープされる必要がある。

いくつかの\aliasエントリがあるかもしれに。いくつかの Rオブジェクトを 1つのファイルで文書化するのはかなりしばしば便利である。例えば、ファイル

Normal.Rdは正規分布に対する密度、分布関数、分位関数と乱数の生成を文書に

している。そのため次のようにして始まる。

\name{Normal}

\alias{Normal}

\alias{dnorm}

\alias{pnorm}

\alias{qnorm}

\alias{rnorm}

また、Rオブジェクトを参照する方法をいくつか持つことがしばしば便利であり、\aliasはオブジェクト名である必要はない。

\nameは必ずしも話題を文書にしたものではなく、もし必要ということであれば、

(この例のように)明示的な\aliasエントリを持つ必要があるということに注意。

\title{Title}

Rdファイルのタイトル情報。これは大文字で始まり、ピリオドで終わってはなら

ない; 互換性の最大化のためその長さを最大で 65文字に制限するように試みよ。

Rのバージョン 2.12.0以降、テキスト中のマークアップはサポートされているが、英語のテキストと句読点 (例えば ‘<’)以外の文字を使うことは移植性を制限するかもしれない。

ヘルプファイル中には 1つ (だけ)\titleセクションが存在しなければならない。

\description{...}

関数が何をするかということについての短い記述 (1つの段落で、数行だけ)。(もし記述が長すぎで容易に短くできないのであれば、ファイルはおそらく一度に過

剰に文書にしようとするであろう。)これはパッケージ概要のファイルを除いて必須である。

\usage{fun(arg1, arg2, ...)}

ファイル中で文書化されている関数と変数の概要を示す 1行かそれ以上。これらはタイプライタフォントで設定されている。これはR系のコマンドである。

指定された使用情報は関数定義と正確に一致させる必要がある (コードと文書の間で整合性を自動的に検査することが可能になるように)。

3 現在のロケールで、LATEXの特殊文字に対する特別な扱いとリストの先頭へ移動した任意の ‘pkgname-package’トピックを伴う。

Page 67: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 61

実際の概要に対し\synopsisを使うことと\usageで修正された概要を示すこと

はもはや望ましいことではない。\synopsisに対するサポートは最終的には除去

される。関数が指定された名前付き引数に依存して、いくつかの異なる方法で使

うことができることを示すためには、セクション\detailsを使用せよ。例えば、

abline.Rdは次のものを含んでいる。

\details{

Typical usages are

\preformatted{

abline(a, b, untf = FALSE, \dots)

......

}

クラス"class"を継承するオブジェクトのための総称的関数 genericに対する S3メソッドの名前を示すためには\method{generic}{class}を使用せよ。印字さ

れたバージョンでは、(メソッドは直接ではなく、メソッドディスパッチを経由して起動しなければならないという理解を反映して)これは genericとして出てくるが、codoc()と他のQCツールは常に完全名を入手することができる。

例えば、print.ts.Rdは次のものを含む。

\usage{

\method{print}{ts}(x, calendar, \dots)

}

これは次のように表示する。

Usage:

## S3 method for class ’ts’:

print(x, calendar, ...)

置換関数の使用方法は、置換関数の名前を明示的に示すのではなく (上の"dim<-")、dim(x) <- valueという形式で与えられなければならな

い。同様にクラス"class"を継承するオブジェクトのための総称的な置

換関数"generic<-"に対する S3 置換メソッドの使用法を示すために、\method{generic}{class}(arglist) <- valueを使うことができる。

オブジェクトの一部の抽出あるいは置換のための S3 メソッド、Ops グループのメンバ用の S3 メソッドとユーザ定義の (2 値) 中置演算子 (‘%xxx%’) の S3メソッドの使用法は、適切な関数名を用いて、上記のルールに従う。例えば、

Extract.factor.Rdは次のものを含んでいる。

\usage{

\method{[}{factor}(x, \dots, drop = FALSE)

\method{[[}{factor}(x, \dots)

\method{[}{factor}(x, \dots) <- value

}

これは次のように表示する。

Page 68: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 62

Usage:

## S3 method for class ’factor’:

x[..., drop = FALSE]

## S3 method for class ’factor’:

x[[...]]

## S3 replacement method for class ’factor’:

x[...] <- value

\S3methodは\methodに代わるものとして受け入れられている。

\arguments{...}

関数の引数の記述であり、引数リストの各要素に対し、次のような形式の項目を

用いたものである。

\item{arg_i}{Description of arg_i.}

(項目の 3つの部分の間には空白がないことに注意。)例えばパラメータの集合に関する一般的な情報を与えるため、\item項目の外部に任意のテキストがあるか

もしれない。

\details{...}

提供される機能の詳細なできるだけ正確な記述であり、\descriptionスロット

にある基本的な情報を拡張している。

\value{...}

関数の返り値の記述。

もし複数の値を持つリストが返されるのであれば、返されるリストの各要素に対

して次のような形式の項目を使うことができる。

\item{comp_i}{Description of comp_i.}

任意のテキストがこのリストに先行している 4かもしれない (例として rleのヘ

ルプを参照せよ)。\valueは暗黙の内に\describe環境なので、そのため環境は

要素を一覧にするために使ってはならず、単に個々の\item{}{}エントリに対し

て使うべきである。

\references{...}

文献への参照に関するセクション。webポインタには\url{}や\href{}{}を使用

せよ。

\note{...}

指摘しておきたい特記のためにこれを使用せよ。複数の\noteセクションは許可

されているが、エンドユーザを混乱させるかもしれない。

例えば、pie.Rdは次のものを含んでいる。

\note{

Pie charts are a very bad way of displaying information.

The eye is good at judging linear measures and bad at

judging relative areas.

......

}

4 リストの項目の間、または後ろにあるテキストは、R 2.10.0より前では捨てられており、勧められない。

Page 69: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 63

\author{...}

Rdファイルの著者に関する情報。余計な区切り文字 (例えば ‘( )’や ‘< >’)なしでEメールアドレスを明記するために\email{}を使うか、webポインタのために\url{}や\href{}{}を使用せよ。

\seealso{...}

関係するRオブジェクトを参照するために、\code{\link{...}}を使って指し示したもの (\codeはRオブジェクト名に関する正しいマークアップであり、\linkはこれをサポートする出力形式でハイパーリンクを生成する。See Section 2.3 [テキストを目立たせる], page 67、そして Section 2.5 [相互参照], page 69)。

\examples{...}

関数の使い方の例。このセクションのコードは再フォーマットなしでタイプライ

タフォントに設定されており、特に目印がない限り example()によって実行され

る (以下を参照せよ)。

例は文書化の目的に役立つだけではなく、Rコードの診断チェックのテストコードも提供する。初期設定では、\examples{}の内部にあるテキストはヘルプペー

ジの出力に表示され、example()と R CMD checkによって実行される。実行せず

表示するだけのテキストに対しては、\dontrun{}を使うことができる。そし

て\dontshow{} はユーザに表示しないテストのための追加コマンドであるが、

example()により実行されるであろう。(以前、これは\testonlyと呼ばれてお

り、まだこれは受け入れられている。)

\dontrun{}の内部のテキストは逐語的であるが、\examplesセクションの他の

部分についてはR系のテキストである。

例えば、

x <- runif(10) # 表示と実行

\dontrun{plot(x)} # 表示のみ

\dontshow{log(x)} # 実行のみ

従って、\dontrunに含まれない例のコードは実行可能である!さらに、例のコードはシステム固有の特徴を使うことや、(例えばインターネットアクセスや特定のディレクトリに書き込む許可のような)特別な便宜を要求してはならない。\dontrun

に含まれるテキストは処理されたヘルプファイルにあるコメントにより示される:正当なRコードである必要はないが、他の逐語的テキストのように、やはりエスケープは%、\と組になっていないブレースに対して使われなければならない。

例のコードは sourceを使って、exampleによって実行できなければならない。こ

れは stdinにアクセスしてはならないということを意味している。例えば、例の

ファイルからデータを scan()することがある。

例を実行可能にするためのデータは乱数生成 (例えば x <- rnorm(100))、またはdata()によって一覧になった標準的なデータセット (詳細は?dataを参照せよ)を用いることによって得ることができる。

最後に examples()によって実行されるが、R CMD checkによっては実行されな

いコードに印をつけるために (独立した行の先頭で)使われる\donttestがある。

これはたまにしか必要とされないが、例えばいくつかのロケールのように、テス

トを行うのが困難な環境で機能しなくなるかもしれないコードに対して使うこと

ができる。(可能な限り例の中で必要とされている機能をテストするために、例えば capabilities()を使用せよ。そして try()や tryCatch()を使うこともで

きる。)

Page 70: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 64

\keyword{key}

ファイルごとに 0またはそれ以上の\keywordセクションがありうる。各\keyword

セクションは単一のキーワードを指定すべきであり、Rの文書ディレクトリ (デフォルトでは R_HOME/doc)にあるファイル KEYWORDSの一覧にある標準的なキー

ワードの 1つであることが好ましい。R内部から標準的なキーワードを調べるためには、例えば RShowDoc("KEYWORDS")を使用せよ。もし文書化される Rオブジェクトが複数のカテゴリに属するのであれば、複数の\keyword項目がありう

るし、あるいはないこともある。

特殊キーワード ‘internal’はパッケージの APIの一部ではない内部オブジェクトのページをマークする。もしオブジェクト fooのヘルプページにキーワード

‘internal’があれば、help(foo)はこのヘルプページを与えるが、fooは HTML

ヘルプシステムにあるオブジェクトのアルファベット順のリストも含め、いくつ

かのオブジェクトの索引から除外される。

help.search()はユーザ定義の値を含めてキーワードによる検索ができる: しかし help.start()を経由してアクセスされる ‘サーチエンジン & キーワー

ド’HTMLページはキーワードの定義済みリストのみへのシングルクリックアクセスを提供する。

2.1.2 データセットのドキュメント化

Rのデータセットを文書にする Rdファイルの構造はわずかに異なる。例えば\argumentsや

\valueのようなセクションは必要ではないが、データの形式とソースについては説明されな

ければならない。

例として、標準的なRのデータセットであるriversを文書にしたsrc/library/datasets/man/rivers.Rd

を見てみよう。� �\name{rivers}

\docType{data}

\alias{rivers}

\title{Lengths of Major North American Rivers}

\description{

This data set gives the lengths (in miles) of 141 \dQuote{major}

rivers in North America, as compiled by the US Geological

Survey.

}

\usage{rivers}

\format{A vector containing 141 observations.}

\source{World Almanac and Book of Facts, 1975, page 406.}

\references{

McNeil, D. R. (1977) \emph{Interactive Data Analysis}.

New York: Wiley.

}

\keyword{datasets} これは以下のさらなるマークアップコマンドを使っている。

\docType{...}

文書オブジェクトの“型”を示す。常にデータセットに対しては ‘data’であり、pkg-package.Rd概要ファイルに対しては ‘package’となる。S4メソッドとクラスに対する文書には ‘methods’(promptMethods()が提供)と ‘class’(promptClass()が提供)を用いている。

Page 71: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 65

\format{...}

データセットの形式の記述 (ベクトル、行列、データフレーム、時系列、. . .のように)。行列とデータフレームについては各列の説明を与えるべきであり、リストあるいは表が好ましい。詳しい情報については、See Section 2.4 [リストと表],page 68を参照せよ。

\source{...}

一次資料の詳細 (参考文献またはURL)。さらにセクション\referencesは二次資

料や使用法について与えることができる。

データセット barを文書にするときには次のことにも注意。

• \usage項目は、常に barまたは (データの遅延読み込みを使わないパッケージでは)data(bar)である。(特に、Rdファイル毎に単一のデータオブジェクトだけを文書に

する。)

• \keyword項目は常に ‘datasets’とすべきである。

もし barがデータフレームであれば、データセットが prompt(bar)を通して起動できるよ

うに文書にせよ。そうでなければ、promptData関数が使うことができる。

2.1.3 S4クラスとメソッドのドキュメント化

‘?’オペレータを使う特別な方法がある。すなわち ‘class?topic’や ‘methods?topic’という、それぞれ S4クラスとメソッドに対する文書にアクセスするためのものである。この仕組みは\aliasの項目で使われているトピック名の慣例に依存している。S4クラスとメソッドのトピック名はそれぞれ次のような形式である。

class-class

generic,signature_list-method

ここで signature listは、(空白を含まず)‘,’によって区切られた (引用符無しの)メソッドのシグネチャ内にクラス名を含んでいる。明示的な指定の無い引数に対しては ‘ANY’を用いる。例えば ‘genericFunction-class’は S4クラス"genericFunction"の文書のトピック名で、

‘coerce,ANY,NULL-method’はシグネチャc("ANY", "NULL")を coerceする S4メソッドに対する文書のトピック名である。

S4クラスとメソッドに対する文書のスケルトンは、パッケージmethodsが提供する関数promptClass()と promptMethods()を用いることで生成することができる。もし S4メソッドに対し、(\usageセクション内で)明示的な関数宣言の提供が必要あるいは望まれているのであれば (例えばもし明示的に言及される “意外な引数”がある場合)、次のようなマークアップを使うことができる。

\S4method{generic}{signature_list}(argument_list)

(e.g., ‘\S4method{coerce}{ANY,NULL}(from, to)’).

オンラインドキュメントシステムの潜在力を完全に利用するために、パッケージ内のユー

ザから見えるすべての S4クラスとメソッドは、パッケージの Rdファイルの 1つに適切な少なくとも\alias項目を 1つ持つ必要がある。もしパッケージが元々は別の場所で定義された関数に対するメソッドを持ち、関数の基本的なデフォルトのメソッドを変えないのであれば、

パッケージは生成するメソッドを文書にする責任を持つが、関数自身とデフォルトのメソッ

ドに対しては責任を持たない。

S4置換メソッドは S3のそれと同様の方法で文書化される: Section 2.1.1 [関数のドキュメント化], page 59の\methodの説明を見よ。

Page 72: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 66

S4クラスとメソッドに対するオンラインドキュメントの使用と作成に関する詳しい情報はhelp("Documentation", package = "methods")を参照せよ。

2.1.4 パッケージのドキュメント化

パッケージは\alias pkgname-packageという概要のヘルプページを持つかもしれない。例

えば package?pkgnameとすると、utilsパッケージの ‘utils-package’というヘルプページを開く。もし他の Rdファイルに pkgnameと名づけられたトピックが存在しなければ、追加の

\aliasとしてこれを使うことは役立つであろう。

パッケージの文書のスケルトンは関数 promptPackage()を使って生成することができる。

もし final = TRUE引数が使われていれば、Rdファイルは library(help = pkgname)を実行

することができる情報を含んだ最終形で生成される。それ以外 (既定値)では、内容に対する提案を与えるコメントが挿入されるであろう。

必須の\name、\titleと pkgname-packageエイリアスは別として、パッケージの概要の

ページに対する唯一の要求は\docType{package}という命令文を含むことである。それは

パッケージに不慣れな読者が使用を開始するに当たり、十分な情報を与えるような短い概要

にすることを推奨している。更に広い範囲に及ぶ文書はパッケージビニェットに配置し (seeSection 1.4 [パッケージのビニェットを書く], page 35)、このページから参照されるのがより良い。あるいは、広い範囲に及ぶ文書は関数、データセット、クラスの個々のmanページに置くのがよい。

2.2 セクショニング

例で新しい段落をはじめる、または空白行を残すためには、((La)TEXに見られるように)単に空行を挿入すればよい。改行するには\crを使用せよ。

(例えば\description{}、\value{}などの)定義済みセクションに加え、任意のセクションを\section{section_title}{...}とすることで “定義”することができる。例えば次のようにする。

\section{Warning}{

You must not call this function unless ...

}

事前に割り当てられたセクションとの一貫性のため、セクション名 (\sectionへの最初の引数)は先頭を大文字にしなければならない。最初と 2番目のブレース間の空白は許されていない。セクションの表題内のマークアップ (例えば\code)は latexの変換 (例えば ‘hyperref’のようなマクロパッケージのバージョンに依存している)で問題を起こす可能性があるので、避けるべきである。

\subsectionマクロは\sectionと同様の形式の引数を受け取るが、セクションの内部で

使用されるので、セクションまたは別のサブセクション内のサブセクションをネストするた

めに使うことができる。ネストの深さに関して事前に定義された制限はないが、書式は 3レベル (つまり、セクションの内部のサブセクションのサブセクション)より深いものために設計されていない。

追加の名前付きセクションは、入力のどこに現れようとも、常に出力の固定された位置

(\note、\seealsoや例の前)に挿入されることに注意 (ただし入力中のそれらの順序は保たれる)。

Page 73: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 67

2.3 テキストを目立たせる

以下の論理的マークアップコマンドはテキストの強調や引用に利用することができる。

\emph{text}

\strong{text}

可能であれば italicや boldフォントを用いて textを強調する; \strongはより強い (より強調した)ものと見なされる。

\bold{text}

可能であれば textを boldフォントに設定する。

\sQuote{text}

\dQuote{text}

移植性のある一重引用符ないしは二重引用符で textを囲う (引用符の記号に使われた文字を接続することなく)。

上記のコマンドのそれぞれは LATEX系の入力を受け取るので、他のマクロが textの内部で使うことができる。

以下の論理的マークアップコマンドは特定の種類のテキストを示すために利用できる。特に

指定のない限り、それらは逐語的なテキスト入力を受け取り、そのため他のマクロはマークアッ

プコマンドの内部で使えない。いくつかの文字はエスケープする必要がある (see Section 2.8[挿入], page 71)。

\code{text}

Rプログラムの一部のリテラル例となるテキストを示す。例えばRコードの断片や Rオブジェクトの名前である。テキストは R系の構文で入力され、可能であれば typewriterフォントを利用して表示する。マクロ\varと\linkは textの内部で解釈される。

\preformatted{text}

プログラムの一部のリテラル例となるテキストを示す。テキストは可能であれば

typewriterフォントを用いて表示される。書式設定、例えば改行は保持される。

エラーや不正フォーマットが原因となり、これを書いている時点での LATEXにある制限のため、このマクロは\dQuoteと\sQuote以外の他のマクロ内でネストす

ることができない。

\kbd{keyboard-characters}

可能であれば slanted typewriterフォントを使ったキーボード入力を示す。そ

のためユーザはコンピュータ出力から入力されるであろう文字を区別することが

できる。テキストは逐語的に入力される。

\samp{text}

逐語的に入力された、文字列のリテラル例であるテキストを示す。折り返しや書

式の再設定は発生しない。可能であれば typewriterフォントを用いて表示する。

\verb{text}

例えば\varのような解釈を伴わないが、ワードラップされたテキストの内部に

含められるであろう文字列のリテラル例であるテキストを示す。可能であれば

typewriterフォントを使って表示する。

\pkg{package_name}

Rパッケージの名前を示す。LATEX系。

Page 74: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 68

\file{file_name}

ファイル名を示す。テキストは LATEX系なので、バックスラッシュはエスケープされる必要がある。可能であれば異なるフォントを用いて表示する。

\email{email_address}

電子メールアドレスを示す。LATEX系で、HTMLと PDF変換ではハイパーリンクとして表される。可能であれば typewriterフォントを用いて表示される。

\url{uniform_resource_locator}

World Wide Webに対する統一資源位置指定子 (URL)を示す。引数は文字通りに扱われ、HTMLとPDF変換ではハイパーリンクとして表される。可能であれば typewriterフォントを用いて表示される。

\href{uniform_resource_locator}{text}

World Wide Webへのハイパーリンクを示す。最初の引数は文字通りに扱われ、ハイパーリンクの URLとして使われる。2番目の引数はユーザに表示する LATEX系のテキストである。

\var{metasyntactic_variable}

メタ構文変数を示す。ある場合にはこれは異なって表示される。例えばイタリッ

ク体で表示されるが、すべてでそのようには表示されない 5。LATEX系。

\env{environment_variable}

環境変数を示す。逐語的。可能であればtypewriterフォントを用いて表示される。

\option{option}

コマンドラインオプションを示す。逐語的。可能であれば typewriterフォント

を用いて表示される。

\command{command_name}

コマンド名を示す。LATEX 系で、そのため\varは解釈される。可能であれば

typewriterフォントを用いて表示される。

\dfn{term}

用語の紹介や使用の定義を示す。LATEX系。

\cite{reference}

例えば本の名前のように、\linkを通した直接の相互参照がない参照を示す (seeSection 2.5 [相互参照], page 69)。LATEX系。

\acronym{acronym}

例えばGNUのような頭字語 (すべての大文字で書かれた省略形)を示す。LATEX系。

2.4 リストと表

1つ以上の\itemコマンドがあるかもしれないその中で、\itemizeや\enumerateコマンドは

単一の引数を取る。各\itemに続くテキストは、適切に字下げされ、最初の段落が箇条書きの

印 (\itemize)または数字 (\enumerate)で印付けられた 1つ以上の段落に整形される。

引数リストとは異なり、これらの書式で書かれた\itemには空白とテキストが続く (ブレースで閉じられていない)。例えば次の通り。

5 現在のところ、これは HTML変換と ‘\usage’と ‘\examples’環境の外部での LATEX変換においてのみ異なって表示される。

Page 75: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 69

\enumerate{

\item A database consists of one or more records, each with one or

more named fields.

\item Regular lines start with a non-whitespace character.

\item Records are separated by one or more empty lines.

}

\itemizeと\enumerateコマンドはネストされる可能性がある。

\describeコマンドは\itemizeに似ているが、初期ラベルを指定することができる。各

\itemは、引数または値\itemと完全に同じ方法で、項目のラベルと本文という 2つの引数をとる。\describeコマンドはHTMLでは<DL>リストに、LATEXでは\descriptionリストに割

り当てられる。

\tabularコマンドは 2つの引数を受け取る。最初の引数は各列で必要とされる整列のために与え (左詰めの ‘l’、右詰めの ‘r’、センタリングの ‘c’)、2番目の引数は\crによって区切

られた任意の行数からなる。そしてフィールドは\tabで区切られている。例えば次のように

なる:

\tabular{rlll}{

[,1] \tab Ozone \tab numeric \tab Ozone (ppb)\cr

[,2] \tab Solar.R \tab numeric \tab Solar R (lang)\cr

[,3] \tab Wind \tab numeric \tab Wind (mph)\cr

[,4] \tab Temp \tab numeric \tab Temperature (degrees F)\cr

[,5] \tab Month \tab numeric \tab Month (1--12)\cr

[,6] \tab Day \tab numeric \tab Day of month (1--31)

}

最初の引数の整列があるので、各行のフィールドは同じ数でなくてはならず、フィールドは

非空でなくてはならない (ただし空白のみを含むことはできる)。(\tabularと最初の引数の間、2つの引数の間に空白はない。)

2.5 相互参照

マークアップ\link{foo}は (通常\code{\link{foo}}の組み合わせの中で)fooのヘルプへのハイパーリンクを生成する。ここで fooは topicであり、すなわち (おそらく他のパッケージ内にある)他の Rdファイルの中の\aliasマークアップの引数である。ハイパーリンクは Rdが

変換される形式のいくつかでサポートされている。例えばHTMLやPDF形式でサポートされるが、例えばテキスト形式など他の形式では無視される。

\linkの主な使用の 1つはヘルプページの\seealsoセクション内である。see Section 2.1[Rd書式], page 58。

先頭と末尾の空白が\aliasからトピックを抜き出すときに除去される一方で、\linkのト

ピックを検索するときには除去されないことに注意。

名前 nameを持つトピック destへリンクする\link[=dest]{name}により、そのトピッ

ク名以外の異なるトピックへのリンクを指定することができる。これは S3/4 クラスの文書を参照するために使うことができる。例えば\code{"\link[=abc-class]{abc}"}

は自身のパッケージ中で定義された S4 クラス"abc"の文書へ参照する方法であり、

\code{"\link[=terms.object]{terms}"}は S3"terms"クラスの文書への参照する方法である (パッケージ stats にある)。ソースファイル中でこれらを読みやすくするために、\code{"\linkS4class{abc}"}は上で与えられた形式を拡張する。

Page 76: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 70

パッケージ pkgのファイル foo.htmlと bar.htmlにそれぞれリンクする\link[pkg]{foo}

や\link[pkg:bar]{foo}のように指定される 2つの他の形式がある。これらはおそらくまだインストールされていないパッケージ (ただし HTMLヘルプシステムが実行時に解決する)、あるいは複数のパッケージがトピックに関してヘルプを提供するという通常望ましくない事

象 6(存在するパッケージが優先権を持つ場合であり、そのためこれは他のパッケージを参照するためだけに必要とされる)を参照するため、これらはほとんど必要とされていない。これらは現時点でHTMLヘルプ (そしてヘルプページの LATEX変換中のハイパーリンクを無視する)とトピックというよりもファイルへのリンクにのみ使われている (どのトピックはアンインストールされたパッケージ中のファイルにあったかを知る方法がないため)。baseと推奨パッケージに対し、これらを使う唯一の理由は検索パスのさらに下にあるパッケージを参照

することを強制するためである。これらは頻繁に誤って使われるため、HTMLヘルプシステムはもしファイル foo.htmlが見つからなければ、パッケージ pkg内のトピック fooを探す。

2.6 数学

数式は印刷される文書用に美しくされなければならないが、まだ我々はテキストと HTMLオ

ンラインヘルプに役立つ何かが欲しいと思っている。これを終わらせるため、2つのコマンド\eqn{latex}{ascii}と\deqn{latex}{ascii}が使われている。\eqnが (TEXの$...$に対

応する)“インライン”数式に使われているのに対し、\deqnは (LATEXの displaymath、また

はTEXの$$...$$にあるように)“表示される数式を与える”。どちらの引数も逐語的なテキストとして扱われる。

どちらのコマンドも後に latexと asciiの両方に対して使える\eqn{latexascii}として扱

うこともできる。コマンドと最初の引数の間、最初の引数と 2番目の引数の間に空白は許されていない。

以下の Poisson.Rdからの例である:

\deqn{p(x) = \frac{\lambda^x e^{-\lambda}}{x!}}{%

p(x) = \lambda^x exp(-\lambda)/x!}

for \eqn{x = 0, 1, 2, \ldots}.

LATEXのマニュアルに対して、これは次のようになる。� �p(x) = λx e−λ

x!

for x = 0, 1, 2, . . .. オンラインヘルプのテキストに対しては、次のものを得る。� �

p(x) = lambda^x exp(-lambda)/x!

for x = 0, 1, 2, .... ギリシャ文字 (大文字、小文字のどちらも)は、もしバックスラッシュが先にあればHTML

で表示され、\dotsと\ldotsは 3点リーダとして、\sqrt、\geと\leは数学記号として表示

される。

6 CRANパッケージにおける一般的な例は\link[mgcv]{gam}である。

Page 77: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 71

例えばAMS extensionsのようなLATEXスタイルファイルを指定する用意がないことから、基本的な LATEXのみしか使えないことに注意。

2.7 図

ヘルプページに図を含めるには\figureマークアップを使用せよ。3つの形式がある。

2つの一般的に使われる単純な形式は\figure{filename}と\figure{filename}{alternate

text}である。これはHTMLまたは LATEXの出力のどちらかに図のコピーを含める。テキスト出力では、別のテキストが代わりに表示される。(2 番目の引数が省略されたとき、ファイル名が使われる。) ファイル名と代わりのテキストはそのまま構文解析され、それらにHTMLや LATEXで重要な特殊文字を含めるべきではない。

専門の形式は\figure{filename}{options: string}である。(‘options:’という語は見えているように正確に入力し、かつ少なくとも 1つの空白が続くように入力しなければならない)この形式では、stringは src属性が続く属性として、HTMLの imgタグの内部に複製さ

れる。または初期設定では\includegraphics呼び出しのオプションとして使われる、LaTeXの\Figureマクロの第 2引数に複製される。任意の単一の文字列がどちらの表示モードに対しても十分とは考えにくいので、専門の形式は通常、条件に覆われる。正当な HTML/LaTeXが使われているか確認するのは作者次第である。例えばHTML(単純な形式)と LaTeX(専門の形式)の両方にロゴを含めるため、次のものを使うことができる:

\if{html}{\figure{logo.jpg}{Our logo}}

\if{latex}{\figure{logo.jpg}{options: width=0.5in}}

図を含むファイルはディレクトリ man/figuresに保存されるべきである。そのディレクト

リの拡張子.jpg、.pdf、.pngと.svgを持つファイルはインストール時に help/figuresディ

レクトリにコピーされる。(PDF形式中の図は大部分のHTMLブラウザでは表示されないが、リファレンスマニュアルでは最善の選択である。)\figure指示文内で man/figuresからの相

対ファイル名を指定せよ。

2.8 挿入

Rシステム自身に対して\Rを使用せよ。関数の引数リスト ‘...’ のドットに対して\dots、一

般的なテキスト中の 3点リーダに対して\ldots を使用せよ。7これらは{}が続けることがで

き、空白は続かないようにするべきである。

エスケープされていない ‘%’の後ろに、ヘルプテキストに関する自身のコメントを置くことができる。行の残りは (最後の改行を除いて)完全に無視される。従って、“ヘルプ”の一部を見えないようにするために ‘%’を使うことができる。

バックスラッシュをもう 1つのバックスラッシュによってエスケープすることができる。(\crは改行を生成するために使われることに注意。)

“コメント”文字 ‘%’と対になっていないブレース 8はほぼ常に ‘\’によってエスケープされる必要がある。‘\\’はバックスラッシュに用いることができ、2つ以上の隣り合うバックスラッシュがあるときにそのようにする必要がある。R系のコードでは、引用符で囲まれた文字列はわずかに異なる処理がされる; 詳細は “Parsing Rd files” (http://developer.r-project.

7 \dotsと\ldotsにはわずかな違いしかない。コードブロックで\ldotsを使うことは技術的に正しくなく、tools::checkRdはこれについて警告を出す – 一方で、現在の変換機は、他の場所に LaTeX 内で小さな違いがあることは別として、\dotsや\ldotsをコードブロック中で同様の方法で扱う。

8 例としてファイル Paren.Rdの例の項目尾を参照せよ。

Page 78: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 72

org/parseRd.pdf)を参照せよ – 特にブレースは引用符で囲まれた文字列の内部でエスケープしてはならない。

‘% { } \’はいずれも LATEX系テキストではエスケープすべきである。

異なるエンコーディングで表現される必要のあるテキストは\encによって印をつけておく

べきである。例えば\enc{Joreskog}{Joreskog}(ブレースの間に空白を入れない)で、最初の引数はエンコーディングが許される環境で使われ、2番目の引数はASCIIとしなければなら

ない (これは例えばエンコードされた形式で表せないロケールにおけるテキスト変換などに使われる)。(\encは個々の単語に対して使われることを意図しており、文全体や段落全体に対するものではない。)

2.9 索引

\aliasコマンド (see Section 2.1.1 [関数のドキュメント化], page 59)はパッケージ中の関数、変数、データセット、S4クラスとメソッドなどすべてのRオブジェクトを含めて文書化された “トピック”を指定するために使われる。オンラインヘルプシステムはすべてのエイリアストピックを含む索引データベースを検索する。

さらに help.search()の検索に使うことができる、\conceptを使う “概念の索引エントリ”を提供することができる。例えば、標準パッケージ statsのファイル cor.test.Rdは次の

ものを含む。

\concept{Kendall correlation coefficient}

\concept{Pearson correlation coefficient}

\concept{Spearman correlation coefficient}

その結果、例えば??Spearmanとすれば、スピアマンの ρを使った対になるサンプル間の関係の調査に関するヘルプページを見つけることができるであろう。

(help.search()ページは追加のマークアップがない文書オブジェクトの “セクション”のみを用いていることに注意。)

もし\linkを経由して他のヘルプファイルからそのような項目と相互参照させたいという

場合には、\aliasを使い、\conceptを使わないようにする必要がある。

2.10 プラットフォーム固有の文書

ときどきプラットフォームごとに文書がことなる必要がある。現在、2つの OS固有のオプション ‘unix’と ‘windows’が利用可能であり、OS固有の包含、除外のために、

#ifdef OS

...

#endif

あるいは

#ifndef OS

...

#endif

にヘルプソースファイルの行を含めることができる。そのようなブロックは入れ子にするべ

きではなく、全体をブロック (つまり、セクションや項目のブレースの始まりと終わりの間)の内部に入れるか、1つ以上の完全なセクションの最上位にあるべきである。

もしプラットフォーム間の違いが大きい、あるいは文書化されたRオブジェクトが 1つのプラットフォームにのみ関係があるという場合、プラットフォーム固有の Rdファイルを unix

あるいは windowsサブディレクトリに置くことができる。

Page 79: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 73

2.11 条件付きテキスト

1つの出力形式に対する最善の内容は、別の出力形式に対するそれとはときおり異なることがある。このような状況のため、\if{format}{text}や\ifelse{format}{text}{alternate}

マークアップが利用される。ここで formatは、textを表すコンマ区切りのリスト形式である。もし形式が合わなければ、alternateが表示される。textと alternateの両方ともテキストとマークアップの任意の列とすることができる。

現時点で、以下の形式が認識される: example、html、latexと text。これらの選択が対

応する目標を出力する。(exampleは他の形式で表示された例ではなく、抽出したコード例を参照することに注意。)また TRUE(すべての形式に一致する)と FALSE(どの形式にも一致しない)も受け入れられている。これらは\Sexprマクロの出力になることもある (see Section 2.12[動的なページ], page 73)。

\out{literal}マクロは大抵\if{format}{text}の textの部分内で使われる。これは描画させるものに、特殊文字をエスケープしようとせずに、文字テキストを正確に出力させる

ことになる。例えば LATEXやHTMLでギリシャ文字、別形式でテキスト文字列 alphaを表示

するために必要なマークアップを出力するには以下のものを使用せよ:

\if{latex}{\out{\alpha}}\ifelse{html}{\out{&alpha;}}{alpha}

2.12 動的なページ

動的に生成されたmanページをサポートする 2つのマクロ\Sexprと\RdOptsが R 2.10.0で導入された。これらは Swaveにならってモデル化され、Rdファイル内で実行形式なR式を含めることを意図している。

\Sexprへの主な引数は実行できる有効な Rコードでなければならない。主な引数の前には角括弧に入ったオプションを取るかもしれない。オプションに依存してコードはパッケー

ジのビルド時、またはmanページを描画するときに実行される可能性がある。

オプションは Sweaveと同じ形式に従うが、異なるオプションがサポートされている。現時点で、使用可能なオプションとその既定値は次の通り:

• eval=TRUE Rのコードを評価する必要があるかどうか。

• echo=FALSE Rのコードをエコーする必要があるかどうか。もし TRUEであれば、ディス

プレイは整形済みブロックに与えられる。例えば、\Sexpr[echo=TRUE]{ x <- 1 }は次

のように表示されるであろう。

> x <- 1

• keep.source=TRUE コードを表示するときに作者の書式設定を維持するか、それを捨て

て逆パース版を使用するか。

• results=text どのように結果を表示するか。可能性があるものは次の通り:

− results=text コードの結果に as.character()を適用し、それをテキスト要素と

して挿入する。

− results=verbatim コードの結果を単にコンソールで実行したかのように印字し、

逐語的に印字された結果を含む (見えない結果は印字されない。)。

− results=rd 結果は所定の位置に挿入され、parse_Rd()に渡されるマークアップを

含む文字ベクトルであると仮定される。これは例えば、計算されたエイリアスを挿

入するために使われる。R 2.13.1-patched以降、parse_Rd()は最初に単一のRdセクションマクロを挿入することを可能にする fragment=FALSEを伴って呼ばれる。も

しそれが失敗すたら、parse_Rd()は古い動作である、fragment=TRUEにして再び呼

ばれる。

Page 80: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 74

− results=hide 出力を何も挿入しない。

• strip.white=TRUE もし strip.white=TRUEであれば、各行の先頭と末尾の空白を取り

除く。strip.white=allであれば、すべての空白行も取り除く。

• stage=install いつこのマクロを実行するかを制御する。取りうる値は、

− stage=build ソースの tar書庫をビルドする際に実行する。

− stage=install ソースからインストールする際に実行する。

− stage=render ヘルプページを表示する際に実行する。

例えば#ifdefのような条件は buildマクロの後、installマクロの前に適用される。特

定の状況 (例えば tar書庫を使わずソースディレクトリから直接インストールする、あるいはバイナリパッケージを構築する)では、上記の説明は文字通りに正確ではないが、作者は実行されるすべての場面で build、#ifdef、install、renderという順序を信頼す

ることはできる。

コードは各場面で一度だけ実行されるため、\Sexpr[results=rd]マクロは後の段階を

意図した\Sexprマクロを出力することができるが、現在あるいはそれより前の場面を意

図した\Sexprマクロは出力できない。

• width, height, fig 現時点で、これらのオプションをとることは許されているが、無

視される。

\RdOptsマクロは、オプションの新しい既定値を続く\Sexprの使用に適用する設定するた

めに使われる。

更なる詳細についてはオンラインドキュメント “Parsing Rd files” (http://developer.r-project.org/parseRd.pdf) を参照せよ。

2.13 ユーザ定義のマクロ

ユーザ定義マクロをサポートする 2つの新しいマクロがR 2.12.0で導入された。\newcommandと\renewcommandマクロは新しいマクロをRdファイル内に定義することを可能にしている。これらは同名の LaTeXマクロと似ているが、同一ではない。

どちらも文字通りに構文解析される 2つの引数をとる。最初の引数は先頭にバックスラッシュを含む新しいマクロの名前、2番目の引数はマクロの定義である。LATEXに見られるように、\newcommandは予め定義されていない新しいマクロを必要とするが、一方で\renewcommand

は置換される (ビルトインのマクロを含め)既存のマクロをとることが許されている。

また LATEXにあるように、定義された新しいマクロは引数をとる可能性があり、例えば#1

のような数値プレースホルダはマクロの定義内で使われる。しかし、LATEXとは異なり、引数の数はマクロの定義に見られるプレースホルダの番号で一番大きな値から自動的に決めら

れる。例えば#1と#3(ただし他のプレースホルダはない)を含むマクロは 2つの引数マクロを定義することになる (2番目の引数は無視される)。LATEXと同様、最大で 9つの引数を定義することができる。もし#文字が数字でないものが続いていた場合、それは特別な意味を持たな

くなる。ユーザ定義のマクロがとる全ての引数は逐語的なテキストとして構文解析され、簡

素なテキスト置換がプレースホルダを置換するために使用され、その後で置換テキストが構

文解析される。

例えば、NEWS.Rdファイルは現在のところ次の定義を使用している。

\newcommand{\PR}{\Sexpr[results=rd]{tools:::Rd_expr_PR(#1)}}

これは\PRを 1つの引数をとるマクロと定義している; そして次のようなコード

Page 81: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 75

\PR{1234}

は構文解析されたときに、

\Sexpr[results=rd]{tools:::Rd_expr_PR(1234)}

と展開される。

2.14 エンコーディング

Rdファイルはテキストファイルであるので、ASCIIでない限り、ファイルが書かれているエン

コーディングを推測することは不可能である: 8ビット文字を持つファイルはUTF-8、Latin-1、Latin-9、KOI8-R、EUC-JPなどがあり得る。そのため\encoding{}の項目は、エンコーディ

ングが ASCIIでなければそのエンコーディングを明記するために使われなければならない。

(\encoding{}セクションは単独の行になっていなければならない。具体的には非 ASCII文字

を含まない場合である。もし Rdファイルでエンコーディングが宣言されていないのであれば、DESCRIPTIONファイルで宣言されたエンコーディングが使われる。)Rdファイルは構文解析の前にUTF-8に変換されるので、ファイル自身の好ましいエンコーディングは今はUTF-8である。

可能な限り、Rdファイルに非ASCII文字を含めることを避け、(テキストを描画するために意図されたフォントで消えてしまう可能性があることから、)verbatim環境の外部で例えば‘<’、‘>’、‘$’、‘^’、‘&’、‘|’、‘@’、‘~’と ‘*’のような記号さえを使うことを避けよ。(パッケージtools中の関数 showNonASCIIfileはファイル中の非 ASCIIバイトを見つけることに役立つ可

能性がある。)

便宜上、エンコーディング名 ‘latin1’と ‘latin2’は常に認識される: これらと ‘UTF-8’はかなり幅広く動作する傾向にある。しかしながら、これは UTF-8のすべての文字が認識されることと、非 Latin文字 9 の被覆率がかなり低いということを意味していない。LATEXのinputenx(Rの?Rd2pdfを参照せよ)を使うと、より高いUTF-8の被覆率を与えるであろう。

\encコマンド (see Section 2.8 [挿入], page 71)は宣言されたエンコーディングをサポートしていない変換で使われる翻字を与えるために使うことができる。

LATEXの変換は宣言されているエンコーディングから UTF-8にファイルを変換し、コマンド

\inputencoding{utf8}

を含み、そしてこれは\usepackage{inputenc}コマンドの適切な呼び出しによって一致させ

る必要がある。RユーティリティR CMD Rd2pdfは変換されたコードを見て、使用されている

エンコーディングをインクルードする: 例えば次のものを使用する。

\usepackage[utf8]{inputenc}

(エンコーディングとして utf8を使用することは 2003/12/01 以降の日付がつけられた LATEX を使うことを必要とする。また、‘UTF-8’中のキリル文字の使用は‘\usepackage[T2A]{fontenc}’も必要と思われ、R CMD Rd2pdfはファイル t2aenc.defが存

在していることと環境変数_R_CYRILLIC_TEX_が設定されているという条件でこれをインク

ルードする。)

この仕組みはラテン文字を使ったときに最も上手く動作する: LATEX中のUTF-8の被覆率はかなり低い。

9 R 2.9.0は LATEX中の UTF-8 キリル文字へのサポートを追加したが、いくつかの OSでは LATEXへのキリル文字へのサポートを追加する必要があり、これを可能にするために、環境変数_R_CYRILLIC_TEX_を空でない値に設定する必要があるだろう。

Page 82: Rの拡張を書く (R 2.15.2)

Chapter 2: Rのドキュメントを書く 76

2.15 Rd書式の処理

システムコマンドラインからRdファイルを処理するためのコマンドがいくつかある。

R CMD Rdconvを使うと、Rの文書フォーマットを他の形式に変換することや、ランタイム検査のために実行形式の例を抽出することができる。現在サポートされている変換は普通の

テキスト、HTMLと LATEXへの変換、および例の抽出である。

R CMD Rd2pdfは、明示的に、あるいはパッケージのソースのあるディレクトリへのパスの

どちらかで指定された Rdファイルの文書から、PDF出力を生成する。後者では、パッケージ中のすべての文書化されたオブジェクトに対する参照マニュアルが、DESCRIPTIONファイル

中の情報も含めた上で生成される。

R CMD Sweaveと R CMD Stangleは (通常は拡張子 ‘.Snw’または ‘.Rnw’を持つ)‘Sweave’文書ファイルを処理する: R CMD StangleはRコードの断片を抽出するために使われる。

これらすべてのコマンドに対する正確な使用方法と利用可能なオプションの詳細な一覧は

R CMD command --helpを実行することで得られる。例えば R CMD Rdconv --helpとする。す

べての利用可能なコマンドは R --helpとすることで一覧が得られる (あるいはWindowsではRcmd --helpとする)。

これらのすべてがWindows で動作する。必要とされていることのすべては一般的にはLATEXのインストールであるが、“R Installation and Administration”マニュアルに書かれているように、ソースからパッケージをビルドするためのツールをインストールする必要が

あるかもしれない。

2.16 Rdファイルの編集

構文の理解、コマンドのハイライト、構造を示すインデントやブレースの不一致の検出など

をするエディタを利用して.Rdファイルを用意することはとても役立つかもしれない。

これに対し、もっともよく使われているシステムは ESSパッケージ (http: / / ess .

r-project.org/: しばしば Emacsと一緒にインストールされるが、ロードする必要があるか

もしれず、別々にインストールする必要さえあるかもしれない) のある Emacs(XEmacsを含む)である。

似たようなものは Stat-ETプラグイン (http://www.walware.de/goto/statet)のあるEclipse IDEと、(Windows限定で)Tinn-R (http://sourceforge.net/projects/tinn-r/)である。

.Rdファイルは LATEXファイルにかなり似ているので、人々はエディタの LATEXモードも使っている。

例えば RStudio(http://rstudio.org/)のように、いくつかの Rのフロントエンドでは.Rdファイルの編集のサポートを提供している。

Page 83: Rの拡張を書く (R 2.15.2)

Chapter 3: Rコードの整理とプロファイリング 77

3 Rコードの整理とプロファイリング

パッケージ中に維持し、多分他の人が使えるようにしている価値がある Rコードは文書化、整理、そして恐らく最適化するに値する。これらの最後 2つの活動がこの章の主題である。

3.1 Rコードの整理

パッケージからロードされた関数のコードとユーザから入力されたコードをRは異なった扱い方をする。デフォルトではユーザから入力されたコードは内部に保存されるソースコード

を持ち、関数がリストに載ったときに、元のソースが再生される。パッケージからロードし

たコードは (デフォルトでは)ソースコードが処分され、関数の構文解析木から関数のリストが再生成される。

通常ソースコードを維持しておくことはよい考えであり、特にソースからコメントが除去

されるのを避ける。しかしながら、例えば一貫したインデントと演算子周りの空白を持つ、整

理された版の関数を生成するため、関数の構文解析木から関数のリストを再構築する能力を

利用することができる。もし元のソースが標準的な形式に従っていなければ、この整理され

た版はより読みやすい可能性がある。

ソースの保存を破棄する方法は 2通りある。

1. コードがRへ読み出される前に、オプション keep.sourceを FALSEに設定することがで

きる。

2. 保存されたソースコードは removeSource()を呼び出すことにより除去することができ

る。例えば次のようにする。

myfun <- removeSource(myfun)

どちらの場合も、もし関数を一覧にすれば、標準的なレイアウトを得るであろう。

整理したいと思っている関数 myfuns.Rのファイルがあるとしよう。次のようなコードを

含むファイル tidy.Rを作成する。

source("myfuns.R", keep.source = FALSE)

dump(ls(all = TRUE), file = "new.myfuns.R")

そしてソースファイルとして、これを使ってRを実行する。例えば R --vanilla < tidy.Rと

する、または Rセッションにペーストすることによる。すると、ファイル new.myfuns.Rは

標準的なレイアウトでアルファベット順に並んだ関数を含むであろう。警告: 関数内のコメントは失われるであろう。

標準的な形式はさらなる整頓のよい出発点を与える。逆パースではそうはできないのだが、

(‘=’よりも)好ましい代入演算子 ‘<-’を代入に一貫して使うことを推奨する。多くのパッケージの作者はRコードの編集に、ESS Emacsパッケージの ESS[S]モードを使った Emacsのバージョン (Unix系、またはWindows上)を使用している。R自身のソースコードに対して推奨された ESS[S]モード内のスタイルオプションについては、Section “R coding standards” inR Internalsを参照せよ。

3.2 速度のためにRコードを整理する

Windowsと Rの大部分 1のUnix系バージョンにおいて、Rコードのプロファイルをすることが可能である。

1 これを可能にするために Rはビルドされる必要があり、オプション--enable-R-profilingがデフォルトである。

Page 84: Rの拡張を書く (R 2.15.2)

Chapter 3: Rコードの整理とプロファイリング 78

コマンド Rprofはプロファイリングを制御するために使用され、そのヘルプページで完全

な詳細を調べることができる。プロファイリングは固定された記録間隔 2(初期値は 20ミリ秒)ごとに、どのRの関数が使われているか記録し、ファイルに結果を記録する (初期値は作業ディレクトリの Rprof.out)動作をする。すると関数 summaryRprofまたはコマンドライン

ユーティリティR CMD Rprof Rprof.outが行動の要約のために使うことができる。

例として以下のコードを考えよう (Venables & Ripley, 2002, pp. 225–6に由来する)。

library(MASS); library(boot)

storm.fm <- nls(Time ~ b*Viscosity/(Wt - c), stormer,

start = c(b=30.401, c=2.2183))

st <- cbind(stormer, fit=fitted(storm.fm))

storm.bf <- function(rs, i) {

st$Time <- st$fit + rs[i]

tmp <- nls(Time ~ (b * Viscosity)/(Wt - c), st,

start = coef(storm.fm))

tmp$m$getAllPars()

}

rs <- scale(resid(storm.fm), scale = FALSE) # 平均の除外Rprof("boot.out")

storm.boot <- boot(rs, storm.bf, R = 4999) # プロファイルするには十分遅いRprof(NULL)

これを走らせたので、次のように結果を要約することができる。

R CMD Rprof boot.out

Each sample represents 0.02 seconds.

Total run time: 22.52 seconds.

Total seconds: time spent in function and callees.

Self seconds: time spent in function alone.

% total % self

total seconds self seconds name

100.0 25.22 0.2 0.04 "boot"

99.8 25.18 0.6 0.16 "statistic"

96.3 24.30 4.0 1.02 "nls"

33.9 8.56 2.2 0.56 "<Anonymous>"

32.4 8.18 1.4 0.36 "eval"

31.8 8.02 1.4 0.34 ".Call"

28.6 7.22 0.0 0.00 "eval.parent"

28.5 7.18 0.3 0.08 "model.frame"

28.1 7.10 3.5 0.88 "model.frame.default"

17.4 4.38 0.7 0.18 "sapply"

15.0 3.78 3.2 0.80 "nlsModel"

12.5 3.16 1.8 0.46 "lapply"

12.3 3.10 2.7 0.68 "assign"

...

2 Unix系ではこれらは CPU時間の間隔であり、Windowsでは経過時間の間隔である。

Page 85: Rの拡張を書く (R 2.15.2)

Chapter 3: Rコードの整理とプロファイリング 79

% self % total

self seconds total seconds name

5.7 1.44 7.5 1.88 "inherits"

4.0 1.02 96.3 24.30 "nls"

3.6 0.92 3.6 0.92 "$"

3.5 0.88 28.1 7.10 "model.frame.default"

3.2 0.80 15.0 3.78 "nlsModel"

2.8 0.70 9.8 2.46 "qr.coef"

2.7 0.68 12.3 3.10 "assign"

2.5 0.64 2.5 0.64 ".Fortran"

2.5 0.62 7.1 1.80 "qr.default"

2.2 0.56 33.9 8.56 "<Anonymous>"

2.1 0.54 5.9 1.48 "unlist"

2.1 0.52 7.9 2.00 "FUN"

...

(関数名はWindows上では引用符で囲まれない。)これはしばしば驚くべき結果を生み出し、ボトルネックとコンパイル済みコードで置き換えることから利益が得られるRのコード片を特定するために使うことができる。

2つの警告: プロファイリングはわずかに余分な実行時間を課す。そして、もし既定のサンプリング間隔で長時間の実行がプロファイルされると出力ファイルはとても大きくなるこ

とがある。

短い時間プロファイリングすることはしばしば誤った結果を導くことがある。Rはときどき使われていないメモリを再利用するためにガーベージコレクションを実施する。これはプ

ロファイリングがたまたまガーベージコレクションを引き起こすどの関数に対しても負担を

かけ、かなりの時間がかかる。gc()を呼び出したすぐ後のコードのプロファイリングと、先

に gcの呼び出しをしないで実行したプロファイリングを比較することが役立つかもしれない。

出力のより細かい分析は CRANパッケージの proftools (http://CRAN.R-project.org/package=proftools)と profr (http://CRAN.R-project.org/package=profr)にあるツールを利用することにより達成できる: 特にこれらはコールグラフを詳しく調べることを可能にする。

3.3 メモリ使用量のためにRコードを整理する

Rコード内でのメモリ使用を測定することは、コードが都合よく利用可能な量より多いメモリを使うとき、あるいはメモリ割り当てとオブジェクトのコピーが遅いコードの原因であると

きのときのどちらにも役立つ。Rのコードで長い時間をかけてメモリ使用をプロファイルする3つの方法がある。3つともすべて、Rが--enable-memory-profilingを用いてコンパイル

されることを要請している。これはデフォルトではないが、現在ではMax OS XとWindowsバイナリディストリビューションで使われている。異なった理由からすべて誤解を招く可能

性がある。

メモリプロファイルを理解する際に、Rのメモリ割り当てについてもう少し知るのは有益である。gc()の結果を見ると、メモリを Vcellsへ分割したものは、ベクトルの内容を保存す

るために使われている。Ncellsへ分割したものは、型や長さのようなベクトルに対する管理

オーバーヘッドを含め、他のすべてを保存するために使われていることを示している。事実、

ベクトルの内容は 2つのプールに分けられる。小さなベクトルに対するメモリ (初期設定では128バイト以下)は大きなチャンクから得られ、Rによって一部が与えられる; 大きなベクトルに対するメモリはオペレーティングシステムから直接得られる。

メモリ割り当てがインタプリタコード内で明らかなことがある。例えば

y <- x + 1

Page 86: Rの拡張を書く (R 2.15.2)

Chapter 3: Rコードの整理とプロファイリング 80

は新しいベクトル yに対してメモリを割り当てをする。Rはその引数の ‘値渡し’の約束を果たす義務があるため、他のメモリ割り当ては目立たず発生する。引数が関数に渡されると、そ

れはすぐにはコピーされない。コピーは (必要があれば)引数が修正されたときに限り発生する。これは驚くべきメモリ使用になる可能性がある。例えば、‘survey’パッケージでは次のようなコードがある。

print.svycoxph <- function (x, ...)

{

print(x$survey.design, varnames = FALSE, design.summaries = FALSE,

...)

x$call <- x$printcall

NextMethod()

}

x$callへの代入がオブジェクト xの全体がコピーされることを起こすことは明らかではないか

もしれない。この値渡しの錯覚を維持するためのコピーは通常、内部のCの関数 duplicate

によってなされる。

メモリ使用のプロファイリングが難しい主な理由はガーベージコレクションである。メモ

リはRプログラム内で明確に定義された回数割り当てられるが、ガーベージコレクタがたまたま走るといつでも解放される。

3.3.1 Rprofのメモリ統計値

前のセクションで書かれた、サンプリング型プロファイラ Rprofはオプション

memory.profiling=TRUEが与えられる可能性がある。すると Rprofは各サンプリング間隔

で、小さなベクトル、大きなベクトル、consセルまたはノードの割り当てたRのメモリの合計を書き出す。またRオブジェクトを複製するために呼び出される内部関数 duplicateへの

呼び出しの回数も書き出す。summaryRprofはこの情報の要約を提供する。これが誤解を招

く可能性がある主な理由は、メモリの使用量はサンプリング間隔の最後に実行中の関数に起

因するためである。2番目の理由はガーベージコレクションが使用中のメモリ量を減らす可能性があり、関数のメモリ使用が少なく見えるためである。gctortureの下で実行すること

は 2つの問題に役立つ: 効果的にサンプリングの頻度を増やすためにコードを遅くして、各ガーベージコレクションに少量のメモリ解放をさせる。mem.limits()を用いてメモリの上

限を変えるを変えることも、異なるメモリ条件下でコードがどのように動作するかを見るた

めに役立つ。

3.3.2 メモリ割り当ての追跡

メモリプロファイリングの 2番目の方法はメモリ割り当てプロファイラ Rprofmem()を使う。

これは大きなベクトルが割り当てられる (ユーザ固有の閾値)かRのヒープに新しいメモリが割り当てられるたびに出力ファイルにスタックトレースを書き出す。このための要約する関

数はまだ設計されている。

前のセクションからの例を次のコードを使って実行する。> Rprofmem("boot.memprof",threshold=1000)

> storm.boot <- boot(rs, storm.bf, R = 4999)

> Rprofmem(NULL)

これは bootの最初と最後の動作は別として、1000バイトを超えるベクトルの割り当てがないことを示している。

3.3.3 オブジェクトのコピーの追跡

3番目のメモリプロファイリングは、特定の (おそらく大きい)Rオブジェクトで作られたコピーを追跡することに関係している。オブジェクトが duplicateまたは別の型へ変換された

Page 87: Rの拡張を書く (R 2.15.2)

Chapter 3: Rコードの整理とプロファイリング 81

とき、または算術演算で同じサイズの新しいオブジェクトが生成されたときに、メッセージが

標準出力に印字されるように、オブジェクトに tracememを呼ぶとオブジェクトに印がつく。

これが誤解を招きうる主な理由は、オブジェクトの部分集合や構成要素の複製物は追跡されな

いということである。これらの構成要素に対し tracememを使うことは役立つかもしれない。

上の例でデータフレーム stに対して tracememを実行することができる。> tracemem(st)

[1] "<0x9abd5e0>"

> storm.boot <- boot(rs, storm.bf, R = 4)

memtrace[0x9abd5e0->0x92a6d08]: statistic boot

memtrace[0x92a6d08->0x92a6d80]: $<-.data.frame $<- statistic boot

memtrace[0x92a6d80->0x92a6df8]: $<-.data.frame $<- statistic boot

memtrace[0x9abd5e0->0x9271318]: statistic boot

memtrace[0x9271318->0x9271390]: $<-.data.frame $<- statistic boot

memtrace[0x9271390->0x9271408]: $<-.data.frame $<- statistic boot

memtrace[0x9abd5e0->0x914f558]: statistic boot

memtrace[0x914f558->0x914f5f8]: $<-.data.frame $<- statistic boot

memtrace[0x914f5f8->0x914f670]: $<-.data.frame $<- statistic boot

memtrace[0x9abd5e0->0x972cbf0]: statistic boot

memtrace[0x972cbf0->0x972cc68]: $<-.data.frame $<- statistic boot

memtrace[0x972cc68->0x972cd08]: $<-.data.frame $<- statistic boot

memtrace[0x9abd5e0->0x98ead98]: statistic boot

memtrace[0x98ead98->0x98eae10]: $<-.data.frame $<- statistic boot

memtrace[0x98eae10->0x98eae88]: $<-.data.frame $<- statistic boot

オブジェクトは 15回複製され、R+1の storm.bfへの各呼び出しで 3回複製されている。nls

の内部で複製は起こらないことから、これは驚きに値する。デバッガ中で storm.bfをステッ

プスルーすると、3回の複製はすべて次の行で起こっていることが分かる。st$Time <- st$fit + rs[i]

データフレームは行列よりも遅く、これが理由の一例である。tracemem(st$Viscosity)

を使うことは何も追加の複製を明らかにしない。

3.4 コンパイル済みコードの整理

コンパイル済みコードのプロファイルはかなりシステム固有であるが、この節はさまざまな

Rユーザから集められたいくつかの手掛かりを含んでいる。いくつかのメソッドは、Rパッケージで使われる場合、コンパイル済み実行ファイルと動的/共有 ライブラリ/オブジェクトによって異なっている必要がある。我々はWindows上でDLLをプロファイルする良い方法を知らない。

3.4.1 Linux

オプションには共有オブジェクトに対しsprofを使う方法と、任意の実行形式と共有オブジェク

トに対して oprofile (http://oprofile.sourceforge.net/を見よ) and perf ( https://perf.wiki.kernel.org/index.php/Tutorialを見よ) を使う方法が含まれている。

3.4.1.1 sprof

環境変数 LD_PROFILEを設定することで、sprofを用いてプロファイルされる共有オブジェク

トを選択することができる。例えば、

% setenv LD_PROFILE /path/to/R_HOME/library/stats/libs/stats.so

R

... bootの例を実行する

% sprof /path/to/R_HOME/library/stats/libs/stats.so \

Page 88: Rの拡張を書く (R 2.15.2)

Chapter 3: Rコードの整理とプロファイリング 82

/var/tmp/path/to/R_HOME/library/stats/libs/stats.so.profile

Flat profile:

Each sample counts as 0.01 seconds.

% cumulative self self total

time seconds seconds calls us/call us/call name

76.19 0.32 0.32 0 0.00 numeric_deriv

16.67 0.39 0.07 0 0.00 nls_iter

7.14 0.42 0.03 0 0.00 getListElement

rm /path/to/R_HOME/library/stats/libs/stats.so.profile

... クリーンアップするため ...

rootアクセス権がプロファイルデータのために使うディレクトリを作成するために必要になる可能性がある。

3.4.1.2 oprofile

oprofileは情報を収集するデーモンを実行することで動作する。デーモンは rootとして実行されなければならない。例えば、次のようにする。

% su

% opcontrol --no-vmlinux

% (optional, some platforms) opcontrol --callgraph=5

% opcontrol --start

% exit

そしてユーザとして次のようにする。

% R

... bootの例を実行する

% opcontrol --dump

% opreport -l /path/to/R_HOME/library/stats/libs/stats.so

...

samples % symbol name

1623 75.5939 anonymous symbol from section .plt

349 16.2552 numeric_deriv

113 5.2632 nls_iter

62 2.8878 getListElement

% opreport -l /path/to/R_HOME/bin/exec/R

...

samples % symbol name

76052 11.9912 Rf_eval

54670 8.6198 Rf_findVarInFrame3

37814 5.9622 Rf_allocVector

31489 4.9649 Rf_duplicate

28221 4.4496 Rf_protect

26485 4.1759 Rf_cons

23650 3.7289 Rf_matchArgs

21088 3.3250 Rf_findFun

Page 89: Rの拡張を書く (R 2.15.2)

Chapter 3: Rコードの整理とプロファイリング 83

19995 3.1526 findVarLocInFrame

14871 2.3447 Rf_evalList

13794 2.1749 R_Newhashpjw

13522 2.1320 R_gc_internal

...

プロファイラの停止と記録のクリアは rootとして行われる必要がある。もし適切なソースコードがデバッグサポートとコールグラフを生成するための opreport -cを伴ってコンパ

イルされていれば、ソースコードに各セクションで消費された時間の注釈をつけるための

opannotateを使うことができる。

3.4.2 Solaris

64-bitの Solaris上で、標準的なプロファイリングツール gprofは、-pgをつけてコンパイル

された共有オブジェクトから情報を収集する。

3.4.3 Mac OS X

開発者は sample(または GUI 版である Sampler.app) と Shark(http: / / developer .

apple .com /tools /sharkoptimize .htmlと http: / /developer .apple .com /tools /

shark_optimize.htmlを参照せよ) を推奨している。

Page 90: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 84

4 デバッグ作業

この章では、役立つエラー情報を取得する方法に始まり、Rをクラッシュさせるエラーにどのように対処するかということが続く、Rの拡張のデバッグを取り扱う。他のスタイルを好む人には、CRANの debug (http://CRAN.R-project.org/package=debug)のような貢献パッケージがある (R-News 3/3 (http://CRAN.R-project.org/doc/Rnews/Rnews_2003-3.pdf)の記事に書かれている)。(ここで与えられたものを補完する例を提供した覚書がRoger Pengによって 2002年から http://www.biostat.jhsph.edu/~rpeng/docs/R-debug-tools.pdf

に提供されている。)

4.1 ブラウジング

R レベルのデバッグ機能の大部分は、内蔵されたブラウザの周辺に基づいている。これは関数のコードに browser()への呼び出しを挿入することで直接使うことができる (例えば、fix(my_function)を使う)。コードの実行が関数のその位置に到着すると、制御は特別なプロンプトをRコンソールに返す。例えば、

> fix(summary.data.frame) ## forループの後に browser()を挿入する

> summary(women)

Called from: summary.data.frame(women)

Browse[1]> ls()

[1] "digits" "i" "lbs" "lw" "maxsum" "nm" "nr" "nv"

[9] "object" "sms" "z"

Browse[1]> maxsum

[1] 7

Browse[1]>

height weight

Min. :58.0 Min. :115.0

1st Qu.:61.5 1st Qu.:124.5

Median :65.0 Median :135.0

Mean :65.0 Mean :136.7

3rd Qu.:68.5 3rd Qu.:148.0

Max. :72.0 Max. :164.0

> rm(summary.data.frame)

ブラウザのプロンプトでは、任意のRの式を入力することができる。例えば ls()は現在のフ

レームにあるオブジェクトを一覧表にし、オブジェクト名を入力するとそれを表示する 1。以

下のコマンドも受け入れられる。

• n

ステップスルーモードに入る。このモードでは、リターンを打つことで、コードの次の

行を実行する (より正確には 1行と継続行)。cを入力すると現在のコンテキストの最後ま

で続ける。例えば、現在のループ、あるいは関数の終わりまで続ける。

• c

通常モードでは、これはブラウザを終了して実行を継続し、復帰は同様に動作する。cont

は同意語である。

1 以下に挙げられたコマンドの例外を除く: printへの明示的な呼び出しを通して表示されるような名前のオブジェクト

Page 91: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 85

• where

コールスタックを表示する。例えば、

> summary(women)

Called from: summary.data.frame(women)

Browse[1]> where

where 1: summary.data.frame(women)

where 2: summary(women)

Browse[1]>

• Q

ブラウザと現在の式を終了し、トップレベルのプロンプトに戻る。

ブラウザプロンプトで実行されたコード内のエラーは、通常は制御をブラウザプロンプト

に返す。オブジェクトは代入によって変更されることもあり、ブラウザを抜けたときにその

変更された値を保持する。もし本当に必要であれば、ブラウザプロンプトからワークスペー

スにオブジェクトを割り当てることができる (スコープに名前がない場合に<<-を使うことに

よる)。

4.2 Rコードのデバッグ

Rプログラムがエラーを出したとしよう。最初に調べるべきことは、エラー時にRが何をしていたかであり、最も役立つツールは traceback()である。エラーの原因がすぐに明らかに

ならない場合は、いつでも traceback()を実行することを勧める。traceback()がエラーは

他のパッケージあるいは Rの baseから報告されたことを示したとき、エラーはいくつかのパッケージにあるものとして、絶えずエラーはRのメーリングリストに報告される。ここに回帰の一式からの例を示す。

> success <- c(13,12,11,14,14,11,13,11,12)

> failure <- c(0,0,0,0,0,0,0,2,2)

> resp <- cbind(success, failure)

> predictor <- c(0, 5^(0:7))

> glm(resp ~ 0+predictor, family = binomial(link="log"))

Error: no valid set of coefficients has been found: please supply starting values

> traceback()

3: stop("no valid set of coefficients has been found: please supply

starting values", call. = FALSE)

2: glm.fit(x = X, y = Y, weights = weights, start = start, etastart = etastart,

mustart = mustart, offset = offset, family = family, control = control,

intercept = attr(mt, "intercept") > 0)

1: glm(resp ~ 0 + predictor, family = binomial(link ="log"))

アクティブフレームへの呼び出しは逆順で与えられる (最深部から始まる)。そのため、エラーメッセージが glm.fit内の明示的なチェックから来ていることが見えている。(traceback()は関数呼び出しのすべての系列を表示する。これは option "deparse.max.lines"を設定す

ることによって、その数を制限することができる。)

ときおり、トレースバックはエラーがコンパイル済みのコードの内部で検出されたことを

示すことがある。例えば (?nlsから)、Error in nls(y ~ a + b * x, start = list(a = 0.12345, b = 0.54321), trace = TRUE) :

step factor 0.000488281 reduced below ’minFactor’ of 0.000976563

> traceback()

2: .Call(R_nls_iter, m, ctrl, trace)

1: nls(y ~ a + b * x, start = list(a = 0.12345, b = 0.54321), trace = TRUE)

Page 92: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 86

これは最深部の呼び出しが.C、.Fortran、.Call、.Externalあるいは.Internalの場合に

当てはまる。そのようなコードはRの式を評価することはできるため、以下のように最深部の呼び出しである必要はない。

> traceback()

9: gm(a, b, x)

8: .Call(R_numeric_deriv, expr, theta, rho, dir)

7: numericDeriv(form[[3]], names(ind), env)

6: getRHS()

5: assign("rhs", getRHS(), envir = thisEnv)

4: assign("resid", .swts * (lhs - assign("rhs", getRHS(), envir = thisEnv)),

envir = thisEnv)

3: function (newPars)

{

setPars(newPars)

assign("resid", .swts * (lhs - assign("rhs", getRHS(), envir = thisEnv)),

envir = thisEnv)

assign("dev", sum(resid^2), envir = thisEnv)

assign("QR", qr(.swts * attr(rhs, "gradient")), envir = thisEnv)

return(QR$rank < min(dim(QR$qr)))

}(c(-0.00760232418963883, 1.00119632515036))

2: .Call(R_nls_iter, m, ctrl, trace)

1: nls(yeps ~ gm(a, b, x), start = list(a = 0.12345, b = 0.54321))

時折 traceback()は役に立たないことがあり、これは S4メソッドディスパッチが関係している場合にも当てはまることがある。以下の例を考えよう。

> xyd <- new("xyloc", x=runif(20), y=runif(20))

Error in as.environment(pkg) : no item called "package:S4nswv"

on the search list

Error in initialize(value, ...) : S language method selection got

an error when called from internal dispatch for function ’initialize’

> traceback()

2: initialize(value, ...)

1: new("xyloc", x = runif(20), y = runif(20))

initializeに as.environmentへの呼び出しがないことから、これはあまり役に立たな

い (“called from internal dispatch” という注意がそのことを知らせている)。この場合、methods:::.asEnvironmentPackageという 1箇所でのみ発生した、引用符で囲まれた呼び出しに対応する Rのソースを探索した。そこでどこでエラーが発生したかということを知った (これは珍しく不可解な例であった)。

エラーメッセージ

evaluation nested too deeply: infinite recursion / options(expressions=)?

は既定値 (5000)を使って扱うことが難しい可能性がある。実際に深い再帰が発生していることを知っていない限り、以下のように設定し、

options(expressions=500)

そしてエラーを示した例を再実行することが役立つ。

時々後のエラーの前兆となる明らかな警告があるが、警告がどこから来たのかははっきり

としない。options(warn = 2)(これは警告をエラーに変換する)と設定することがここでは役に立つ。

一度エラーを見つけたなら、いくつかの選択がある。処理の 1つに事後のダンプを見ることで、クラッシュの時に何が起こっていたかについてより解明することがある。そのよう

Page 93: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 87

にするためには、options(error=dump.frames)を設定し、コードを再度実行せよ。そして

debugger()を起動し、ダンプを調査せよ。我々の例を続ける:> options(error = dump.frames)

> glm(resp ~ 0 + predictor, family = binomial(link ="log"))

Error: no valid set of coefficients has been found: please supply starting values

これは前と同じエラーであるが、last.dumpによって呼ばれたオブジェクトがワークスペー

スに現れる。(そのようなオブジェクトは大きいこともあるので、必要が無くなったときには削除せよ。)オブジェクトは関数 debuggerを呼び出すことで後に検査することができる。

> debugger()

Message: Error: no valid set of coefficients has been found: please supply starting values

Available environments had calls:

1: glm(resp ~ 0 + predictor, family = binomial(link = "log"))

2: glm.fit(x = X, y = Y, weights = weights, start = start, etastart = etastart, mus

3: stop("no valid set of coefficients has been found: please supply starting values

Enter an environment number, or 0 to exit Selection:

これは tracebackと同じ呼び出しの列を与えるが、呼び出しは外部から順になり、最初の行

だけとなり、現在の幅で切り詰められる。しかし、これでエラー時に何が起きていたか詳細

を検討することができる。環境を選択すると、そのフレーム内のブラウザを開く。そこで、エ

ラーメッセージを発生させた関数呼び出しを選択し、いくつかの変数を検査する (そして 2つの関数呼び出しを実行する)。

Enter an environment number, or 0 to exit Selection: 2

Browsing in the environment with call:

glm.fit(x = X, y = Y, weights = weights, start = start, etas

Called from: debugger.look(ind)

Browse[1]> ls()

[1] "aic" "boundary" "coefold" "control" "conv"

[6] "dev" "dev.resids" "devold" "EMPTY" "eta"

[11] "etastart" "family" "fit" "good" "intercept"

[16] "iter" "linkinv" "mu" "mu.eta" "mu.eta.val"

[21] "mustart" "n" "ngoodobs" "nobs" "nvars"

[26] "offset" "start" "valideta" "validmu" "variance"

[31] "varmu" "w" "weights" "x" "xnames"

[36] "y" "ynames" "z"

Browse[1]> eta

1 2 3 4 5

0.000000e+00 -2.235357e-06 -1.117679e-05 -5.588393e-05 -2.794197e-04

6 7 8 9

-1.397098e-03 -6.985492e-03 -3.492746e-02 -1.746373e-01

Browse[1]> valideta(eta)

[1] TRUE

Browse[1]> mu

1 2 3 4 5 6 7 8

1.0000000 0.9999978 0.9999888 0.9999441 0.9997206 0.9986039 0.9930389 0.9656755

9

0.8397616

Browse[1]> validmu(mu)

[1] FALSE

Browse[1]> c

Available environments had calls:

1: glm(resp ~ 0 + predictor, family = binomial(link = "log"))

2: glm.fit(x = X, y = Y, weights = weights, start = start, etastart = etastart

3: stop("no valid set of coefficients has been found: please supply starting v

Enter an environment number, or 0 to exit Selection: 0

> rm(last.dump)

Page 94: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 88

last.dumpは後ほど、あるいは別のRセッションでさえも見ることができるので、事後分析デバッグはRのバッチ利用に対しても可能である。我々はダンプが保存されるよう準備する必要がある: これはコマンドラインフラグ--saveを使って実行の最後にワークスペースを

保存するか、以下のような設定を通して行うことができる。

> options(error = quote({dump.frames(to.file=TRUE); q()}))

さらなるオプションと動作の例については dump.framesのヘルプを参照せよ。

代わりのエラーアクションは関数 recover()を使うことである:

> options(error = recover)

> glm(resp ~ 0 + predictor, family = binomial(link = "log"))

Error: no valid set of coefficients has been found: please supply starting values

Enter a frame number, or 0 to exit

1: glm(resp ~ 0 + predictor, family = binomial(link = "log"))

2: glm.fit(x = X, y = Y, weights = weights, start = start, etastart = etastart

Selection:

これは dump.framesによく似ている。しかし、ダンプとダンプの再ロードをしなくともプロ

グラムの状態を直接調べることができる。dump.framesのヘルプページでは、非対話的な使用

において dump.framesのように recoverが動作することから、dump.callsと dump.frames

に代わってエラーアクションとして recoverを使うことができるとしている。

事後分析デバッグは何が不味かったのかを正確に調査するのには良いが、なぜなのかを見

出すには必ずしもよくない。代わりのアプローチに、ちょうど前後で何が起こったか詳しく

見ることはあり、それをするのに良い方法として debugを使うことがある。これは関数呼び

出しの始めにブラウザへの呼び出しを挿入し、ステップスルーモードで始める。我々の例で

は、次のように使うことができる。

> debug(glm.fit)

> glm(resp ~ 0 + predictor, family = binomial(link ="log"))

debugging in: glm.fit(x = X, y = Y, weights = weights, start = start, etastart = etastart,

mustart = mustart, offset = offset, family = family, control = control,

intercept = attr(mt, "intercept") > 0)

debug: {

## lists the whole function

Browse[1]>

debug: x <- as.matrix(x)

...

Browse[1]> start

[1] -2.235357e-06

debug: eta <- drop(x %*% start)

Browse[1]> eta

1 2 3 4 5

0.000000e+00 -2.235357e-06 -1.117679e-05 -5.588393e-05 -2.794197e-04

6 7 8 9

-1.397098e-03 -6.985492e-03 -3.492746e-02 -1.746373e-01

Browse[1]>

debug: mu <- linkinv(eta <- eta + offset)

Browse[1]> mu

1 2 3 4 5 6 7 8

1.0000000 0.9999978 0.9999888 0.9999441 0.9997206 0.9986039 0.9930389 0.9656755

9

0.8397616

Page 95: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 89

(プロンプト Browse[1]>はこれはブラウジングの最初のレベルであることを示している: それ自身がデバッグされているか browser()への呼び出しを含む関数へステップインすること

が可能である。)

debugは、例えば debug(stats:::predict.Arima)によって、隠された関数と S3メソッドに対して使うことができる。(S4メソッドに対しては使用できないが、別の方法が debug

のヘルプページで与えられている。)時々、例えば arimaの内部で定義された関数 arimafn

のように、別の関数の内部で定義された関数をデバッグしたくなるだろう。そうするために、

debugを外部の関数 (ここでは arima)に仕込み、内部の関数が定義されるまでステップ実行せよ。そして、内部の関数で debugを呼ぶようにせよ (そして外部関数でステップスルーモードから抜けるためには cを使用せよ)。

関数のデバッグ機能を削除するには、予め debugに与えられた引数と共に undebugを呼び

出せ: そうしないとデバッグ機能は、後のRセッションで存続してしまう (あるいは関数が編集されるか、あるいは変更されるまで存続する)。

traceは関数に一時的にデバッグコードを挿入するために使うことができる。例えば、エ

ラーになる箇所の直前に browser()への呼び出しを挿入する。実行している例に戻ると、

## 最初に関数の式の番号付き一覧を取得する

> page(as.list(body(glm.fit)), method="print")

> trace(glm.fit, browser, at=22)

Tracing function "glm.fit" in package "stats"

[1] "glm.fit"

> glm(resp ~ 0 + predictor, family = binomial(link ="log"))

Tracing glm.fit(x = X, y = Y, weights = weights, start = start,

etastart = etastart, .... step 22

Called from: eval(expr, envir, enclos)

Browse[1]> n

## ここからシングルステップ

> untrace(glm.fit)

自身の関数では fixを使って一時的なコードを挿入することが容易いかもしれないが、trace

は名前空間中の関数に対し役立つことがある (fixInNamespaceが役立つように)。あるいは、視覚的にコードを挿入するには trace(,edit=TRUE)を使用せよ。

4.3 gctortureとvalgrindを使う

メモリ割り当てと配列外部での読み/書きのエラーは、一部のマシンではまさによくあるクラッシュ(例えばセグメンテーション違反)の原因である。しばしばクラッシュは不適切なメモリアクセスのかなり後になって現れる: 特に R自身が確保した構造体へのダメージは次のガーベージコレクションでのみ明らかになる (あるいはオブジェクトが削除された後のガーベージコレクションで明らかになることさえある)。

4.3.1 gctortureを使う

ガーベージコレクションをできるだけ多く実行することは、メモリの問題を早く発見するこ

とに役立てることができる。これは gctorture(TRUE)によって実現することができる。その

ヘルプページには次のように書かれている。

(ほぼ)すべてのメモリ割り当てでガーベージコレクションを引き起こす。メモリ保護のバグを見つけ出すことを意図している。また残念なことに、Rの実行をとても遅くしてしまう。

Page 96: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 90

‘メモリ保護’への参照は、まだRオブジェクトが使われているのに、保護を欠いたことでガーベージコレクションされることを可能にしている場合である、PROTECT/UNPROTECTへのCレベルの呼び出しを欠いた参照である。しかし、ガーベージコレクションは他のメモリ関連の

エラーにも役立つことがある。

通常 gctorture(TRUE)の下で実行すると、Rプログラムの早い段階で単にクラッシュが発生するが、上手く行けば実際の原因に近づく。そのようなクラッシュを解読する方法は、次

のセクションを参照せよ。

オプション--use-gctを使うことにより、gctorture(TRUE)の下で、R CMD checkによっ

て対象とされるすべての例、テスト、ビニェットを実行することができる。

関数 gctorture2はGC拷問プロセスをより洗練した制御を提供する。関数の引数 step、

waitと inhibit_releaseはヘルプページに文書化されている。環境変数もまた GC拷問をはじめるために使うことができる: R_GCTORTUREは gctortureの step引数に対応しており、

R_GCTORTURE_WAITは wait、そして R_GCTORTURE_INHIBIT_RELEASEは inhibit_releaseに

対応している。

もしRが--enable-strict-barrierと設定されているのであれば、書き込みバリアの整

合性のためにさまざまなテストが有効化される。さらに保護の問題を検出するのに役立つテ

ストも同様に有効化される:

• すべてのGCは完全なGCである。

• 小さなノードページに作成された新しいノードは、作成時に NEWSXPと印付けられる。

• GCの後、NEWSXP型でないすべての空きノードは FREESXP型と印付けられ、直前の型が

記録される。

• アクセサ関数への呼び出しの大部分は、それらの SEXP入力と SEXP出力を検査し、もし

FREESXPが見つかれば、エラーを合図する。ノードのアドレスと古い型はエラーメッセー

ジに含められる。

デバッガと gctortureあるいは gctorture2をともに使うこのメカニズムは、メモリ保護

の問題を分離することに役立つことがある。

4.3.2 valgrindを使う

もし ‘ix86’、‘x86_64’、‘ppc32’、‘ppc64’あるいは ‘s390x’上の Linux、あるいは ‘i386’、‘x86_64’上の Mac OS 10.5/6/7を入手できるのであれば、起こりうる問題を検査するために valgrind(http://www.valgrind .org/、‘tinned’ と韻を踏む) を使うことができる。valgrindの下でいくつかの例を実行するために、次のようなものを使う。

R -d valgrind --vanilla < mypkg-Ex.R

R -d "valgrind --tool=memcheck --leak-check=full" --vanilla < mypkg-Ex.R

ここで、mypkg-Ex.Rは例の集合である。例えば、R CMD checkによって mypkg.Rcheckに生成

されたファイルである。時折、これはコンパイラの最適化の結果である ‘未初期化の値’のメモリ読み込みを報告するので、非最適なコンパイルの下で検査する価値がある: 最大の情報のためにはデバッグシンボルを使ったビルドを使用せよ。readlineとR自身からわずかなメモリリークがあるだろうということが分かっている — これらは Rセッションの最後まで使われるメモリ領域である。これは valgrindの無しよりも 20倍ほど遅くなること、また特定の場合ではそれよりも更に遅くなることを想定せよ。valgrindの以前のバージョンは、CPU

に固有の命令 (3D now、SSE、SSE2、SSE3と似たもの)を使う多くの最適化されたBLASに満足していなかったので、特に valgrindと一緒に使うためには、Rのバージョンをビルドする必要があるかもしれない。

Page 97: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 91

Mac OS 10.6/7上で、valgrindのセッションはRを終了したときにハングしやすい。これは valgrind 3.8.1より前の問題であり、環境変数 R_OSX_VALGRINDを設定することによって

回避することができる。Rセッション内で system()を直接的、あるいは間接的に使うことは

避ける必要がある。

valgrindによってサポートされたプラットフォームでは、valgrindがRのヒープから確保されたメモリの使用で発生するエラーを検出するのに役立つ追加の器具類と共に、Rのバージョンをビルドすることができる。設定オプションは--with-valgrind-instrumentation=level

であり、levelは 0、1あるいは 2である。レベル 0は既定値で、何も付け加えない。レベル 1は初期化されていないメモリを検出し、速度にほとんど影響を与えない。レベル 2は他にも多くのメモリ使用に関するバグを検出するだろうが、valgrindの下で実行されているときは

Rをかなり遅くしてしまう。この設定を gctortureと併せて使うと、より効果的である (そしてさらに遅くなる)。

valgrindの出力の例は次の通り。

==12539== Invalid read of size 4

==12539== at 0x1CDF6CBE: csc_compTr (Mutils.c:273)

==12539== by 0x1CE07E1E: tsc_transpose (dtCMatrix.c:25)

==12539== by 0x80A67A7: do_dotcall (dotcode.c:858)

==12539== by 0x80CACE2: Rf_eval (eval.c:400)

==12539== by 0x80CB5AF: R_execClosure (eval.c:658)

==12539== by 0x80CB98E: R_execMethod (eval.c:760)

==12539== by 0x1B93DEFA: R_standardGeneric (methods_list_dispatch.c:624)

==12539== by 0x810262E: do_standardGeneric (objects.c:1012)

==12539== by 0x80CAD23: Rf_eval (eval.c:403)

==12539== by 0x80CB2F0: Rf_applyClosure (eval.c:573)

==12539== by 0x80CADCC: Rf_eval (eval.c:414)

==12539== by 0x80CAA03: Rf_eval (eval.c:362)

==12539== Address 0x1C0D2EA8 is 280 bytes inside a block of size 1996 alloc’d

==12539== at 0x1B9008D1: malloc (vg_replace_malloc.c:149)

==12539== by 0x80F1B34: GetNewPage (memory.c:610)

==12539== by 0x80F7515: Rf_allocVector (memory.c:1915)

...

この例は、2006年 1月にMatrix (http://CRAN.R-project.org/package=Matrix)パッケージに含まれていたバグを突き止めている間に、Rの検出機器を備えたバージョンから出たものである。最初の行はRが自由にアクセスできないメモリアドレスから 4バイト読み込もうとしたことを示している。これにどこでエラーが起きたのかを表すCのスタックトレースが続いている。次はアクセスしたメモリの説明である。それは GetNewPageから呼び出された malloc

によって確保されたブロックの内側である。すなわち、Rヒープの内部である。このメモリがすべてRに属していることから、valgrindは検出機器を備えていないRのビルドでは、問題を検出できなかったであろう (そしてしなかったであろう)。この例では、スタックトレースは tsc_transposeにあるバグを分離、修正するのに十分であった。そして gctorture()を

動作させたことで、何も追加の情報が得られなかった。スタックトレースが十分に有益でな

い場合、valgrindにオプション--db-attach=yesをつけることが役に立つかもしれない。こ

れは Cコードの内部の変数が検査できるように (see Section 4.4.2 [Rオブジェクトの検査],page 94)、事後分析デバッガ (初期設定では gdb)を起動する。

valgrindの下で、オプション--use-valgrindを使うことで、R CMD checkによって対象

となるすべての例、テスト、ビニェットを実行することができる。もしこれをするのであれ

ば、valgrindのオプションをいくつかの異なる方法で選択する必要があるだろう。例えば、

次のような内容を含む~/.valgrindrcを持つこと

--tool=memcheck

Page 98: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 92

--memcheck:leak-check=full

あるいは、環境変数 VALGRIND_OPTSを設定することによる。

Mac OS Xでは、デバッグシンボルが利用可能であることを保証する必要がある (そのためvalgrindはファイルの行番号を報告する)。.soファイルがロードされたときに、valgrindのオプション--dysmutil=yesがシンボルにダンプするよう求めることで、これをすることがで

きる。これはパッケージがシステム領域にインストールされた場所 (例えば R.frameworkな

ど)では動作せず、遅くなることがある。R CMD INSTALL --dsymを用いてパッケージをインス

トールすると、ダンプされたシンボルをインストールする。(これは環境変数 PKG_MAKE_DSYM

を空でない値に設定することによってもできる。)

4.4 コンパイル済みコードのデバッグ

遅かれ早かれ、プログラマはRにロードされたコンパイル済みコードのデバッグの必要性に直面するであろう。この節では、gccによってコンパイルされたコードに gdbを使うプラット

フォームを対象としているが、例えば dddと insightのような gdbのフロントエンド、そして

例えば Sunの dbxのような他のデバッガでもで同様のことが可能である。

最初に ‘クラッシュ’、つまり Rがメモリアクセス違反 (‘セグメンテーション違反’あるいは ‘バスエラー’)、不当な命令、あるいは同様なもので予想外の終了をしたときを考える。RのUnix系のバージョンでは基本的な情報を与えることを目指したシグナルハンドラを利用している。例えば、

*** caught segfault ***

address 0x20000028, cause ’memory not mapped’

Traceback:

1: .identC(class1[[1]], class2)

2: possibleExtends(class(sloti), classi, ClassDef2 = getClassDef(classi,

where = where))

3: validObject(t(cu))

4: stopifnot(validObject(cu <- as(tu, "dtCMatrix")), validObject(t(cu)),

validObject(t(tu)))

Possible actions:

1: abort (with core dump)

2: normal R exit

3: exit R without saving workspace

4: exit R saving workspace

Selection: 3

Rのプロセスはダメージを受けているかもしれないので、本当に安全なオプションは最初のものだけである。

‘クラッシュ’の別の原因は、Cスタックが限度を超えることである。Rは自身のコードの内部でそれを追跡しようと試みるが、超過はサードパーティがコンパイルしたコードで起こ

ることがある。現代の POSIX-準拠の OSについては、Rはそれを安全に受け取ることができ、トップレベルのプロンプトへ返す。そのため、次のようなものを受け取る。

> .C("aaa")

Error: segfault from C stack overflow

>

Page 99: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 93

しかし、CのスタックオーバーフローはWindowsでは致命的で、通常そのプラットフォーム上でのデバッグ作業を打ち破ってしまう。

もしコアダンプを出すようなクラッシュがあれば、コアダンプを検査するために、次のよ

うなものを使うことができる。

gdb /path/to/R/bin/exec/R core.12345

もしコアダンプが無効、あるいはダンプを生成しないエラーをキャッチする場合は、Rが正常に実行された時点で、例えば次のようにしてデバッガの下でRを直接実行することができる。

$ R -d gdb --vanilla

...

gdb> run

うまくいけばデバッガはエラーをキャッチして、プロンプトに戻る。これは無限ループの捕捉

や非常に長時間実行されるコードを中断することにも使用される。単純な例は、

> for(i in 1:1e7) x <- rnorm(100)

[hit Ctrl-C]

Program received signal SIGINT, Interrupt.

0x00397682 in _int_free () from /lib/tls/libc.so.6

(gdb) where

#0 0x00397682 in _int_free () from /lib/tls/libc.so.6

#1 0x00397eba in free () from /lib/tls/libc.so.6

#2 0xb7cf2551 in R_gc_internal (size_needed=313)

at /users/ripley/R/svn/R-devel/src/main/memory.c:743

#3 0xb7cf3617 in Rf_allocVector (type=13, length=626)

at /users/ripley/R/svn/R-devel/src/main/memory.c:1906

#4 0xb7c3f6d3 in PutRNGstate ()

at /users/ripley/R/svn/R-devel/src/main/RNG.c:351

#5 0xb7d6c0a5 in do_random2 (call=0x94bf7d4, op=0x92580e8, args=0x9698f98,

rho=0x9698f28) at /users/ripley/R/svn/R-devel/src/main/random.c:183

...

後に続くいくつかの “トリック”は知っておく価値がある:

4.4.1 動的にロードされたコードでエントリポイントを見つける

ほとんどのコンパイル環境下では、動的にRへロードされるコンパイル済みコードは、ロードされるまで内部に設定したブレークポイントを持つことができない。Unix系でそのように動的にロードされるコードにシンボリックデバッガを使用するためには、以下のものを利用

する。

• Rの実行ファイルでデバッガを呼び出す。例えば R -d gdbによる。

• Rを開始する。

• Rのプロンプトで、共有オブジェクトをロードするために dyn.loadまたは libraryを使

用する。

• 割込み信号を送る。これでデバッガのプロンプトへ戻される。prompt.

• コードにブレークポイントを設定する。• signal 0RETとタイプしてRの実行を継続する。

Windowsではシグナルは使えないかもしれない。もしそうであれば、手続きはより複雑になる。rw-FAQ と www.stats.uwo.ca/faculty/murdoch/software/debuggingR/gdb.shtml

Page 100: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 94

(http://www.stats.uwo.ca/faculty/murdoch/software/debuggingR/gdb.shtml).を参照せよ。

4.4.2 デバッグ中にRオブジェクトを検査する

コンパイル済みコードから Rオブジェクトを検査する鍵は、sによって指される Rオブジェクトを印字する通常の Rの印字の仕組みを使った関数 PrintValue(SEXP s)か、より安全な

‘オブジェクト’のみを印字する R_PV(SEXP s)である。

PrintValueを使用する 1つの方法は、デバッグされるコードに適切な呼び出しを挿入することである。

別の方法に、シンボリックデバッガから R_PVを呼び出すことがある。(PrintValueは Rf_

PrintValueとして隠される。)例えば、もし畳み込みのCコードに適切なブレークポイントを設置していれば、畳み込みの例からオブジェクト abを使用して、gdbからは次のものを使

うことができる。

(gdb) p R_PV(ab)

任意のRオブジェクトを観察するためには、少しきつい作業をする必要がある。例えば、次のようにしよう。

R> DF <- data.frame(a = 1:3, b = 4:6)

ブレークポイントを do_getに設定し、Rプロンプトで get("DF")とタイプすることで、DFの

メモリ内のアドレスを見つけることができる。例えば、

Value returned is $1 = (SEXPREC *) 0x40583e1c

(gdb) p *$1

$2 = {

sxpinfo = {type = 19, obj = 1, named = 1, gp = 0,

mark = 0, debug = 0, trace = 0, = 0},

attrib = 0x40583e80,

u = {

vecsxp = {

length = 2,

type = {c = 0x40634700 "0>X@D>X@0>X@", i = 0x40634700,

f = 0x40634700, z = 0x40634700, s = 0x40634700},

truelength = 1075851272,

},

primsxp = {offset = 2},

symsxp = {pname = 0x2, value = 0x40634700, internal = 0x40203008},

listsxp = {carval = 0x2, cdrval = 0x40634700, tagval = 0x40203008},

envsxp = {frame = 0x2, enclos = 0x40634700},

closxp = {formals = 0x2, body = 0x40634700, env = 0x40203008},

promsxp = {value = 0x2, expr = 0x40634700, env = 0x40203008}

}

}

(デバッガの出力は読みやすさのために再フォーマットしている)。

R_PV()を使うと、SEXPのさまざまな要素の値を “検査する”ことができる。例えば、

Page 101: Rの拡張を書く (R 2.15.2)

Chapter 4: デバッグ作業 95

(gdb) p R_PV($1->attrib)

$names

[1] "a" "b"

$row.names

[1] "1" "2" "3"

$class

[1] "data.frame"

$3 = void

対応する情報が格納されている場所を正確に見つけるには、“より深い所”へ向かう必要がある:

(gdb) set $a = $1->attrib

(gdb) p $a->u.listsxp.tagval->u.symsxp.pname->u.vecsxp.type.c

$4 = 0x405d40e8 "names"

(gdb) p $a->u.listsxp.carval->u.vecsxp.type.s[1]->u.vecsxp.type.c

$5 = 0x40634378 "b"

(gdb) p $1->u.vecsxp.type.s[0]->u.vecsxp.type.i[0]

$6 = 1

(gdb) p $1->u.vecsxp.type.s[1]->u.vecsxp.type.i[1]

$7 = 5

別の選択肢は、R 2.13.0から利用可能となっている再帰的にオブジェクトの低レベルの構造を示す R_inspect関数である (この例が別のマシンで作られているため、アドレスは上とは異なる):

(gdb) p R_inspect($1)

@100954d18 19 VECSXP g0c2 [OBJ,NAM(2),ATT] (len=2, tl=0)

@100954d50 13 INTSXP g0c2 [NAM(2)] (len=3, tl=0) 1,2,3

@100954d88 13 INTSXP g0c2 [NAM(2)] (len=3, tl=0) 4,5,6

ATTRIB:

@102a70140 02 LISTSXP g0c0 []

TAG: @10083c478 01 SYMSXP g0c0 [MARK,NAM(2),gp=0x4000] "names"

@100954dc0 16 STRSXP g0c2 [NAM(2)] (len=2, tl=0)

@10099df28 09 CHARSXP g0c1 [MARK,gp=0x21] "a"

@10095e518 09 CHARSXP g0c1 [MARK,gp=0x21] "b"

TAG: @100859e60 01 SYMSXP g0c0 [MARK,NAM(2),gp=0x4000] "row.names"

@102a6f868 13 INTSXP g0c1 [NAM(2)] (len=2, tl=1) -2147483648,-3

TAG: @10083c948 01 SYMSXP g0c0 [MARK,gp=0x4000] "class"

@102a6f838 16 STRSXP g0c1 [NAM(2)] (len=1, tl=1)

@1008c6d48 09 CHARSXP g0c2 [MARK,gp=0x21,ATT] "data.frame"

一般的に各オブジェクトの表示は次の形式に従う:@<address> <type-nr> <type-name> <gc-info> [<flags>] ...

再帰の深さとベクトルの出力のよりきめ細かい制御のために、R_inspect3は 2つの整数のパラメータを受け取る: 最大の深さとスカラーベクトルを表示する最大の要素数である。R_inspectの既定値は現在のところ、それぞれ-1(制限無し)と 5になっている。

Page 102: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 96

5 システムと他言語間のインタフェース

5.1 オペレーティングシステムへのアクセス

オペレーティングシステムの関数へのアクセスはRの関数 systemと system2を経由して行わ

れる。プラットフォームにより詳細は異なり (オンラインヘルプを参照せよ)、安全に仮定されることのほぼすべては、最初の引数は実行のために渡される (必ずしもシェルによらない)文字列 commandであり、systemへの 2番目の引数は、それが真であればコマンドの出力をRの文字列ベクトルに集める internalになるであろうということである。

関数 system.time は時間計測に利用できる。子プロセスの計時はUnix系でのみ可能で、そこでの計時は信頼できないものかもしれない。

5.2 インタフェース関数.Cと.Fortran

これらの二つの関数は、ビルド時あるいは dyn.loadを通してRにリンクされたコンパイル済みコードへのインタフェースを提供する (see Section 5.3 [dyn.loadと dyn.unload], page 98)。これらは主にコンパイルされたCと FORTRAN 77のコードのそれぞれを意図したものであるが、.C関数は、例えばC++のようなCのインタフェースを生成することができる他の言語に使うこともできる (see Section 5.6 [C++コードとのインタフェース], page 105)。

各関数の最初の引数は、Cや FORTRANに知られている 1シンボル名を明記した文字列、

すなわち関数あるいはサブルーチンの名前である。(シンボルがロードされていることは、例えば is.loaded("cg")によってテストすることができる。翻訳されたシンボル名ではなく.C

あるいは.Fortranに渡した名前を使うこと。)

コンパイルされたコードに渡す Rオブジェクトを与える引数は 65個に及ぶことがある。通常これらは渡される前にコピーされ、コンパイルされたコードが返してきたときにRのリストオブジェクトに再びコピーされる。もし引数に名前が与えられていたら、それらは返さ

れるリストオブジェクトの成分の名前に使われる (ただしコンパイルされたコードには渡されない)。

以下のテーブルはRの原子ベクトルのモードとCの関数あるいは FORTRANのサブルーチンへの引数の種類の対応を与える。

Rの保持モード Cの型 FORTRANの型logical int * INTEGER

integer int * INTEGER

double double * DOUBLE PRECISION

complex Rcomplex * DOUBLE COMPLEX

character char ** CHARACTER*255

raw unsigned char * none

最初の二つに注意するようにしていただきたい。64ビットのUnix/Linux/OS Xプラットフォーム上では、intと INTEGERは 32ビットであるが、longは 64ビットである。S-PLUSから移植されたコード (logicalと integerに long *を使っているもの)はすべての 64ビットプラットフォームでは動作しないであろう (Windowsを含めいくつかのプラットフォームでは動いているように見えるであろうが)。もしコンパイルされたコードが Cの関数と FORTRAN

1 おそらくはプラットフォーム特有の翻訳の後になる。例えば先頭か末尾にアンダースコアを加えること。

Page 103: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 97

のサブプログラムを混ぜたものであれば、引数の型は上の表で与えられたものに合わせなけ

ればならない。

Cの型 Rcomplexは R.hによってインクルードされるヘッダーファイル R_ext/Complex.h

で定義された、doubleのメンバ rと iを持った構造体である。(大部分のプラットフォームで、構造体は C99の型 double complexと互換性がある方法で格納されている: しかしながら、double complexの引数を期待して、C99の関数に Rcomplexを渡すことは可能ではないであ

ろう。また C++の complex型と互換性がある必要がある。さらに互換性はコンパイラの最適

化レベルの設定に依存する可能性がある。)

1文字の文字列だけが FORTRANと受け渡しでき、これが上手くいくかどうかはコンパイラ依存である。他のRオブジェクトは.Cに渡せるが、他のインタフェースを使う方がより

良いであろう。

保持モードがの数値ベクトルは、Rの関数 as.single、singleあるいは modeを使うとい

う最も簡便な方法により、float *として Cに、あるいは REALとして FORTRANに渡すことが可能である。これは既存の Cあるいは FORTRANのコードとのインタフェースを支援するためだけの使用を意図したものである。

論理値は 0(FALSE)、1(TRUE)あるいは INT_MIN = -2147483648(NA、ただし NAOKが trueの場合のみ)として送られ、コンパイルされたコードは 3つの値の 1つを返さなければならない。(INT_MIN以外の非 0の値は TRUEに対応付けられている。)

仮引数 NAOKが trueでない限り、他のすべての引数は欠損値 NAであるか、IEEE特殊値 NaN、

Infと-Infであるかをチェックされ、これらの値が存在するとエラーを発生させる。もし NAOK

が trueであれば、引数の値はチェックされずに渡される。

DUPはコピーを抑制するために使うことができる。これは危険である: その使用に対する議論のオンラインヘルプを参照せよ。もし DUP = FALSEであれば、数値ベクトルを float *あ

るいは REALとして渡すことができず、文字列ベクトルは使用できない。

引数 PACKAGEはシンボル名に対する探索を明記された共有オブジェクトに限定する (あるいは Rにコンパイルされたコードには"base"を使用せよ。)。二つのパッケージの書き手が同じシンボル名を避ける方法がなく、そのような名前の衝突はRをクラッシュさせるのに普通は十分であることから、引数 PACKAGEの使用はとても望ましいものである。(もし引数が無く、呼び出しがパッケージ名前空間内で定義された関数本体から場合、最初の (もしあれば)useDynLibディレクティブによりロードされた共有オブジェクトが使われる。)しかし、R2.16.0より前では正しい名前空間の発見は信頼できず、Rの早いのバージョンのもので使われるパッケージに対しては引数 PACKAGEを使うことを強く推奨する。

コンパイルされたコードはその引数を通して以外何も返すべきではないことに注意: Cの関数の型は voidで、FORTRANのサブプログラムはサブルーチンでなければならない。

考えをまとめるため、2つの有限長の数列を畳み込むという、とても簡単な例を考えよう。(これはインタプリタのRコードで高速に行うのは大変だが、Cのコードでは容易である。).Cを使い、以下のようにしてできる。

Page 104: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 98

void convolve(double *a, int *na, double *b, int *nb, double *ab)

{

R_len_t i, j, nab = *na + *nb - 1;

for(i = 0; i < nab; i++)

ab[i] = 0.0;

for(i = 0; i < *na; i++)

for(j = 0; j < *nb; j++)

ab[i + j] += a[i] * b[j];

}

Rからの呼び出しは以下のようになる。

conv <- function(a, b)

.C("convolve",

as.double(a),

as.integer(length(a)),

as.double(b),

as.integer(length(b)),

ab = double(length(a) + length(b) - 1))$ab

.Cを呼ぶ前に、すべての引数を正しい Rの保持モードに強制変換することに気をつけなければならない; 型を合わせることの失敗は、誤った結果や把握するのが難しいエラーを導く可能性がある。

C(あるいは C++)で characterベクトルの引数を扱うのには特別な注意が必要とされる。

DUP = TRUEのみが許されているので、エントリで要素の内容は複製され、char **配列の要素

に割り当てられる。出口では、Cの配列の要素は文字ベクトルの新しい要素を生成するためにコピーされる。これは、char **配列の文字列の内容は、文字列を短くするために\0を入れ

ることを含め変更することができるが、文字列は長くすることはできないということを意味

している。R_allocを通して新しい文字列を割り当てることと、新しい文字列によって char

**配列中のエントリを変更することは可能である。しかしながら、読み込み専用以外で文字

ベクトルが使用されるときは、.Callインタフェースがより好まれるであろう。

文字列を FORTRANコードに渡すことはさらに注意が必要で、可能であれば避けるべきである。文字ベクトルの最初の要素のみが固定長 (255)の文字配列として渡されて入る。255文字までの文字は 1文字のベクトルになって戻される。これがどの程度上手く動作するか (あるいはすべてで動作するにしても)は各プラットフォームのCと FORTRANのコンパイラに依存している。

.Cを通せば、原子ベクトル以外の Rオブジェクトを渡すことができるが、これは歴史的な互換性のためだけにサポートされている: そのようなオブジェクトには.Callあるいは

.Externalインタフェースを使用せよ。Rinternals.hを含む任意の C/C++コードは.Call

あるいは.Externalから呼ばれなければならない。

5.3 dyn.loadと dyn.unload

Rで使われるコンパイルされたコードは共有オブジェクト (Max OS Xを含めた Unix系、更なる情報は see Section 5.5 [共有オブジェクトの作成], page 104 を参照せよ) あるいはDLL(Windows)としてロードされる。

Page 105: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 99

共有オブジェクト/DLLは dyn.loadによってロードされ、dyn.unloadによってアンロー

ドされる。アンロードは通常は必要ではないが、Windowsを含め、いくつかのプラットフォームでDLLを再ビルドするために必要とされる。

2つの関数の最初の引数はオブジェクトへのパスを与える文字列である。プログラマは (.soのような)オブジェクト/DLLに対する特定のファイルの拡張子を仮定するべきではないが、プラットフォームから独立させるため、次のような構造を使用するべきである。

file.path(path1, path2, paste0("mylib", .Platform$dynlib.ext))

Unix系システムでは、dyn.loadに与えられるパスは、絶対パス、現在のディレクトリからの相対パス、あるいはユーザのホームディレクトリから相対的な ‘~’で始まるパスがありうる。

ロードは NAMESPACEファイルに書かれた useDynLib()宣言に基づいて自動的にされるこ

とが最も頻繁に行われるが、library.dynamの呼び出しを介して明示的に行われるかもしれ

ない。これは次のような形式である。

library.dynam("libname", package, lib.loc)

ここで libnameは拡張子を取り除いたオブジェクト/DLLの名前である。最初の引数 chname

はパッケージが別の名前でインストールされると動作しないので packageにしてはならない

ことに注意。

いくつかの Unix系システムでは、オブジェクトがロードされるときに、どのようにシンボルが解決されるかという選択が、引数 localと nowによって制御されている。本当に必要

としている場合にのみこれらを使用せよ: 特に now=FALSEを使い、未解決のシンボルを呼び

出すことはRを突然終了させてしまうであろう。

Rは object/DLLがロード、あるいはアンロードされたときに自動的にコードを実行する方法を提供している。これは、例えば、Rの動的シンボルメカニズムでネイティブルーチンを登録する、ネイティブコード中のデータを初期化する、あるいはサードパーティのライブ

ラリの初期化に使うことができる。DLLをロードしているとき、Rは R_init_libと名前が

つけられたDLLの中でルーチンを探す。libは拡張子を取り除いたDLLファイルの名前である。例えば次のコマンド

library.dynam("mylib", package, lib.loc)

では、Rは R_init_mylibと名づけられたシンボルを探す。同様に、オブジェクトをアンロー

ドするときに、Rは例えば R_unload_mylibのように、R_unload_libと名づけられたルーチ

ンを探す。いずれの場合も、もしルーチンが存在しているのであれば、Rはそれを呼び出し、DLLを表す単独の引数に渡す。これは R_extディレクトリの Rdynload.hファイルで定義さ

れた、型 DllInfoの値である。

このメカニズムでは DLLの基本名は有効なファイル名で、Cのエントリポイントの一部として有効である必要があるという暗黙の制限があることに注意: 移植可能なコードのため、DLLの名前を ASCII英数字とアンダースコアに制限するのが最善である。R 2.15.0以降では、もしエントリポイント R_init_libが見つからなければ、‘_’を ‘.’に置き換えたものも探される。

以下の例は、mylib DLLに対する初期化とアンロードの一連の動作のテンプレートを示している。

Page 106: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 100� �#include <R.h>

#include <Rinternals.h>

#include <R_ext/Rdynload.h>

void

R_init_mylib(DllInfo *info)

{

/* ルーチンの登録と、

リソースの割り当て. */

}

void

R_unload_mylib(DllInfo *info)

{

/* リソースの開放 */

} もし共有オブジェクト/DLLが 1度より多くロードされたら、最も新しいのバージョンが

使用される。より一般的には、もし同じシンボル名がいくつかの共有オブジェクトで現れた

ら、もっとも最近ロードされた存在が使用される。引数 PACKAGEおよび登録 (次の節を見よ)は、どの存在を意味しているかという曖昧さを避けるのに良い方法を与える。

Unix系では、プロセスが開始されたときに、動的にリンクされた依存ライブラリを解決するために使用されるパスは固定される (セキュリティ上の理由のため)。そのため、dyn.load

は Rシェルスクリプト (etc/ldpathsを通して)と OS特有の既定値によって設定された位置しか、そのようなライブラリを探索しない。

Windowsでは依存DLLが探される場所をより制御 (とよりセキュリティを弱く)することを可能にしている。すべてのバージョンで探される場所には環境変数 PATHを含んでいるが、

最低の優先度である: 探索場所に DLLがロードされたディレクトリは含んでいないことに注意。dyn.loadに引数 DLLpathを経由してかなり高い優先度を持つ単一のパスを加えること

ができる。これは (初期設定で)パッケージの libs/i386あるいは libs/x64ディレクトリを

DLLのサーチパスに含めるために、library.dynamによって使用される。

5.4 ネイティブルーチンの登録

‘ネイティブ’ルーチンは、コンパイルされたコードのエントリポイントを意味する。

.C、.Call、.Fortranと.Externalの呼び出しにおいて、R は適切な共有オブジェクト/DLLの中を調べて、指定されたネイティブルーチンを見つけなければならない。初期設定では、RはロードされたDLLのシンボルと他の場所を検索するためにオペレーティングシステム特有のダイナミックローダーを使う。別の方法として、DLLの作成者はRを使って明示的にルーチンを登録し、DLL内でルーチンを見つけるのに単一のプラットフォームに依存しない機構を使用することができる。この登録の仕組みは、引数の数と型を含め、ルーチンに

関する付加的な情報の提供に使うことができ、Rプログラマに別の名前の下で利用できるようにする。将来的には、登録は “安全な”あるいは限られたネイティブアクセスのフォームを実装するために使われるかもしれない。

Rを使ってルーチンを登録するために、Cルーチン R_registerRoutinesを呼ぶ。これは

Section 5.3 [dyn.loadと dyn.unload], page 98にある初期化ルーチン R_init_dll nameの内

部で始めてDLLがロードされたときに一般的に行われる。R_registerRoutinesは 5つの引

Page 107: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 101

数を受け取る。最初は Rによって初期化ルーチンへ渡される DllInfoオブジェクトである。

これはRがメソッドに関する情報を保存している場所である。残りの 4つの引数は、4つの異なるインタフェースのルーチンを表す配列である: .C、.Call、.Fortranと.External。そ

れぞれの引数は以下の表で与えられる要素型の NULLで終わる配列である:

.C R_CMethodDef

.Call R_CallMethodDef

.Fortran R_FortranMethodDef

.External R_ExternalMethodDef

現在のところ、R_ExternalMethodDefは R_CallMethodDef型と同じであり、Rでアクセスされるルーチンの名前、実際のネイティブシンボルへのポインタ (つまりルーチン自身)、ルーチンが期待する引数の数からなるフィールドを含んでいる。.Externalを通して起動さ

れる可変個数の引数を持つルーチンに対しては、Rに実際に渡された数をチェックしないよう、引数の数に-1を指定する。例えば、もし以下のように定義された myCallというルーチン

があったとき、

SEXP myCall(SEXP a, SEXP b, SEXP c);

.Callインタフェース用の他のルーチンと一緒に

R_CallMethodDef callMethods[] = {

{"myCall", (DL_FUNC) &myCall, 3},

{NULL, NULL, 0}

};

のように書くであろう。

.Cと.Fortranインタフェースで使用するためのルーチンは類似したデータ構造で述べら

れるが、各引数の型と “スタイル”を表す 2つの追加フィールドを持つ。これらは省略することもできる。しかしながら、もし指定されていれば、それぞれはルーチンに対するパラメー

タの数と同じ数の要素を持つ配列である必要がある。型の配列は引数の期待される型を表す

SEXP型を含まなければならない。(技術的には、型の配列の要素は単なる符号なし整数であるR_NativePrimitiveArgType型である。)Rの型と対応する型識別子は以下の表で与えられる:

numeric REALSXP

integer INTSXP

logical LGLSXP

single SINGLESXP

character STRSXP

list VECSXP

次のように宣言された Cルーチン myCを考えよう。

void myC(double *x, int *n, char **names, int *status);

これは次のように登録する。

R_CMethodDef cMethods[] = {

{"myC", (DL_FUNC) &myC, 4, {REALSXP, INTSXP, STRSXP, LGLSXP}},

{NULL, NULL, 0}

};

各引数が単に入力として、出力として、あるいは入出力として使われるかを指定すること

ができる。メソッドを説明するスタイルフィールドはこのために使われる。その目的はRが必要でないときは値をコピーすることを避けることで、R-C/FORTRANのインタフェース

Page 108: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 102

間でより効率的に値を転送できるようにすることである 2。一般的には、登録データ中でこの

情報は省略する。

各ルーチンを説明する配列を作成したので、最後のステップは実際にそれらを Rに登録することである。これは R_registerRoutinesを呼ぶことによって行う。例えば、もし.Cと

.Callによってアクセスされる、上にあるようなルーチンを書いていた場合、以下のコードを

利用するであろう:

void

R_init_myLib(DllInfo *info)

{

R_registerRoutines(info, cMethods, callMethods, NULL, NULL);

}

このルーチンはRがmyLibと名づけられた共有オブジェクト/DLLをロードしたときに起動される。R_registerRoutinesの呼び出しにある最後の 2つの引数は.Fortranと.External

インタフェースによってアクセスされるルーチンのためのものである。上の例では、これら

の型のルーチンを持たないことから NULLが与えられている。

Rが共有オブジェクト/DLLをアンロードしたとき、登録は自動的に抹消される。シンボルを抹消する他の仕組みはない。

ルーチンの登録の例はRソースツリーの別パッケージでも見ることができる (例えば stats)。また、簡潔で高度な導入が R News にある (volume 1/3, September 2001, pages 20–23,http://www.r-project.org/doc/Rnews/Rnews_2001-3.pdf))。

一旦ルーチンが登録されると、もしパッケージのNAMESPACEファイル中のuseDynLibの呼び

出しで配置されたら、Rオブジェクトとして参照することができる (Section 1.6.4 [useDynLib],page 44を参照せよ)。これは使われるたびにエントリポイントを探すオーバーヘッドを避けることができ、パッケージのエントリポイントが使われるものであることを保証する (PACKAGE= "pkg"引数を使うことなく)。だから例えば、パッケージ statsがその NAMESPACEファイルに

# C_という接頭辞がつけられた名前ですべての C/Fortranルーチンを参照する

useDynLib(stats, .registration = TRUE, .fixes = "C_")

という記述を含んでいた場合、ansari.testのデフォルトメソッドは次のように含めるこ

とができる。

pansari <- function(q, m, n)

.C(C_pansari, as.integer(length(q)), p = as.double(q),

as.integer(m), as.integer(n))$p

5.4.1 速度の考慮

ネイティブルーチンを登録することと PACKAGE引数を使うことは大きな違いになることがあ

る。結果はかなり顕著にOS(と 32あるいは 64ビットの場合も含む)、Rのバージョン、その時点でRに他に何がロードされているかということに依存している。

考えをまとめるために、最初に x84_64 Mac OS 10.7とR 2.15.2を考えよう。単純な.Call

関数は次のようになり、

foo <- function(x) .Call("foo", x)

Cのコードは次のようになるであろう。

2 だがこれは現在は行われていない

Page 109: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 103

SEXP foo(SEXP x)

{

return x;

}

もし R CMD SHLIB foo.cによってコンパイルし、コードを dyn.load("foo.so")でロード

し、foo(pi)を実行すると、約 22マイクロ秒 (us)かかった。DLLを次のように指定すると、

foo2 <- function(x) .Call("foo", x, PACKAGE = "foo")

時間は 1.7 usに減少した。

今度はこれらの関数を、NAMESPACEファイルが useDynlib(foo)を使っているパッケージ

の一部にすることを考えよう。これは"foo"が優先的に foo.dllで探されるので、直ちに実行

時間を減少させる。PACKAGEの指定なしでは、約 5 usかかり (起動するたびに適切なDLLを理解する必要があるが、すべてのDLLを探索する必要はない)、PACKAGE引数を伴うと約 1.7usとなる。

次にパッケージがネイティブルーチン fooを登録したと仮定しよう。すると foo()はまた

適切な DLLを見つけなければならないが、DLL中のエントリポイントに速くたどり着けるので、約 4.2 usとなる。foo2()は約 1 usの時間がかかる。もしシンボルを NAMESPACEファ

イルに登録し、以下のコードを利用すると、

foo3 <- function(x) .Call(C_foo, x)

パッケージがロードされたときに一度だけネイティブルーチンのアドレスが探索され、

foo3(pi)は約 0.8 usかかる。

.Call()ではなく、.C()のバージョンを使うと、約 0.2 us余分に時間がかかる。

これらはすべてかなり小さい違いであるが、実行回数が何百万回にもなる数マイクロ秒の

Cルーチンが起動されることは稀ではなく、そのようなことをする人は違いを知っておきたいであろう。

Linuxと Solaris上では、シンボルを探すオーバーヘッドはかなり小さいので、foo(pi)は

foo3(pi)のおよそ 5倍の時間がかかる。

Windows上でのシンボル検索ははるかに遅かったので、Rは小さなキャッシュを保持している。もしシンボルがキャッシュに保存できるほどキャッシュが空いていれば、パフォーマン

スは Linuxと Solarisに類似したものになる。R自身のコードはいつも登録されたシンボルを利用しているので、これらは決してキャッシュには寄与しない: しかしながら、他の多くのパッケージはシンボル検索に頼っているのである。

5.4.2 他のパッケージ内のネイティブルーチンへのリンク

Rによって呼ばれるCルーチンを登録することに加え、あるパッケージがそのCルーチンを他のパッケージのCコードから呼べるようにするということは時折役に立つことがある。これをサポートするためのインタフェースはR 2.4.0から提供されている。インタフェースは以下のように宣言される 2つのルーチンからなる。

void R_RegisterCCallable(const char *package, const char *name,

DL_FUNC fptr);

DL_FUNC R_GetCCallable(const char *package, const char *name);

パッケージ packAのCルーチン myCfunを他のパッケージから利用可能にしたいと思って

いる場合、次の呼び出し

R_RegisterCCallable("packA", "myCfun", myCfun);

Page 110: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 104

を初期化関数 R_init_packAに含める。Cルーチンを使おうとしているパッケージ packBは以下の呼び出しの形式で関数ポインタを取得するであろう。

p_myCfun = R_GetCCallable("packA", "myCfun");

packBの作者は p_myCfunは適切な宣言をしていることを確実にしなければならない。将

来的にRはより大量のルーチンをエクスポートすることを単純化する自動化ツールを提供するかもしれない。

他のパッケージのヘッダファイルを利用したいパッケージは、DESCRIPTIONファイルの

LinkingToフィールドにカンマ区切りのリストとしてそれらを宣言する必要がある。例えば

次のようになる。

Depends: link2, link3

LinkingTo: link2, link3

依存するパッケージは予めインストールしておかなければならないし、予めロードする必

要があるので、それらのパッケージに ‘Depends’している (そのため、コンパイルされたコードのパスは見つけられる)。

これは、インストールされパッケージからリンクされた includeディレクトリが、CとC++コードのインクルードパスに加えられることを用意する。

この仕組みを利用した CRANの例には Matrix (http: / / CRAN . R-project . org /

package=Matrix) へリンクしたパッケージ lme4 (http: / / CRAN . R-project . org /

package=lme4)がある。

5.5 共有オブジェクトの作成

Rにロードするための共有オブジェクトは R CMD SHLIBを用いることで作成できる。このコ

マンドはオブジェクトファイル (拡張子.oがついている)あるいはC、C++、FORTRAN 77、Fortran 9x、Objective CあるいはObjective C++(それぞれ拡張子.c、.ccあるいは.cpp、.f、

.f90あるいは.f95、.m、.mmあるいは.Mがついている)のソースからなるであろうファイルの一覧を引数としてとることが可能である。あるいはリンカに渡すコマンドを引数としてと

ることが可能である。使い方の情報は R CMD SHLIB --help(あるいは Rの SHLIBに関するヘ

ルプ)を参照せよ。

もしソースファイルをコンパイルすることが難しい設定をせず動作しない場合、変数 PKG_

CPPFLAGS (for the C preprocessor, typically ‘-I’ flags), PKG_CPPFLAGS (Cのプリプロセッサでは、一般的には ‘-I’フラグ)、PKG_CFLAGS、PKG_CXXFLAGS、PKG_FFLAGS、PKG_FCFLAGSとPKG_OBJCFLAGS(それぞれ C、C++、FORTRAN 77、Fortran 9xと Objective Cのコンパイラに対し)の一部をコンパイルディレクトリ中の Makevarsファイルに設定することで、追加

フラグを指定することができる (あるいは、もちろんオブジェクトファイルを直接にコマンドラインから生成する)。同様に、Makevars中の変数 PKG_LIBSは、共有オブジェクトをビルド

するときに、追加のフラグ ‘-l’と ‘-L’をリンカに渡すために使うことができる。(R CMD SHLIB

に引数としてリンカのコマンドを供給することは、Makevarsの PKG_LIBSに優先する。)

オブジェクトを作成する適切なルールと共に、Makevarsファイルにマクロ ‘OBJECTS’を設定することで、他の言語でコンパイルされたコードを含める配置をすることが可能である。

既に設定されたフラグ (例えば etcR_ARCH/Makeconfファイル)は以下のBourneシェル構文にあるように、環境変数 MAKEFLAGSによって上書きすることができる (少なくともシステムが POSIX-準拠の makeを使って)。

MAKEFLAGS="CFLAGS=-O3" R CMD SHLIB *.c

Page 111: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 105

またローカル Makevarsファイル、システムの make ファイル、あるいはサイト全体のMakevars.siteファイルの後に読まれる、個別の Makevarsファイルにそのような変数を設

定することもできる。

R CMD SHLIBがMakeを使うとき、フラグが変わったというだけで、共有オブジェクトを再生成しないということに注意。そして、もし test.cと test.fが共にカレントディレクト

リに存在していたら、

R CMD SHLIB test.f

は test.cをコンパイルしないであろう!

もしアドオンパッケージの srcサブディレクトリが上に挙げられた拡張子の一つのソース

コード、あるいは Makefileではなく Makevarsファイルを含んでいる場合、R CMD INSTALLは

R CMD SHLIBの仕組みを用いて共有オブジェクトを生成する (NAMESPACEの useDynlib、ある

いはパッケージの.onLoad関数を通して Rにロードする)。もし Makevarsファイルが存在す

れば、最初にそれが読まれ、次にシステムmakefile、その次に任意の個人的な Makevarsファ

イルが読まれる。

もしパッケージの srcサブディレクトリが Makefileを含んでいるのであれば、これ

は R CMD SHLIBの仕組みに代わって R CMD INSTALLによって使用される。makeは makefileR_HOME/etcR_ARCH/Makeconf、src/Makefileと任意の Makevarsファイルで呼ばれる (この順で)。src/Makefileで最初に見つかったターゲットが使用される。

Makefileよりも Makevarsファイルを使用することが望ましい: 前者は例外的な場合にのみ使用するべきである。

Windowsでも同じコマンドが動作するが、Makevarsよりも優先して Makevars.winが使

用され、R CMD INSTALLによって使われるのは src/Makefile.winだけで、src/Makefileは

無視されるであろう。さまざまなコンパイラで DLL をビルドした過去の経験に関しては、ファイル ‘README.packages’と http://www.stats.uwo.ca/faculty/murdoch/software/

compilingDLLs/を参照せよ。Windowsでは、dllname-win.defと呼ばれるエクスポートの

定義を供給することができる: そうでなければ R CMD SHLIBに供給されるオブジェクト中 (だがライブラリではない)のすべてのエントリポイントがDLLからエクスポートされる。一つの例として、statsパッケージの stats-win.defがある: パッケージ fastICA (http://CRAN.R-project.org/package=fastICA)の CRANの例である。

もしソースコードを読んでこれらの仕組みを破壊したいという気にさせられたなら、抵抗

して欲しい。余りにも多くの開発者の時間がこのドキュメントを追いそこねたことによって

引き起こされたエラーの追跡に費やされ、パッケージの作者がなぜ自身のパッケージが動か

なくなったのかという説明を要求することによってさらに費やされている。特に、文書化さ

れていない環境変数あるいはmake変数はパッケージの作者が使うものではなく、予告なく変更されるものである。

5.6 C++コードとのインタフェース

二つのファイル X.hと X.cppからなり、我々が Rの中で使いたいと思っている 2つのクラスXと Yを実装している以下の仮の C++ライブラリがあるものとする。

Page 112: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 106� �// X.h

class X {

public: X (); ~X ();

};

class Y {

public: Y (); ~Y ();

}; � �// X.cpp

#include <R.h>

#include "X.h"

static Y y;

X::X() { REprintf("constructor X\n"); }

X::~X() { REprintf("destructor X\n"); }

Y::Y() { REprintf("constructor Y\n"); }

Y::~Y() { REprintf("destructor Y\n"); } Rで使うために、やらなければならない唯一のことは、ラッパー関数を書き、関数が次の

もので囲まれているようにすることである。

extern "C" {

}

例えば、� �// X_main.cpp:

#include "X.h"

extern "C" {

void X_main () {

X x;

}

} // extern "C" コンパイルとリンクはC++のコンパイラ、リンカでしなければならない (Cのコンパイラ、

リンカあるいはリンカ自身ではなく); そうでなければ、C++の初期化コード (それゆえ静的変数 Yのコンストラクタ)が呼ばれない。適切に設定されたシステムでは、以下のようにして共有オブジェクトを生成するために簡単に使うことができる。

Page 113: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 107

R CMD SHLIB X.cpp X_main.cpp

一般的には X.soが生成される (ファイル名の拡張子はあなたのプラットフォームとは異なるかもしれない)。さて、Rを始めると以下の内容がもたらされる。

R version 2.14.1 Patched (2012-01-16 r58124)

Copyright (C) 2012 The R Foundation for Statistical Computing

...

Type "q()" to quit R.

R> dyn.load(paste("X", .Platform$dynlib.ext, sep = ""))

constructor Y

R> .C("X_main")

constructor X

destructor X

list()

R> q()

Save workspace image? [y/n/c]: y

destructor Y

WindowsのRの FAQ (rw-FAQ)はWindowsでこの例をどのようにコンパイルするかという方法の詳細について述べている。

この例の初期のバージョンではC++の iostreamsを使用していた。これは避けたほうがよい。Rのコンソールに出力が現れる保証はなく、実際にWindowsの Rのコンソールには現れないであろう。可能なすべての場合で、すべての入出力に対しRのコード、あるいはCのエントリポイント (see Section 6.5 [印字], page 139)を使用せよ。R自身の Cの I/Oを混乱させるC++の I/Oへの呼び出しを含むDLLの単なるロードをする例が見られる (例えば開いているファイルのバッファをリセットすることなど)。

大部分のRのヘッダファイルはC++のプログラムにインクルードすることはできるが、それらは extern "C"ブロック内部に含められるべきではない (C++のシステムヘッダをインクルードするにつれて)。逆に Rのヘッダが Cのヘッダファイルを含むにつれて Rのヘッダをインクルードするのは不可能になるであろう—もしこれが生じたら、Rヘッダをインクルードする前に ‘NO_C_HEADERS’を定義し、Rヘッダの前に自身で適切なC++版 (‘cmath’のように)のヘッダをインクルードせよ。

5.7 Fortran I/O

出力が Rのコンソールに現れる保証がないということから、C++の入出力ストリームを少なからず使用することに対して既に警告してきた。そして、この警告は Fortran (77あるいは9x)の*と 6の一式への出力にも同様に適用される。See Section 6.5.1 [FORTRANからの印字], page 140では回避方法を記載している。

過去の大部分の Fortran コンパイラは C I/O の上に I/O を実装しているので、2 つの相互作用はうまくいく。これは g77では当てはまっていたが、gcc 4.y.zで利用されている

gfortranではそれほど当てはまっていない。特に Fortran I/Oを利用するすべてのパッケージはWindowsでコンパイルされたときに、C I/Oに干渉する: Fortran I/Oが初期化されたとき (一般的にパッケージがロードされたとき)に、Cの stdoutと stderrはLFの行末に切り替えられる。(ファイル src/modules/lapack/init_win.cの init関数はこれを和らげる方

法を示している。)さらに悪いことに、R 2.6.2より前では、Windows GUIコンソール (Rgui)で Fortranの出力を利用していると Rセッションはハングしたものだった。これは現在では

Page 114: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 108

Fortranの出力がファイルに書き出されることを保証することによって回避されている (ワーキングディレクトリの fort.6に書き込む)。

5.8 他のパッケージへのリンク

パッケージ packAのDLLを packBから提供されるDLLにリンクすることは一般的には可能ではない (Section 5.3 [dyn.loadと dyn.unload], page 98で述べたセキュリティ上の理由と、共有オブジェクトと動的ライブラリを区別するプラットフォームがあるため)が、Windowsでは可能である。

packAの後に packBを再インストールすることのように、ここには手の込んだ問題がありうることに注意 — パッケージ packBによって提供されるAPIは後方互換性を残していることが望ましい。

5.8.1 Unix系

Unix系 OSでは、限られた環境において、パッケージ packAの共有オブジェクトからパッケージ packBから提供されるライブラリへリンクすることが可能である。厳しい移植性の問題があるので、配布されるパッケージに対してこれは推奨されない。

もし packBが静的ライブラリ packB/libs/libpackB.aを提供しているのであれば、これ

が最も簡単である。(ライブラリはそれが重要となるプラットフォームでは、PICフラグをつけてコンパイルされる必要があるだろう。)するとパッケージ packAがインストールされるときに、パッケージ packBからのコードが組み込まれるので、必要なのはインストール時にパッケージ packBのために静的ライブラリを見つけることだけである。唯一の問題はパッケージpackBを見つけることで、そのために以下のようにしてRに尋ねることができる。

PKGB_PATH=‘echo ’cat(system.file("libs", .Platform$r_arch, package="packB", mustWork=TRUE))’ \

| "${R_HOME}/bin/R" --vanilla --slave‘

PKG_LIBS="$(PKGB_PATH)/libpackB.a"

これはサブアーキテクチャが使われてないときに空のパスコンポーネントを与える (だが現在のプラットフォームで動作する)。

動的ライブラリpackB/libs/libpackB.so(Mac OS X上のpackB/libs/libpackB.dylib)に対しては、次のものを使うことができる。

PKGB_PATH=‘echo ’cat(system.file("libs", .Platform$r_arch, package="packB", mustWork=TRUE))’ \

| "${R_HOME}/bin/R" --vanilla --slave‘

PKG_LIBS=-L"$(PKGB_PATH)" -lpackB

これはインストール時に動作するが、パッケージpackBのlibsディレクトリへのパスがld.so3

のサーチパスにないことから、パッケージ packBがロードされたときにはまず動作しないであ

ろう。Rが起動される前に、LD_RUN_PATH、LD_LIBRARY_PATHを設定する、あるいは ld.so

キャッシュ(man ldconfigを参照せよ)に加えることで、パスをそこに配置することができる。それをサポートするプラットフォームでは、動的ライブラリへのパスはインストール時にハー

ドコードできる (パッケージ packBの位置は変化しないと仮定できる)。GNUリンカ (例えばLinux)を使うシステムとその他 (例えばMac OS X)では、これは次のようにしてできる。

PKGB_PATH=‘echo ’library(packB); cat(system.file("libs", package="packB"))’ \

| "${R_HOME}/bin/R" --vanilla --slave‘

PKG_LIBS=-L"$(PKGB_PATH)" -rpath "$(PKGB_PATH)" -lpackB

3 Mac OS Xでは dyldと DYLD_LIBRARY_PATHSの下

Page 115: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 109

そして別のシステム (例えば、ネイティブリンカを用いた Solaris)では-rpathよりも-Rを使

うべきである。

R CMD libtool --configの結果から、半自動的に必要とされるものを理解することがで

きるであろう (‘hardcode’を探す)。

パッケージ packAのコンパイルされるコードが、パッケージ packBから提供されたヘッダを利用可能にすることは、LinkingToの仕組みによってできる (see Section 5.4 [ネイティブルーチンの登録], page 100)。

5.8.2 Windows

パッケージ packAが packBのDLL packB/libs/exB.dll、もしかするとパッケージのDLLpackB/libs/packB.dllによって提供されるコンパイル済コードを使用したいということを

考えよう。(同様にして、これは複数のパッケージへのリンクに拡張できる。)3つの取り組むべき問題がある:

• パッケージ packAのコンパイルされるコードが、パッケージ packBから提供されたヘッダを利用可能にすること。

これは LinkingToの仕組みによってなされる (see Section 5.4 [ネイティブルーチンの登録], page 100)。

• packA.dllを packB/libs/exB.dllへリンクする準備をすること。

これは Makevars.winに以下の形式のエントリを必要とする。

PKG_LIBS= -L<something> -lexB

そして、一つの可能性として、<something>はインストールされた pkgB/libsディレク

トリのパスである。パスを知るために、Rにそれがどこかと尋ねる必要がある。

PKGB_PATH=‘echo ’library(packB); cat(system.file("libs", package="packB"))’ \

| rterm --vanilla --slave‘

PKG_LIBS= -L"$(PKGB_PATH)" -lexB

別の可能性はパッケージ packAがエクスポートファイル exB.defに送り込んだインポー

トライブラリを使うことである。すると、Makevars.winは次のものを含むことができる。

PKG_LIBS= -L. -lexB

all: $(SHLIB) before

before: libexB.dll.a

libexB.dll.a: exB.def

すると、インストールしているパッケージ packAは exB.dllに対するインポートライ

ブラリを作成し、利用するであろう。(エクスポートファイルを準備する一つの方法はpexports.exeを使うことである。)

• exB.dllに依存している packA.dllをロードすること。

もしパッケージ packB によって exB.dllが使用されていて (事実、packB.dllか

packB.dllはパッケージに依存している)、packBが packAの前にロードされていたら、R実行形式に既に exB.dllがロードされているので、これ以上何もする必要がない (これは最もよくあるシナリオである)。

より一般的には、exB.dllが見つかることを保証するために、library.dynamに引数

DLLpathを使うことができる。例えば、次のように設定することによる。

Page 116: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 110

library.dynam("packA", pkg, lib,

DLLpath = system.file("libs", package="packB"))

DLLpathは 1つだけパスを設定できるので、2つ以上のパッケージへのリンクをするには、PATHに設定することに頼る必要があることに注意。

5.9 CでRのオブジェクトを扱う

Rの関数の実行速度を上げるためにCのコードを使うことはしばしばとても有益である。伝統的にこれは Rの.C関数を通して行われてきた。しかしながら、もしユーザが内部の Rのデータ構造を使って Cコードを書きたいと思うのであれば、.Callと.External関数を使っ

てそれを行うことができる。各場合においてRで関数を呼び出すための文法は、.Cのそれに

似ているが、2つの関数は異なる Cインタフェースを持っている。一般的に、.Callインタ

フェース (Sバージョン 4の同じ名前のインタフェースに基づいてモデル化されている)は使うには多少簡単であるが、.Externalはもう少し一般的になる。

.Callへの呼び出しは.Cによく似ていて、例えば次のようになる。

.Call("convolve2", a, b)

最初の引数は既に Rにロードされたコードの Cシンボル名を表す文字列でなければならない。最大で 65個のRオブジェクトを引数として渡すことができる。C側のインタフェースは次のようになる。

#include <R.h>

#include <Rinternals.h>

SEXP convolve2(SEXP a, SEXP b)

...

.Externalへの呼び出しはほぼ同一で、

.External("convolveE", a, b)

となるが、C側のインタフェースは異なっており、次のように引数を一つだけ持っている。

#include <R.h>

#include <Rinternals.h>

SEXP convolveE(SEXP args)

...

ここで argsは LISTSXPという、引数が抽出できる Lispスタイルのペアリストである。

それぞれの場合で、Rオブジェクトはヘッダファイル Rinternals.hで定義された関数とマ

クロの集合、あるいは Rdefines.hで定義された S4と互換性のあるマクロを通して操作できるようになる。.Callと.Externalの詳細については、Section 5.10 [インタフェース関数.Callと.External], page 120を参照せよ。

.Callまたは.Externalを使うことを決める前に、他の選択肢を見るべきである。第一に、

Rのインタプリタコードの動作を検討せよ; もしこれが十分早ければ、これは通常は最高の選択肢である。.Cを使うことが十分かどうかを見るべきでもある。もしCで動作するタスクが原子ベクトルだけ取り込み、Rへの呼び出しを必要としないほど十分に単純であれば、.Cで

十分である。新しいインタフェースは SとRの比較的新しい追加部分で、それが利用可能になる前に、.Cだけを使用して書かれた有用なコードは大量にある。.Callと.Externalインタ

フェースはより多くの制御を可能としているが、より多くの責任を課すので注意して使う必

Page 117: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 111

要がある。.Callも.Externalも引数をコピーしない: これらのインタフェースを通して受け取った引数は読み込み専用として扱わなければならない。

Cコード内からRオブジェクトを扱うために 2つのアプローチを取ることができる。1番目(歴史的に)は、.Internalの呼び出しを介して、Rのコア部分を実装するために使われてきたマクロと関数を利用することである。これらの公開された 4部分集合は任意のRのインストールで利用可能でなければならないディレクトリ R_INCLUDE_DIR(既定値は R_HOME/include)内のヘッダファイル Rinternals.hで定義されている。

別のアプローチはヘッダファイルRdefines.hに定義された、Sバージョン 4のインタフェースに対し定義されたマクロと関数のR版を使うことである。これはいくらか単純なアプローチであり、コードが Sと共有されることを意図しているのであれば、好ましいであろう。しかしながら、あまり文書化されておらず、テストさえあまりされていない。これらのマクロ

(文字ベクトルやリストの要素を割り当てるといったこと)を用いた慣用的な S4の構造はRでは不適切であることにも注意。

ここで記した関数とマクロを使ってかなりの量の Rが実装されているので、Rのソースコードは例と “やり方”の豊富な情報源を提供する: 心に強く訴える例のためにソースコードを使用せよ。

Cコードでどのように Rオブジェクトが扱われるかについて何かを知ることは必要である。扱うことになる Rオブジェクトのすべては、SEXPRECと typedefされた構造体へのポインタである SEXP型 5で扱われる。この構造体はRオブジェクトの通常の型、つまり様々なモードのベクトル、関数、環境、言語オブジェクトなどをすべて扱える variant型と考えよ。詳細はこの節の後ろと Section “R Internal Structures” in R Internalsで与えているが、大部分の目的でプログラマはそれを知る必要はない。それよりも Rオブジェクトが Cコード (RオブジェクトはRのインタプリタコードにあるので)に variant型として順に配布され、例えば数値計算で必要となったときだけ適切な部分が抽出されるという、Visual Basicで使われるようなモデルを考えよう。Rのインタプリタコードのように、多くの使用は variantオブジェクトを正しい型に強制変換することからなる。

5.9.1 ガーベージコレクションの影響を扱う

Rがメモリ割当を処理する方法について少し知る必要がある。Rオブジェクトへのメモリ割当はユーザによって開放されない; 代わりに、メモリは随時ガーベージコレクションされる。つまり、確保されたメモリで使われていないものの一部、あるいはすべてが解放されるか、再

利用可能としてマークされる。

Rオブジェクトの型は Rinternals.hにある typedef SEXPRECによって定義された、Cの構造体で表される。構造体はデータブロックや他の SEXPRECへのポインタをいくつか含む。

SEXPは単に SEXPRECへのポインタである。

もし Cコードで Rオブジェクトを作成したのであれば、オブジェクトを使っていることを、オブジェクトへのポインタに PROTECTマクロを使うことによって、Rにそれを伝えなければならない。これはRにオブジェクトが使用中であることを伝え、従ってオブジェクトはガーベージコレクションの間に破壊されないことになる。保護されるのはオブジェクトであ

り、ポインタ変数ではないことに気をつけよ。もしある時点で PROTECT(p)を呼び出したら、

以後 pが保護されるというのはよくある間違いである。ただし、一度新しいオブジェクトが pに割り当てられると、これは真ではない。

4 see Chapter 6 [R API], page 136: これらは APIのすべての部分ではないことに注意。5 SEXPは LISP系言語の構文では共通の S imple EXPressionの頭文字である。

Page 118: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 112

1つの Rオブジェクトを保護すると、自動的に対応する SEXPRECを指すすべての Rオブジェクトを保護する。例えば、保護されたリストのすべての要素は自動的に保護される。

プログラマは単に PROTECTの呼び出しへのハウスキーピングに責任をもつ。対応するマ

クロ UNPROTECTがあり、それはオブジェクトがもはや不要となったときに、保護を解除す

るオブジェクトの数を与える引数 intを取る。保護の仕組みはスタックに基づいているの

で、UNPROTECT(n)は最後に保護された n個のオブジェクトの保護を解除する。PROTECTと

UNPROTECTの呼び出しはユーザのコードが終了するときに釣り合わなければならない。も

しハウスキーピング処理が間違っていれば、R は"stack imbalance in .Call"(あるいは.External)について警告する。

以下はCコードでRの数値ベクトルを作成する小さな例である。最初に Rinternals.hの

マクロを利用する:

#include <R.h>

#include <Rinternals.h>

SEXP ab;

....

PROTECT(ab = allocVector(REALSXP, 2));

REAL(ab)[0] = 123.45;

REAL(ab)[1] = 67.89;

UNPROTECT(1);

そして、Rdefines.hのマクロを使う:

#include <R.h>

#include <Rdefines.h>

SEXP ab;

....

PROTECT(ab = NEW_NUMERIC(2));

NUMERIC_POINTER(ab)[0] = 123.45;

NUMERIC_POINTER(ab)[1] = 67.89;

UNPROTECT(1);

さて、読者は上の Cコードがちょうど動作しているような操作の間に、どのように Rオブジェクトを除去することができるか問うかもしれない。この例では、偶然にも保護なしで

行えばできるが、一般には利用するRのマクロと関数の後ろに隠れているものが何か、それらのいずれがメモリ割り当てを引き起こしているか知らないし (知りたくもない)、それゆえガーベージコレクションとオブジェクト abが除去される。

いくつかの場合では、保護が本当に必要とされているかよく経過を追跡する必要がある。

特に大量のオブジェクトが生成される状況では注意せよ。ポインタ保護スタックは固定サイズ

(既定値は 10,000)で、いっぱいになることもありうる。従って、見えるすべてをただ PROTECT

して、最後の数千のオブジェクトを UNPROTECTすることは良い考えではない。ほぼいつでも

オブジェクトを他のオブジェクト (自動的にプロテクトされる)の一部として割り当てること、あるいはオブジェクトの使用後に直ちに保護を解除することのどちらかは可能である。

Rが既に知っていて、使用されているオブジェクトに保護は必要ない。特に、これは関数の引数に適用される。

ポインタ保護スタックで一番上になくても、SEXP sによって指されるオブジェクトの保護を解除する、あまり使われないマクロ UNPROTECT_PTR(s)がある。これはパーサの外部からは

Page 119: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 113

ほとんど必要とされない (Rのソースは 3つの例を持ち、1つは src/main/plot3d.cにある)。

現在の値がまだ保護される必要があるのにオブジェクトが変更されることがある (例えば重複、強制変換、成長)。このような場合に PROTECT_WITH_INDEXは REPROTECTを使って保護

された値を置き換えるために使われる保護の場所のインデックスを保存する。例えば次のよ

うになる (optimの内部コードから)。

PROTECT_INDEX ipx;

....

PROTECT_WITH_INDEX(s = eval(OS->R_fcall, OS->R_env), &ipx);

REPROTECT(s = coerceVector(s, REALSXP), ipx);

UNPROTECT_PTRを PROTECT_WITH_INDEXと混ぜるのは、前者はオブジェクトの保護が解除

された後に、保護されていたオブジェクトの保護の位置を変えるため、危険であることに注意。

5.9.2 ストレージの割り当て

多くの目的で、R オブジェクトを割り当てて、それらを操作することだけで十分である。Rinternals.hに定義された、かなりの数の allocXxx関数がある—それらを探索してみたくなるかもしれない。これらはさまざまな型のRオブジェクトを割り当て、標準的なベクトル型に対しては、Rdefines.hに定義された同等の NEW_XXXマクロがある。

もし計算途中でCオブジェクトに対しストレージが必要になるのであれば、R_allocを呼

び出して確保するのが最善である; see Section 6.1 [メモリ割り当て], page 137.これらのメモリ確保ルーチンのすべては自身のエラーチェックを行うので、もしメモリが確保できなかった

ら、ルーチンがエラーを発生させ、返ってこないということをプログラマは仮定すればよい。

5.9.3 Rの型の詳細

Rinternals.hのマクロのユーザは Rの型が内部でどのように知られているかを知っておく必要がある: もし Rdefines.hのマクロが使われているのであれば、S4と互換性のある名前が使われる。

Rのデータ型の違いは Cでは SEXPTYPEによって表される。これらのいくつかは Rに通じるものがあり、内部型に通じるものもある。通常のRオブジェクトのモードは以下の表で与えられる。

SEXPTYPE Rで同等なものREALSXP 保存モードが doubleの数値

INTSXP 整数

CPLXSXP 複素数

LGLSXP 論理値

STRSXP 文字

VECSXP リスト (総称的ベクトル)LISTSXP ペアリスト

DOTSXP ‘...’オブジェクトNILSXP NULLSYMSXP 名前/シンボルCLOSXP 関数または関数のクロージャ

ENVSXP 環境

Page 120: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 114

内部の SEXPTYPEの間で重要なのは LANGSXP、CHARSXP、PROMSXPなどである。(注意: 内部のオブジェクト型を返すことはできるが、それらが扱われるかということについてされる仮定

が、ユーザレベルの評価で違反するかもしれないので、内部のオブジェクト型を返すのは安全

ではない。)更なる詳細は Section “R Internal Structures” in R Internalsで与えられている。

引数の型についてかなりの確信がない限り、コードはデータ型をチェックするべきである。

ときおりCコードで作成されたRの式を評価することで作成されたオブジェクトのデータ型をチェックする必要もあるかもしれない。型の確認のために isReal、isIntegerと isString

のような関数を使うことができる。その他の類似した関数の定義についてはヘッダファイル

Rinternals.hを見よ。これらの関数はすべて引数として SEXPを取ることができ、TRUEあるいは FALSEを示す 1あるいは 0を返す。もう一度、データ型を確認するには二つの方法があり、Rdefines.hには IS_NUMERICのようなマクロがある。

もし SEXPが正しい型でなかったら何が起こるだろうか?時々エラーを発生させる以外に選択がないことがある。このために関数 errorを使うことができる。オブジェクトを正しい型

に強制変換することが通常は望ましい。例えば、もし SEXPが型 INTEGER型であったことが分

かったが、REALオブジェクトが必要であった場合、次のような同等の方法で型を変えること

ができる。

PROTECT(newSexp = coerceVector(oldSexp, REALSXP));

あるいは

PROTECT(newSexp = AS_NUMERIC(oldSexp));

保護は新しいオブジェクトが作成されたときに必要となる; SEXPによって以前指されていたオブジェクトは保護されるが、今では使われていない。

すべての強制変換関数は自身のエラーチェックを行い、必要に応じて、警告と共に NAを生

成するか、あるいはエラーと共に停止する。

これらの強制変換関数は、オブジェクトのクラスを送出しないことから、R コードでas.numeric(など)を呼ぶことと同じではない。従って、通常は Rコードの呼び出しの中で強制変換を行うのが好ましい。

ここまで、CコードからRオブジェクトの生成と強制変換をどのようにするか、Rの数値ベクトルから数値データをどのように取り出すかということだけを見てきた。これらはRオブジェクトと数値計算アルゴリズムを結びつけるのに十分である可能性があるが、役に立つ

返り値オブジェクトを生成するにはもう少し知る必要がある。

5.9.4 属性

多くの Rオブジェクトは属性を持つ: 最も役立つものには、クラスと、オブジェクトを行列や配列として特徴付ける dimと dimnamesがある。ベクトルの names属性を使って作業するの

も役立つであろう。

これを説明するために、2つのベクトルの外積をとるコードを書いてみよう (outerと%o%

が既にしていることであるが)。いつもの通り、Rのコードは単純である。

out <- function(x, y)

{

storage.mode(x) <- storage.mode(y) <- "double"

.Call("out", x, y)

}

ここで xと yは数値ベクトル (おそらくは整数)で、もしかすると名前がついていることを期待している。今回は、呼び出しているRコードで強制変換を行う。

Page 121: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 115

計算をするための Cコードは次のようになる。

#include <R.h>

#include <Rinternals.h>

SEXP out(SEXP x, SEXP y)

{

R_len_t i, j, nx = length(x), ny = length(y);

double tmp, *rx = REAL(x), *ry = REAL(y), *rans;

SEXP ans;

PROTECT(ans = allocMatrix(REALSXP, nx, ny));

rans = REAL(ans);

for(i = 0; i < nx; i++) {

tmp = rx[i];

for(j = 0; j < ny; j++)

rans[i + nx*j] = tmp * ry[j];

}

UNPROTECT(1);

return(ans);

}

REALが使われている方法に注意: 関数呼び出しなので、結果を保存することと索引付けがかなり速くなる可能性がある。

しかし、結果に dimnamesを設定したい。allocMatrixは一つのショートカットを提供す

るが、我々はどのように直接 dim属性を設定するかを見せる。

#include <R.h>

#include <Rinternals.h>

SEXP out(SEXP x, SEXP y)

{

R_len_t i, j, nx = length(x), ny = length(y);

double tmp, *rx = REAL(x), *ry = REAL(y), *rans;

SEXP ans, dim, dimnames;

PROTECT(ans = allocVector(REALSXP, nx*ny));

rans = REAL(ans);

for(i = 0; i < nx; i++) {

tmp = rx[i];

for(j = 0; j < ny; j++)

rans[i + nx*j] = tmp * ry[j];

}

PROTECT(dim = allocVector(INTSXP, 2));

INTEGER(dim)[0] = nx; INTEGER(dim)[1] = ny;

setAttrib(ans, R_DimSymbol, dim);

Page 122: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 116

PROTECT(dimnames = allocVector(VECSXP, 2));

SET_VECTOR_ELT(dimnames, 0, getAttrib(x, R_NamesSymbol));

SET_VECTOR_ELT(dimnames, 1, getAttrib(y, R_NamesSymbol));

setAttrib(ans, R_DimNamesSymbol, dimnames);

UNPROTECT(3);

return(ans);

}

この例はいくつかの新しい特徴を紹介している。getAttribと setAttrib 関数は個々の

属性を取得、設定する。それらの関数の 2 つ目の引数は、我々が必要とする属性のシンボル表に名前を定義する SEXPである; これらとこのような多くのシンボルはヘッダファイルRinternals.hに定義されている。

ここにも近道がある: 関数 namesgets、dimgetsと dimnamesgetsはそれぞれ

names<-、dim<-と dimnames<-(ベクトルと配列用)という既定のメソッドの内部版であり、GetMatrixDimnamesと GetArrayDimnamesのような関数がある。

もし事前に定義されていない属性を加えたい場合はどうなるであろうか?そのためにinstallへの呼び出しを通して、その属性に対するシンボルを加える必要がある。説明のた

め、値 3.0属性"version"を加えたいと仮定しよう。次のように使うことができる。

SEXP version;

PROTECT(version = allocVector(REALSXP, 1));

REAL(version)[0] = 3.0;

setAttrib(ans, install("version"), version);

UNPROTECT(1);

必要とされていないときに installを使うことは無害であり、もしシンボルが既に表に設

定されていたら、シンボル表からシンボルを検索するのに簡単な方法を提供する。しかしな

がら、検索にはわずかではない時間がかかるので、もし検索が頻繁に行われるようであれば、

static SEXP VerSymbol = NULL;

...

if (VerSymbol == NULL) VerSymbol = install("version");

のようにせよ。

5.9.5 クラス

Rではクラスは"class"と名づけられた属性であるので、そのようなものとして扱うことが

できるが、classgetsという近道がある。我々の例の返り値に"mat"というクラスを与えたい

と考えよう。これは次のようにできる。

#include <R.h>

#include <Rdefines.h>

....

SEXP ans, dim, dimnames, class;

....

PROTECT(class = allocVector(STRSXP, 1));

SET_STRING_ELT(class, 0, mkChar("mat"));

classgets(ans, class);

UNPROTECT(4);

return(ans);

}

Page 123: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 117

値は文字ベクトルなので、関数 mkCharを使って、Cの文字配列からそれを作る方法を知っておかなければならない。

5.9.6 リストを扱う

Rは早い段階で LISP風のリスト (今では “ペアリスト”と呼ばれている)から S風の総称的ベクトルを使うことに移行したので、リストに関しては多少注意が要る。結果として、モー

ド listのオブジェクトに対する適切なテストは isNewListとなり、allocList(n)ではなく、

allocVector(VECSXP, n)が必要となる。

総称的ベクトルの要素に直接アクセスすることにより、リストの要素を検索あるいは設定

することができる。次のようなリストオブジェクトがあるとしよう。

a <- list(f = 1, g = 2, h = 3)

そして、次のようにすることで、a[[2]]として a$gにアクセスできる。

double g;

....

g = REAL(VECTOR_ELT(a, 1))[0];

これはすぐに面倒になりうるし、以下の関数 (パッケージ statsの中の関数に基づく)はとても役立つであろう:

/* strと名づけられたリストの要素を取得する。なければ NULLを返す */

SEXP getListElement(SEXP list, const char *str)

{

SEXP elmt = R_NilValue, names = getAttrib(list, R_NamesSymbol);

for (R_len_t i = 0; i < length(list); i++)

if(strcmp(CHAR(STRING_ELT(names, i)), str) == 0) {

elmt = VECTOR_ELT(list, i);

break;

}

return elmt;

}

そして次のように言うことができる。

double g;

g = REAL(getListElement(a, "g"))[0];

5.9.7 文字データを扱う

Rの文字ベクトルは、すべての要素が CHARSXP型である VECSXPのようなベクトル型である

STRSXPとして保存される。STRSXPの CHARSXP要素は STRING_ELTと SET_STRING_ELTを用い

てアクセスできる。

CHARSXPは読み込み専用オブジェクトで、決して修正してはならない。特に CHARSXPの中に

含まれるCスタイルの文字列は読み込み専用として扱い、この理由から文字データの CHARSXP

にアクセスするために使われる CHAR関数は、(const char *)を返さなければならない (これはコンパイラが不適切な使用について警告を発することを可能にする)。CHARSXPは不変なの

で、同じ CHARSXPは同じ文字列を表す要素を必要としている任意の STRSXPによって、共有す

ることができる。

Page 124: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 118

mkCharを呼び出すことと、null 終端の C スタイルの文字列を提供することによって、CHARSXPを得ることができる。この関数はもし対応する文字列が既に存在しているのであれ

ば、既存の CHARSXPを返す。そうでなければ新しく作成し、返す前にキャッシュに加える。

変異した mkCharLenはバッファの一部から CHARSXPを作るために使うことができ、nullが終端であることを保証する。

Rの文字列は 2^31 - 1バイトに制限されており、そのため mkCharへの入力もそうなって

いなければならないことに注意 (64ビットプラットフォームでは、Cはより長い文字列を許可している): 関数自身ではR 2.15.1より前ではチェックをしない。

5.9.8 変数の発見と設定

Cでの計算に必要とされるすべての Rオブジェクトが、.Callあるいは.Externalに引数と

して渡されるのは普通であるだろうが、与えられた名前からCの内部でRオブジェクトの値を見つけることが可能である。以下のコードは get(name, envir = rho)と同等である。

SEXP getvar(SEXP name, SEXP rho)

{

SEXP ans;

if(!isString(name) || length(name) != 1)

error("name is not a single string");

if(!isEnvironment(rho))

error("rho should be an environment");

ans = findVar(install(CHAR(STRING_ELT(name, 0))), rho);

Rprintf("first value is %f\n", REAL(ans)[0]);

return(R_NilValue);

}

主な動作は findVar によってなされるが、それをつかうためにはシンボル表に名前として

nameを設定しておく必要がある。値が内部的な使用で欲しかったので、NULLを返している。

同様の構文を持つ関数は以下のものがある。

void defineVar(SEXP symbol, SEXP value, SEXP rho)

void setVar(SEXP symbol, SEXP value, SEXP rho)

これらはRの変数に値を割り当てるために使うことができる。defineVarは新しいバインドを作るか、特定の環境フレームにある既存のバインドの値を変更する; assign(symbol, value,

envir = rho, inherits = FALSE)の類似物であるが、assignとは異なり、defineVarはオブ

ジェクト valueのコピーを作成しない。6setVarは rho、あるいはそれを取り巻く環境内で

symbolに対する既存のバインドを探す。もしバインドが見つかれば、その値は valueに変更

される。見つからなければ、グローバル環境に指定された値で新しいバインドが生成される。

これは assign(symbol, value, envir = rho, inherits = TRUE)に対応している。

5.9.9 いくつかの便利な関数

いくつかの命令は頻繁に行われるので、それらを扱う便利な関数がある。(これらのすべてはヘッダファイル Rinternals.hを通して提供されている。)

1つの論理値引数 ignore_quotesを渡したいとしよう: 以下のようにすることができる。

6 defineVar(symbol, duplicate(value), rho))を使って環境フレームにオブジェクトの copy を割り当てることができる。

Page 125: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 119

int ign = asLogical(ignore_quotes);

if(ign == NA_LOGICAL) error("’ignore_quotes’ must be TRUE or FALSE");

これは必要な強制変換を行い (少なくともベクトル引数から)、そして渡された値が NA、あるい

は強制変換が失敗した場合にはNA_LOGICALを返す。同様のasInteger、asRealとasComplex

もある。関数 asCharは CHARSXPを返す。これらすべての関数は先頭より後ろの入力ベクトル

のすべての要素を無視する。

長さ 1の実数ベクトルを返すために、次のものを使うことができる。

double x;

...

return ScalarReal(x);

そしてすべての原子ベクトル型に対して、これのバージョンがある (長さ 1の文字ベクトル用で、引数が CHARSXP型の ScalarStringと、const char *型の mkStringに対するもの)。

isXXXX関数には、その見かけのRレベルの対応とは異なるものがある: 例えば、isVectorは任意の原子ベクトル型 (isVectorAtomic)と、リストと式 (isVectorList)(属性のチェックなしで)に対して真である。isMatrixは長さ 2の"dim"属性のテストである。

ペアリストと言語オブジェクトの構築物に役立つ、一連の小さなマクロ/関数がある (内部の構造は単に SEXPTYPEによって異なる)。関数 CONS(u, v)は基本構成要素である: uからの

ペアリストに v(ペアリストあるいは R_NilValueである)が続く構築物である。LCONSは言語

オブジェクトを構築する変異体である。関数 list1から list5は 1から 5個の項目からペアリストを生成し、関数 lang1から lang6は言語オブジェクトに対して同様のことを行う (0から 5つの引数を加えて呼び出す関数)。関数 eltと lastEltはペアリストの i番目の要素と最後の要素を見つけ、nthcdrはペアリストの n番目の位置を指すポインタを返す (その CARは n番目の項目である)。

関数 str2typeと type2strはRの長さ 1の文字列と SEXPTYPEの数字を相互にマッピング

し、type2charは数字を Cの文字列へマッピングする。

5.9.9.1 半内部の便利な関数

もし稀な “API”の変化に適応する意思があるのであれば、Cコードで使うことができるかなりの関数の集まりがある。これらは、通常はそれらのRに対応する “馬車馬”を含んでいる。

関数 any_duplicatedと any_duplicated3はRの any(duplicated(.))の高速版である。

関数 R_compute_identicalはRの identical関数に対応する。

5.9.10 名前付きオブジェクトとコピー

以下のようにRで割り当てがされたとき、

x <- 1:10

y <- x

名前付きオブジェクトは必ずしもコピーされる必要はなく、そのため 2つの割り当ての後にyと xは同じ SEXPREC(SEXPが指す構造体)に結び付けられる。これは、それらの中の 1つを変える任意のコードは、もし通常のRの意味論が適用されるのであれば、コピーを修正する前にコピーをしなければならないことを意味する。.Cと.Fortranは引数をコピーする一方 (危険な dup = FALSEが使われない限り)、.Callと.Externalはコピーしないことに注意。その

ため duplicateは引数を修正する前に、一般的に.Callへの引数に対し呼び出される。

Page 126: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 120

しかしながら、このコピーの少なくともいくつかは不必要である。最初の割り当てが示す

x <- 1:10では、Rはまず値 1:10を持つオブジェクトを生成し、それから xへ代入するが、も

し xが修正されたら、値 1:10を持つ一時オブジェクトは二度と参照できないので、コピーは

必要ない。Rはマクロ NAMEDと SET_NAMEDを経由してアクセスできる SEXPRECのフィールド

から名前付きと名前付きでないオブジェクトを区別している。これは次の値を取ることがで

きる。

0 オブジェクトは任意のシンボルにバインドされていない

1 オブジェクトはちょうど 1つのシンボルにバインドされている

2 オブジェクトは潜在的に 2つ以上のシンボルにバインドされており、他の変数が現在この値にバインドされているようにオブジェクトは振る舞わなければなら

ない。

過去の存在に注意: Rは完全な参照カウントをせず、今のところでは少ないバインディングになっているかもしれない。

NAMED(foo)が 0である任意の SEXPの値を変更することは安全で、もし NAMED(foo)が 2であれば、任意の変更の前に、値は複製されていなければならない (duplicateへの呼び出しを通じて)。y <- xの後に xの値が変更されていたとしても、複製のために変更するコードの

作者の責任であることに注意。

NAMED(foo) == 1の場合には、いくらかの最適化が可能であるが、無視される可能性もあ

る (そして複製は NAMED(foo) > 0のときにはいつでも行われる)。(この最適化は今のところユーザのコードでは利用可能ではない)置換する関数の内部での使用を意図したものである。以下のものを使ったとしよう。

x <- 1:10

foo(x) <- 3

これは次のように計算される。

x <- 1:10

x <- "foo<-"(x, 3)

すると"foo<-"の内部で、xの現在の値を指すオブジェクトは NAMED(foo)を 1とする。それにバインドされた唯一のシンボルは xであるため、変更することは安全で、すぐに再バイン

ドできるだろう。("foo<-"の残りのコードが xへの参照がなく、誰も y <- "foo<-"(x)のよ

うな直接の呼び出しをしようとしないことを条件とする。)

今のところ、.Call呼び出しへのすべての引数は、NAMEDが 2に設定されており、そのためユーザは引数は変更の前に複製を行う必要があると仮定しなければならない。

5.10 インタフェース関数.Callと.External

この節では、R/Cのインタフェースの詳細を議論する。

これら 2つのインタフェースはほぼ同じ機能性を持つ。.Callは Sバージョン 4の同じ名前のインタフェースに基づいており、.Externalは.Internalに基づいている。.Externalは

より複雑であるが、可変個の引数を許している。

5.10.1 .Callの呼び出し

まず Rdefines.hマクロを使い、有限長の畳み込みの例を.Callを使うように変換しよう。Rでの呼び出し関数は次のようになる。

Page 127: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 121

conv <- function(a, b) .Call("convolve2", a, b)

これはほとんどこれ以上簡単にならないが、以下で見るようにすべての型チェックは Cに移されなければならならず、次のようになる。

#include <R.h>

#include <Rdefines.h>

SEXP convolve2(SEXP a, SEXP b)

{

R_len_t i, j, na, nb, nab;

double *xa, *xb, *xab;

SEXP ab;

PROTECT(a = AS_NUMERIC(a));

PROTECT(b = AS_NUMERIC(b));

na = LENGTH(a); nb = LENGTH(b); nab = na + nb - 1;

PROTECT(ab = NEW_NUMERIC(nab));

xa = NUMERIC_POINTER(a); xb = NUMERIC_POINTER(b);

xab = NUMERIC_POINTER(ab);

for(i = 0; i < nab; i++) xab[i] = 0.0;

for(i = 0; i < na; i++)

for(j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j];

UNPROTECT(3);

return(ab);

}

さて、次は Rinternals.h形式のバージョンである。Cコードだけが変化する。

#include <R.h>

#include <Rinternals.h>

SEXP convolve2(SEXP a, SEXP b)

{

R_len_t i, j, na, nb, nab;

double *xa, *xb, *xab;

SEXP ab;

PROTECT(a = coerceVector(a, REALSXP));

PROTECT(b = coerceVector(b, REALSXP));

na = length(a); nb = length(b); nab = na + nb - 1;

PROTECT(ab = allocVector(REALSXP, nab));

xa = REAL(a); xb = REAL(b);

xab = REAL(ab);

for(i = 0; i < nab; i++) xab[i] = 0.0;

for(i = 0; i < na; i++)

for(j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j];

UNPROTECT(3);

return(ab);

}

Page 128: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 122

これは正確に同じ方法で呼び出される。

5.10.2 .Externalの呼び出し

.Externalを説明するのに同じ例を使うことができる。.Callを.Externalに置き換える点だ

けRのコードは変化する。

conv <- function(a, b) .External("convolveE", a, b)

しかし主要な変化はCコードへどのように引数が渡されるかということであり、今回は 1つのSEXPとして渡される。Cコードの唯一の変化はどのように引数を扱うかということである。

#include <R.h>

#include <Rinternals.h>

SEXP convolveE(SEXP args)

{

R_len_t i, j, na, nb, nab;

double *xa, *xb, *xab;

SEXP a, b, ab;

PROTECT(a = coerceVector(CADR(args), REALSXP));

PROTECT(b = coerceVector(CADDR(args), REALSXP));

...

}

もう一度、インタフェースの R側で、引数は既に使用されているオブジェクトであるため、引数を保護する必要はない。以下のマクロ

first = CADR(args);

second = CADDR(args);

third = CADDDR(args);

fourth = CAD4R(args);

は最初の 4つの引数にアクセスする簡便な方法を与える。より一般的には、CDRと CARマクロ

は以下のように使える。

args = CDR(args); a = CAR(args);

args = CDR(args); b = CAR(args);

これははっきりと無制限の引数を取り出すことを可能にしている (一方で、.Callには 65個という少なくないとは言え、制限がある)。

length(args)は供給される引数の数を与える (その中の最初は無視される)ので、より有効な.Externalインタフェースは可変個数の引数を伴う呼び出しを扱う簡単な方法を提供す

る。実際の引数に与えられた名前 (‘tags’)を知る必要があるかもしれない。それは TAGマクロ

と、以下の例のようなものを使うことによってできる。以下の例では、名前ともし引数がベ

クトル型であれば引数の最初の値を表示する。

Page 129: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 123

SEXP showArgs(SEXP args)

{

args = CDR(args); /* skip ’name’ */

for(int i = 0; args != R_NilValue; i++, args = CDR(args)) {

const char *name =

isNull(TAG(args)) ? "" : CHAR(PRINTNAME(TAG(args)));

SEXP el = CAR(args);

if (length(el) == 0) {

Rprintf("[%d] ’%s’ R type, length 0\n", i+1, name);

continue;

}

switch(TYPEOF(el)) {

case REALSXP:

Rprintf("[%d] ’%s’ %f\n", i+1, name, REAL(el)[0]);

break;

case LGLSXP:

case INTSXP:

Rprintf("[%d] ’%s’ %d\n", i+1, name, INTEGER(el)[0]);

break;

case CPLXSXP:

{

Rcomplex cpl = COMPLEX(el)[0];

Rprintf("[%d] ’%s’ %f + %fi\n", i+1, name, cpl.r, cpl.i);

}

break;

case STRSXP:

Rprintf("[%d] ’%s’ %s\n", i+1, name,

CHAR(STRING_ELT(el, 0)));

break;

default:

Rprintf("[%d] ’%s’ R type\n", i+1, name);

}

}

return(R_NilValue);

}

これはラッパ関数によって呼び出される。

showArgs <- function(...) invisible(.External("showArgs", ...))

このスタイルのプログラミングは便利であるが、必ずしも必要ではないことに注意しよう。以

下のような別のスタイルがあるからである。

showArgs1 <- function(...) invisible(.Call("showArgs1", list(...)))

(とてもよく似た)Cコードがスクリプトにある。

5.10.3 欠損値と特殊値

.C呼び出しがエラーチェックでするいることの 1つ (NAOKが真でない限り)に、欠損値 (NA)とIEEE特殊値 (Inf, -Inf and NaN)をチェックすることと、それが見つかったときにエラーを与えることがある。.Callインタフェースを用いると、これらはコードに渡される。この例で

Page 130: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 124

は、IEC60559算術が特殊値を正しく扱うので、特殊値には問題はない。現在の実装では、NA

が NaNの一種であることから、NAに対しても当てはまり問題はないが、そのような詳細に頼

ることは賢明ではない。従って R.hによってインクルードされている R_exts/Arith.hに定義

されたマクロを利用して、NAを扱うようコードを書き直すことにする。

コードの変更点は convolve2あるいは convolveEの任意のバージョンで同じである。

...

for(i = 0; i < na; i++)

for(j = 0; j < nb; j++)

if(ISNA(xa[i]) || ISNA(xb[j]) || ISNA(xab[i + j]))

xab[i + j] = NA_REAL;

else

xab[i + j] += xa[i] * xb[j];

...

ISNAマクロと同様のマクロ ISNAN(NaNあるいは NAをチェックする)と R_FINITE(NAとすべての特殊値に対して偽となる)は double型の数値に対してのみ適用されることに注意。整数、

論理値と文字列の欠損は、定数 NA_INTEGER、NA_LOGICALと NA_STRINGに等しいかどうかで

検査できる。これらと NA_REALはRベクトルの要素を NAに設定するために使うことができる。

定数R_NaN、R_PosInfとR_NegInfはdoubleを特殊値に設定するために使うことができる。

5.11 CからRの式を評価する

我々が使う主な関数は次のものである。

SEXP eval(SEXP expr, SEXP rho);

これは解釈される R コード eval(expr, envir = rho)と同等である。しかし findVar、

defineVarと findFun(関数に探索を制限する)を使うこともできる。

これがどのように適用されるかを見るために、以下のように使われる、式に対して単純化

された lapplyの内部版を示す。

a <- list(a = 1:5, b = rnorm(10), test = runif(100))

.Call("lapply", a, quote(sum(x)), new.env())

上のコードはに以下の Cコードと一体となっている。

Page 131: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 125

SEXP lapply(SEXP list, SEXP expr, SEXP rho)

{

R_len_t i, n = length(list);

SEXP ans;

if(!isNewList(list)) error("’list’ must be a list");

if(!isEnvironment(rho)) error("’rho’ should be an environment");

PROTECT(ans = allocVector(VECSXP, n));

for(i = 0; i < n; i++) {

defineVar(install("x"), VECTOR_ELT(list, i), rho);

SET_VECTOR_ELT(ans, i, eval(expr, rho));

}

setAttrib(ans, R_NamesSymbol, getAttrib(list, R_NamesSymbol));

UNPROTECT(1);

return(ans);

}

もし式ではなく関数を渡すことができれば、より lapplyに近くなるであろう。これを行

う 1つの方法は、次の例のようにRのインタプリタコードを通すことであるが、(もしいくらか曖昧であれば)Cコードで行うこともできる。以下は src/main/optimize.cのコードに基

づいている。

SEXP lapply2(SEXP list, SEXP fn, SEXP rho)

{

R_len_t i, n = length(list);

SEXP R_fcall, ans;

if(!isNewList(list)) error("’list’ must be a list");

if(!isFunction(fn)) error("’fn’ must be a function");

if(!isEnvironment(rho)) error("’rho’ should be an environment");

PROTECT(R_fcall = lang2(fn, R_NilValue));

PROTECT(ans = allocVector(VECSXP, n));

for(i = 0; i < n; i++) {

SETCADR(R_fcall, VECTOR_ELT(list, i));

SET_VECTOR_ELT(ans, i, eval(R_fcall, rho));

}

setAttrib(ans, R_NamesSymbol, getAttrib(list, R_NamesSymbol));

UNPROTECT(2);

return(ans);

}

上のコードは以下のコードで利用される。

.Call("lapply2", a, sum, new.env())

関数 lang2は 2要素の実行可能なペアリストを生成するが、LISP風言語の知識がある人にだけは明らかであろう。

C コードでの R 呼び出しの構築と、評価の包括的な例として、src/main/print.cの

printAttributesの一片を考えよう。

/* R_printの構造に基づいた

Page 132: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 126

print(CAR(a), digits=digits)、

次に eval(call, env)への呼び出しを構築する必要がある。

この種の定型書式は do_callを参照せよ。

*/

SEXP s, t;

PROTECT(t = s = allocList(3));

SET_TYPEOF(s, LANGSXP);

SETCAR(t, install("print")); t = CDR(t);

SETCAR(t, CAR(a)); t = CDR(t);

SETCAR(t, ScalarInteger(digits));

SET_TAG(t, install("digits"));

eval(s, env);

UNPROTECT(1);

現時点で CAR(a)は印字されるRオブジェクトであり、現在の属性である。3つの段階がある:長さ 3のペアリストとして呼び出しが構築され、リストが埋められ、ペアリストで表された式が評価される。

ペアリストは総称的ベクトルリストとはかなり異なり、Rで唯一ユーザが見れるリストの形式である。ペアリストはアイテム (CAR(t)でアクセスされる)と名前あるいはタグ (SET_TAGで設定される)からなる連結リスト (CDR(t)で次のエントリを求める)である。この呼び出しでは、3つのアイテムと 1つのシンボル (呼ばれる関数を指す)、そして 2つの引数の値があり、最初は名前がなく、2番目には名前がつけられている。LANGSXP型に設定することは、こ

れを評価することができる呼び出しにすることである。

5.11.1 ゼロ点を見つける

この項では、Becker, Chambers & Wilks (1988, pp.~205–10)の例にある一変数関数のゼロ点を見つけることを再度行う。Rのコードと例は以下の通りである。

zero <- function(f, guesses, tol = 1e-7) {

f.check <- function(x) {

x <- f(x)

if(!is.numeric(x)) stop("Need a numeric result")

as.double(x)

}

.Call("zero", body(f.check), as.double(guesses), as.double(tol),

new.env())

}

cube1 <- function(x) (x^2 + 1) * (x - 1.5)

zero(cube1, c(0, 5))

ここで今回はRコードで強制変換とエラーチェックを行っている。Cコードは次のようになる。

Page 133: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 127

SEXP mkans(double x)

{

SEXP ans;

PROTECT(ans = allocVector(REALSXP, 1));

REAL(ans)[0] = x;

UNPROTECT(1);

return ans;

}

double feval(double x, SEXP f, SEXP rho)

{

defineVar(install("x"), mkans(x), rho);

return(REAL(eval(f, rho))[0]);

}

SEXP zero(SEXP f, SEXP guesses, SEXP stol, SEXP rho)

{

double x0 = REAL(guesses)[0], x1 = REAL(guesses)[1],

tol = REAL(stol)[0];

double f0, f1, fc, xc;

if(tol <= 0.0) error("non-positive tol value");

f0 = feval(x0, f, rho); f1 = feval(x1, f, rho);

if(f0 == 0.0) return mkans(x0);

if(f1 == 0.0) return mkans(x1);

if(f0*f1 > 0.0) error("x[0] and x[1] have the same sign");

for(;;) {

xc = 0.5*(x0+x1);

if(fabs(x0-x1) < tol) return mkans(xc);

fc = feval(xc, f, rho);

if(fc == 0) return mkans(xc);

if(f0*fc > 0.0) {

x0 = xc; f0 = fc;

} else {

x1 = xc; f1 = fc;

}

}

}

5.11.2 数値微分の計算

評価と.Externalの使い方を説明するために長い例 (Saikat DebRoyによる)を使う。これは数値微分を計算し、Rのインタプリタコードで効果的にできるだろうが、大規模なCの計算の一部で必要とされるであろう。

Rインタプリタ版と例は以下の通りである。

Page 134: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 128

numeric.deriv <- function(expr, theta, rho=sys.frame(sys.parent()))

{

eps <- sqrt(.Machine$double.eps)

ans <- eval(substitute(expr), rho)

grad <- matrix(, length(ans), length(theta),

dimnames=list(NULL, theta))

for (i in seq_along(theta)) {

old <- get(theta[i], envir=rho)

delta <- eps * max(1, abs(old))

assign(theta[i], old+delta, envir=rho)

ans1 <- eval(substitute(expr), rho)

assign(theta[i], old, envir=rho)

grad[, i] <- (ans1 - ans)/delta

}

attr(ans, "gradient") <- grad

ans

}

omega <- 1:5; x <- 1; y <- 2

numeric.deriv(sin(omega*x*y), c("x", "y"))

ここで exprは式、thetaは文字ベクトルの変数名、rhoは使われる環境を表す。

コンパイル済みのバージョンに対しては、Rからの呼び出しは次のようになるだろう。

.External("numeric_deriv", expr, theta, rho)

使用例は以下の通り。

.External("numeric_deriv", quote(sin(omega*x*y)),

c("x", "y"), .GlobalEnv)

式を引用符で囲う必要性は、呼び出した側で評価されるのを止めるためであることに注意。

以下はこれからセクションごとに説明する完全な Cコードである。

#include <R.h> /* for DOUBLE_EPS */

#include <Rinternals.h>

SEXP numeric_deriv(SEXP args)

{

SEXP theta, expr, rho, ans, ans1, gradient, par, dimnames;

double tt, xx, delta, eps = sqrt(DOUBLE_EPS), *rgr, *rans;

R_len_t start, i, j;

expr = CADR(args);

if(!isString(theta = CADDR(args)))

error("theta should be of type character");

if(!isEnvironment(rho = CADDDR(args)))

error("rho should be an environment");

PROTECT(ans = coerceVector(eval(expr, rho), REALSXP));

PROTECT(gradient = allocMatrix(REALSXP, LENGTH(ans), LENGTH(theta)));

rgr = REAL(gradient); rans = REAL(ans);

Page 135: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 129

for(i = 0, start = 0; i < LENGTH(theta); i++, start += LENGTH(ans)) {

PROTECT(par = findVar(install(CHAR(STRING_ELT(theta, i))), rho));

tt = REAL(par)[0];

xx = fabs(tt);

delta = (xx < 1) ? eps : xx*eps;

REAL(par)[0] += delta;

PROTECT(ans1 = coerceVector(eval(expr, rho), REALSXP));

for(j = 0; j < LENGTH(ans); j++)

rgr[j + start] = (REAL(ans1)[j] - rans[j])/delta;

REAL(par)[0] = tt;

UNPROTECT(2); /* par, ans1 */

}

PROTECT(dimnames = allocVector(VECSXP, 2));

SET_VECTOR_ELT(dimnames, 1, theta);

dimnamesgets(gradient, dimnames);

setAttrib(ans, install("gradient"), gradient);

UNPROTECT(3); /* ans gradient dimnames */

return ans;

}

引数を扱うためのコードは以下のものである。

expr = CADR(args);

if(!isString(theta = CADDR(args)))

error("theta should be of type character");

if(!isEnvironment(rho = CADDDR(args)))

error("rho should be an environment");

thetaと rhoの型が正しいかは検査するが、exprの型は検査していないことに注意。これは

evalが EXPRSXP以外のRオブジェクトの多くの型を扱うことができるからである。我々が行える役立つ強制変換はなく、もし引数が正しいモードでなければ、エラーメッセージと共に

中断する。

コードの最初の段階は環境 rhoで式を評価することで、次のようにする。

PROTECT(ans = coerceVector(eval(expr, rho), REALSXP));

そして、数値微分のための空間を以下のようにして確保する。

PROTECT(gradient = allocMatrix(REALSXP, LENGTH(ans), LENGTH(theta)));

allocMatrixへの最初の引数は行列の SEXPTYPEを与える: ここでは行列を REALSXPにした

い。他の 2つの引数は行と列の数である。

for(i = 0, start = 0; i < LENGTH(theta); i++, start += LENGTH(ans)) {

PROTECT(par = findVar(install(CHAR(STRING_ELT(theta, i))), rho));

ここでループに入っている。各変数ごとにループを行う。forループ中では、最初に STRSXP

thetaの i番目の要素に対応するシンボルを作成する。ここで STRING_ELT(theta, i)が

STRSXP thetaの i番目の要素にアクセスする。マクロ CHAR()はその実際の文字表現 7を取り

出す: それはポインタを返す。次に名前を設定し、その値を見つけるために findVarを使う。

7 なぜこれが必要ないかもしれないかについては、see Section 5.15 [文字エンコーディングの問題], page 134を参照せよ。

Page 136: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 130

tt = REAL(par)[0];

xx = fabs(tt);

delta = (xx < 1) ? eps : xx*eps;

REAL(par)[0] += delta;

PROTECT(ans1 = coerceVector(eval(expr, rho), REALSXP));

最初にパラメータの実数値を取り出し、数値微分を近似するために使われる増分 deltaを計

算する。そして deltaによって par(環境 rhoにある)に保存された値を変更し、環境 rhoで再

度 exprを評価する。ここでは本来のRのメモリ位置を直接扱っているので、Rは変更されたパラメータ値に対して評価をする。

for(j = 0; j < LENGTH(ans); j++)

rgr[j + start] = (REAL(ans1)[j] - rans[j])/delta;

REAL(par)[0] = tt;

UNPROTECT(2);

}

さて、勾配行列の i番目の列を計算する。どのようにそれがアクセスされているかに注意: Rは (FORTRANのように)列ごとに行列を記憶している。

PROTECT(dimnames = allocVector(VECSXP, 2));

SET_VECTOR_ELT(dimnames, 1, theta);

dimnamesgets(gradient, dimnames);

setAttrib(ans, install("gradient"), gradient);

UNPROTECT(3);

return ans;

}

最初に勾配行列に列名を付けている。これは最初の要素である行名を NULL(既定値)、2番目の要素の列名に thetaと設定するリストを確保することによって行われている。次にこのリ

ストはシンボル R_DimNamesSymbolを持つ属性として指定される。最後に勾配行列は ansと

いう勾配属性として設定し、残った保護された位置の保護解除し、答え ansを返す。

5.12 CからRのコードを構文解析する

Rの拡張機能がユーザからのR式を受け入れて、それを評価したいと仮定する。前の項では評価については取り上げていたが、式はテキストとして入力され、最初に構文解析される必

要があった。Rの構文解析インタフェースのごく一部はヘッダファイル R_ext/Parse.h8で

宣言されている。

使用例は Rソースツリーに含められた (例)Windowsパッケージ windlgsに見ることができる。最も重要な部分は次のものである。

8 現在のインタフェースを表示することだけを保証している: これは変わりやすい。

Page 137: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 131

#include <R.h>

#include <Rinternals.h>

#include <R_ext/Parse.h>

SEXP menu_ttest3()

{

char cmd[256];

SEXP cmdSexp, cmdexpr, ans = R_NilValue;

ParseStatus status;

...

if(done == 1) {

PROTECT(cmdSexp = allocVector(STRSXP, 1));

SET_STRING_ELT(cmdSexp, 0, mkChar(cmd));

cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));

if (status != PARSE_OK) {

UNPROTECT(2);

error("invalid call %s", cmd);

}

/* EXPSEXPが length > 1となるので、ここではループが必要となる */

for(R_len_t i = 0; i < length(cmdexpr); i++)

ans = eval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv);

UNPROTECT(2);

}

return ans;

}

テキストの 1行がR式の 1行以上を生じさせるかもしれないことに注意。

R_ParseVectorは、Rレベルで parse(text=)を実装するために基本的に使われるコード

である。最初の引数は文字ベクトル (textに対応する)であり、2番目の引数は構文解析する式の最大値である (nに対応する)。3番目の引数は列挙型の変数へのポインタであり、PARSE_OK

以外のすべての値をエラーとみなすのが普通である (parseがするように)。返される可能性がある他の値は PARSE_INCOMPLETEと PARSE_ERRORであり、どちらの場合も値が R_NilValue

で返される。4番目の引数は srcfileオブジェクト、あるいは (上の例にあるように)R NULL

オブジェクトである。前者の場合、srcref属性が結果につけられる。結果には式と同じ長さ

の srcrefオブジェクトのリストが含まれていて、それが元の書式で結果をエコーすることを

可能にしている。

5.12.1 ソース参照へのアクセス

Rの評価器がコードを評価するときに、構文解析器によって加えられたソース参照はRの評価器によって記録される。2つの関数は Cコードを実行するデバッガにこれらを利用可能にしている:

SEXP R_GetCurrentSrcref(int skip);

この関数は R_Srcrefとソース参照情報を含むエントリに対する現在の評価スタックを検

査する。skip引数は srcrefオブジェクトの SEXPを返す前に、スタックの一番上から数えて、

いくつの省略するソース参照があるかを伝える。もし skip < 0であれば、abs(skip)の場所

がスタックの底からカウントアップされる。もし参照が少なすぎる、あるいはソース参照が

ないことが分かれば、NULLが返される。

Page 138: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 132

SEXP R_GetSrcFilename(SEXP srcref);

この関数は表示のためにソース参照からファイル名を抽出し、ファイル名を含む長さ 1の文字ベクトルを返す。もし名前が見つからなければ、""が返される。

5.13 外部ポインタと弱参照

SEXPTYPEの EXTPTRSXPと WEAKREFSXPはRレベルでも出会うことがあるが、これらはCコードで作られている。

外部ポインタ SEXPは ‘handles’のようなCの構造体への参照を扱うために意図されたものであり、例えばパッケージ RODBC (http://CRAN.R-project.org/package=RODBC)ではこの目的のために使われている。Rオブジェクトがコピーされるときに、外部ポインタオブジェクトが複製されないという点において、これらのコピーの動作は普通ではない。(このため、外部ポインタは通常の動作をするオブジェクトの一部としてのみ利用するべきである。例

えばリストの属性、あるいは要素である。)

外部ポインタは

SEXP R_MakeExternalPtr(void *p, SEXP tag, SEXP prot);

によって作成される。ここで pはポインタ (そして、そのためこれは持ち運びできる状態で関数ポインタにはなり得ない)であり、tagと protは外部ポインタオブジェクトの寿命までは存

在する (ガーベージコレクションから保護される)、普通の Rオブジェクトへの参照である。便利な規則は、型判別のフォームのために tagフィールドを使い、メモリが Rヒープから確保されている場合に、外部ポインタが指し示すメモリを保護するために protフィールドを使

うことである。tagと protは R_NilValueになることがあり、よくそうなる。

外部ポインタの要素へのアクセスと設定は、以下の関数を通して行うことができる。

void *R_ExternalPtrAddr(SEXP s);

SEXP R_ExternalPtrTag(SEXP s);

SEXP R_ExternalPtrProtected(SEXP s);

void R_ClearExternalPtr(SEXP s);

void R_SetExternalPtrAddr(SEXP s, void *p);

void R_SetExternalPtrTag(SEXP s, SEXP tag);

void R_SetExternalPtrProtected(SEXP s, SEXP p);

ポインタをクリアすることは、その値を Cの NULLポインタにすることである。

外部ポインタオブジェクトは finalizer という、オブジェクトがガーベージコレクションされたときに動作するコード片を持っていることがある。これはRのコードあるいはCのコードであり、それぞれに様々なインタフェースがある。

void R_RegisterFinalizerEx(SEXP s, SEXP fun, Rboolean onexit);

typedef void (*R_CFinalizer_t)(SEXP);

void R_RegisterCFinalizerEx(SEXP s, R_CFinalizer_t fun, Rboolean onexit);

funに示される Rの関数は、ファイナライズされるオブジェクトを単一の引数にとる関数でなければならない。Rはシャットダウンするときにガーベージコレクションは行わない。拡張された形式の onexit引数は、通常のRセッションのシャットダウンの間に、ファイナライザの実行することを求めるために使うことができる。ファイナライズの処理でポインタをクリ

アするのは、よい実践であるということが示唆されている。

外部ポインタとやりとりするためのRレベルでの唯一の関数は、ファイナライザの設定のために使うことができる reg.finalizerである。

Page 139: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 133

外部ポインタが saveされ、そしてリロードされるようにすることはおそらく良い考えで

はないが、もしこれが起こると、ポインタは Cの NULLポインタに設定されるであろう。

弱参照はプログラマに、一旦エンティティが到達不可能になると、エンティティのガーベー

ジコレクションを防ぐことなく、エンティティの情報を維持することを可能にする。

弱参照はキーと値を持つ。値が到達可能であるとは、直接、あるいは到達可能なキーへの

弱参照を通して値に到達可能であることをいう。一旦値がガーベージコレクションの間に到

達不可能であると判断されたら、キーと値は R_NilValueに設定され、ファイナライザはガー

ベージコレクションの後半で実行される。

弱参照のオブジェクトは次の関数のいずれか 1つにより作成される。

SEXP R_MakeWeakRef(SEXP key, SEXP val, SEXP fin, Rboolean onexit);

SEXP R_MakeWeakRefC(SEXP key, SEXP val, R_CFinalizer_t fin,

Rboolean onexit);

ここで R、あるいは Cのファイナライザは外部ポインタオブジェクト (その終了処理インタフェースは弱参照を通して実装されている)と同様の方法で指定される。

その部分には以下の関数を通してアクセスすることができる。

SEXP R_WeakRefKey(SEXP w);

SEXP R_WeakRefValue(SEXP w);

void R_RunWeakRefFinalizer(SEXP w);

弱参照のちょっとした例はwww.stat.uiowa.edu/~luke/R/references/weakfinex.html

(http://www.stat.uiowa.edu/~luke/R/references/weakfinex.html)に見ることができるが、これは今ではより直接的にできる、外部ポインタにファイナライザを追加するために

使われている。これを書いている時点で、CRANあるいはBioconductorのパッケージで弱参照を用いているものはない。

5.13.1 例

パッケージ RODBC (http://CRAN.R-project.org/package=RODBC) はデータベースへ接続するチャネルを保持するために外部ポインタを利用している。一度に複数の接続が開く

ことがある。それぞれの接続に対するステータス情報は、RODBC チャネルの一部として("handle_ptr"属性として)、外部ポインタを通して返される Cの構造体 (下のコード引用では this_handleによって指し示される)に格納されている。以下のコードで外部ポインタは作成される。

SEXP ans, ptr;

PROTECT(ans = allocVector(INTSXP, 1));

ptr = R_MakeExternalPtr(thisHandle, install("RODBC_channel"), R_NilValue);

PROTECT(ptr);

R_RegisterCFinalizerEx(ptr, chanFinalizer, TRUE);

...

/* チャンネル番号 */

INTEGER(ans)[0] = nChannels;

/* と属性として接続の文字列を返す */

setAttrib(ans, install("connection.string"), constr);

setAttrib(ans, install("handle_ptr"), ptr);

UNPROTECT(3);

return ans;

Page 140: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 134

外部ポインタの使用と、ファイナライザの使用を識別するために与えられるシンボルに注意

せよ。ファイナライザを登録するときの最後の引数が TRUEであるので、ファイナライザはRセッションの最後に動作する (クラッシュしない限り)。これはデータベースへの接続の終了とクリーンアップに使われる。ファイナライザのコードは単に次のようになる。

static void chanFinalizer(SEXP ptr)

{

if(!R_ExternalPtrAddr(ptr)) return;

inRODBCClose(R_ExternalPtrAddr(ptr));

R_ClearExternalPtr(ptr); /* not really needed */

}

ポインタをクリアし、NULLポインタであるかを検査することは、既に閉じられたチャネルを

閉じようとするあらゆる可能性を回避する。

もはや接続は役に立たないということで、純粋にファイナライザを接続を閉じ、破棄する

ために使えるようにする場合には、Rの接続は外部ポインタの別の使用例を提供する。

5.14 ベクトルアクセサ関数

REAL、INTEGERや VECTOR_ELTのようなベクトルアクセサは Rの拡張で使われるときは、関数である。(Rのソースコードで使われるとき、SET_STRING_ELTと SET_VECTOR_ELTは常に

関数であることは別として、効率のために、これらはマクロとなる。)

アクセサ関数は、それらが適切な SEXPの型で使われているかを検査する。

もし効率性が重要であれば、Rinternals.hをインクルードする前に ‘USE_RINTERNALS’を定義することによってアクセサのマクロ版を得ることができる。もしそのようにする

必要があると分かったら、アクセサが適切に使われていることを厳格にテストするため、

‘USE_RINTERNALS’が定義されなくてもコードがコンパイルできることを検査していただきたい。

5.15 文字エンコーディングの問題

CHARSXPは既知のエンコーディング (Latin-1あるいは UTF-8)に由来するものとして特徴付けることができる。これは主に人間が読める出力を意図しており、大部分のパッケージは、そ

のような CHARSXPをまとめて扱うことができる。しかし、もしそれらがCレベルの文字あるいは出力として解釈される必要があるのであれば、現在のロケールのエンコーディングに変

換されることを保証するのが普通は正しいであろう: これは CHARではなく translateCharに

よって、CHARSXPのデータにアクセスすることによってできる。もし再エンコーディングが必

要であれば、vmaxsetが使われていない限り、これは.Call/.Externalの呼び出しの終わりまで続く R_allocでメモリを確保する。

UTF-8に変換する同様の関数 translateCharUTF8がある: これは忠実な変換がほぼいつでも可能という利点を持っている (それに対し、少数の言語では、現在のロケールのエンコーディングがUTF-8である場合を除き、現在のロケールのエンコーディングで表現することができる)。

以下のものによる、CHARSXPsに記されたエンコーディングへの公開インタフェースがある。

typedef enum {CE_NATIVE, CE_UTF8, CE_LATIN1, CE_SYMBOL, CE_ANY} cetype_t;

cetype_t getCharCE(SEXP);

SEXP mkCharCE(const char *, cetype_t);

Page 141: Rの拡張を書く (R 2.15.2)

Chapter 5: システムと他言語間のインタフェース 135

CE_UTF8と CE_LATIN1だけが CHARSXPsに記されており (そのため Rf_getCharCEは最初の 3つのうち 1つだけを返す)、これらは非 ASCII文字列でのみ使われなければならない。値 CE_

SYMBOLは Adobeシンボルエンコーディングであることを示すために内部で利用される。値CE_ANYは文字列が再エンコーディングを必要としないことを示すために使われる – これはASCIIであると分かっている文字列に対し使用される。また、これは文字列が一連のバイト列

として扱われるという意図した入力パラメータとして使うことができる。(許容される入力の長さについては、mkCharの下にあるコメントを見よ。)

関数

const char *reEnc(const char *x, cetype_t ce_in, cetype_t ce_out,

int subst);

は文字列の再エンコードに使うことができる: translateCharのように、関数は R_allocに

よって確保された文字列を返す。これは CE_SYMBOLから CE_UTF8へ変換することができるが、

逆はできない。引数 substは変換不可能な文字あるいは不適切な入力をどうするかというこ

とを制御する: これはバイト単位で処理され、1であれば 16進法の形式<a0>で出力すること

を示し、2であれば.で置換され、他の値ではそのバイトでは何も出力を生成しない。

与えられた長さで特徴付けられた文字列を生成する

SEXP mkCharLenCE(const char *, size_t, cetype_t);

という関数もある。

Page 142: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 136

6 The R API: Cコードのエントリポイント

Cコードから呼ぶことができるRの実行形式/DLLには数多くのエントリポイントがある (そして FORTRANコードから呼ぶことができるものもある)。ここで文書化されているものだけは、かなりの予告を伴った場合にだけ変更されるほど十分に安定したものである。

これらを使うための推奨される手続きは次のようにして、Cコードにヘッダファイル R.h

をインクルードすることである。

#include <R.h>

これはディレクトリ R_INCLUDE_DIR/R_extから、他のいくつかのヘッダファイルをインク

ルードすることになる。また、そこには他のインクルードされるヘッダファイルもあるが、そ

れらが含む多くの特徴は文書化されておらず、不安定なものであるとみなすべきである。

別の方法は Sからコードを移植するときに役立つかもしれないヘッダファイル S.hをイン

クルードすることである。これは R.hよりもかなりインクルードが少なく、追加の互換性定

義を持っている (例えば、Sからの S_complex型)。

Sとの互換性のために使われる定義はときどき矛盾を起こすことがあり (特にWindowsヘッダと)、既知の問題のある定義は STRICT_R_HEADERSを定義することによって削除するこ

とができる。

R.hによってインクルードされるものも含め、これらのヘッダファイルの大部分は、C++コードから使うことができる。extern "C"宣言の内部でインクルードされる必要があるもの

もあり、分かりやすくするために、すべてのRヘッダファイルでこれが勧められている。

Note: Rはユーザのコードでクラッシュするのを避けるために、多くの外部名を再配置するため、これらのエントリポイントを使うときに、適切なヘッダファイ

ルをインクルードすることは必須である。

この再配置は問題を起こす可能性があり 1、R_NO_REMAPを定義することと、Rinternals.h

と R_ext/Error.hからの使用されているすべての関数名の前に ‘Rf_’をつけることで再配置は除外することができる。

エントリポイントは次のように分類することができる。

API このマニュアルで文書化され、インストールされたヘッダファイルに宣言されて

いるエントリポイント。これらは配布されたパッケージで使うことができ、廃止

後にのみ変更される。

public すべての Rプラットフォームでエクスポートされているが、文書化されておらず、注意なく変更されがちな、インストール済みヘッダファイルで宣言されたエ

ントリポイント。

private Rのビルド時に使用され、すべてのRプラットフォームでエクスポートされているが、インストール済みヘッダファイルで宣言されていないエントリポイント。

配布するコードで使用してはならない。

hidden エクスポートが可能 (共有ライブラリとしてRを使ったときの、Windowsといくつかの最新のUnix系コンパイラ/ローダ)でない場合のエントリポイント。

1 error、length、vectorと warningの再定義することが既知の問題である

Page 143: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 137

6.1 メモリ割り当て

Cプログラマが利用可能なメモリ割り当ては 2種類あり、一つは Rが後片付けを管理し、他方はユーザが完全な制御権 (と責任)を持つ。

6.1.1 一時的な記憶領域の割り当て

ここではRが.Cへの呼び出しの終わりに、メモリを再利用する。次のものを使用する。

char *R_alloc(size_t n, int size)

これは sizeバイト毎に n単位を確保する。典型的な使い方 (パッケージ statsから)は

x = (int *) R_alloc(nrows(merge)+2, sizeof(int));

(size_tは R_allocを定義したヘッダをインクルードしている stddef.hで定義されている。)

(Sの古いバージョンとの互換性のために)確保されたメモリをゼロに設定する S_allocと

いうよく似た呼び出しもある。

char *S_alloc(long n, int size)

そして

char *S_realloc(char *p, long new, long old, int size)

は確保したサイズを oldから new単位に変え、追加された単位をゼロに設定する。

Sの現在のバージョンとの互換性のため、ヘッダ S.hは以下に相当するラッパマクロ (のみ)を定義している。

type* Salloc(long n, int type)

type* Srealloc(char *p, long new, long old, int type)

このメモリはヒープから取得され、.C、.Callあるいは.Externalの呼び出しの終わりに

解放される。vmaxgetへの呼び出しで現在のメモリの位置を記録し、vmaxsetへの呼び出しで

順に確保されたメモリをクリアすることで、ユーザもメモリを管理することができる。これ

は熟練者に対してのみ推奨される。

このメモリはエラーあるいはユーザ割り込みによって開放されることに注意 (許可されている場合: see Section 6.12 [割り込み許可], page 149)。

nは longであるが、Rの内部の割り当てメカニズムによって制限が課されていることに注意。これらは nに対する現在の制限が 16Gb以下の 64ビットのシステムでのみ作用する。

6.1.2 ユーザに制御されたメモリ

メモリ割り当ての別の方法は、Rのエラー処理を提供するインタフェースである、mallocへ

のインタフェースである。このメモリはユーザに開放されるまで存在し、Rのワークスペースに対して確保したメモリに追加される。

インタフェース関数は

type* Calloc(size_t n, type)

type* Realloc(any *p, size_t n, type)

void Free(any *p)

であり、calloc、reallocと freeの類似物を提供する。もし割り当ての最中にエラーがあれ

ば、Rによって処理されるので、もしこれらのルーチンから戻ってこれば、メモリは上手く確保された、あるいは開放されたということになる。Freeはポインタ pを NULLに設定する。

(すべての Sのバージョンでそうするというわけではない。)

Page 144: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 138

ユーザは、メモリがエラーやユーザ割り込みを含めて、もはやメモリが必要なくなったと

きに、このメモリを Freeする手配をしなければならない。これは呼び出しているRの関数中の on.exitアクションから行うのが最も都合よくできる – 例として pwilcoxを参照せよ。

Calloc/Reallocによって割り当てられたメモリは、mallocによって使われるものと同じ

プールから来たものと仮定してはならない: 特に freeあるいは strdupを

これらのエントリポイントは、もし STRICT_R_HEADERSが定義されているのであれば、R_

という接頭辞をつける必要がある。

6.2 エラー処理

基本的なエラー処理ルーチンはRコードの stop、warningと同等であり、同じインタフェー

スを使用している。

void error(const char * format, ...);

void warning(const char * format, ...);

これらは printfの呼び出しと同じ呼び出し順序を持つが、最も単純な場合はエラーメッセー

ジを与える単一の文字列引数で呼び出すことができる。(もし文字列が ‘%’を含むのであれば、これをしてはならない。さもなければ書式として解釈される恐れがある。)

もし STRICT_R_HEADERSが定義されていなければ、次の呼び出し形式を使った Sと互換性のあるインタフェースがある。

PROBLEM ...... ERROR

MESSAGE ...... WARN

PROBLEM ...... RECOVER(NULL_ENTRY)

MESSAGE ...... WARNING(NULL_ENTRY)

最後の二つの形式はすべての Sのバージョンで利用可能である。ここで、‘......’は printf

への引数の集合であるので、文字列あるいはコンマ区切りの引数が続く書式文字列をとるこ

とができる。

6.2.1 FORTRANからのエラー処理

FORTRANコードからの errorと warningへの呼び出しには 2つのインタフェース関数が提供されており、どちらも単一の文字列引数をとる。それらは次のように定義されている。

subroutine rexit(message)

subroutine rwarn(message)

255文字より長いメッセージは、警告と共に切り詰められる。

6.3 乱数生成

R内部の乱数生成ルーチンへのインタフェースは

double unif_rand();

double norm_rand();

double exp_rand();

であり、それぞれ 1つの一様、正規、指数擬似乱数を与える。しかしこれらが使われる前に、ユーザは次のものを呼び出さなければならない。

GetRNGstate();

そして、すべての必要となる変数が生成された後には、次のものを呼ばなければならない。

Page 145: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 139

PutRNGstate();

これらは本質的には.Random.seedを読み込み (あるいは生成し)、使用後にそれを書き出している。

ファイル S.hは Sとの互換性のために、GetRNGstateと PutRNGstateではなく、seed_in

と seed_outを定義している。これらは 1つの無視される long *引数をとる。

乱数生成はRに固有のものである; Rの関数への呼び出しを評価することによって以外で、乱数生成の種類を選択する方法や、乱数の種を設定する方法はない。

Rの rxxx関数の背後にある Cコードはヘッダファイル Rmath.hをインクルードすること

によってアクセスすることができる; See Section 6.7.1 [分布関数], page 141。それらの呼び出しは単一の変数を生成し、GetRNGstateと PutRNGstateの呼び出しで囲う必要がある。

6.4 欠損値と IEEE特殊値

NA、Inf、-Infと NaNを検査するために、関数の集合が提供されている。これらの関数はマク

ロを通してアクセスされる:

ISNA(x) Rの NAに対してのみ真

ISNAN(x) Rの NAと IEEE NaNに対して真

R_FINITE(x) Inf、-Inf、NA、NaNに対して偽

そして、NaNは真だが、NAは偽となる関数 R_IsNaNを通してアクセスされる。

isfiniteあるいは finiteではなく、R_FINITEを使うようにせよ; 後者はしばしば間違いを起こし、isfiniteは R_FINITEが isfiniteを拡張するマクロであるような環境でのみ利用

可能である。

現時点で、Cコードで書かれた ISNANは isnanを呼び出すマクロである。(これはあるC++のシステム上で問題を起こすことから、もしRのヘッダがC++のコードから呼ばれると、関数呼び出しが使用される。)

Infあるいは-Infは、R_PosInfあるいは R_NegInfと同等か検査することで確認すること

ができ、NAを NA_REALと設定する (が検査はしない)。

上のすべては倍精度浮動小数点数型変数に対してのみ適用される。整数変数に対してはマ

クロ NA_INTEGERによってアクセスされる変数があり、欠損に対し設定あるいは検査するため

に使うことができる。

6.5 印字

コンパイル済み Cルーチンから Rへ印字するのに最も有用な関数は Rprintfである。これ

は printfと正確に同じ方法で使用されるが、Rの出力 (ファイルではなく GUIコンソールか

もしれない。そして sinkによってリダイレクトすることができる。)に書き出すことが保証されている。Rへ戻る前に ("\n"を含んでいる)完全な行を書くのが賢明である。Rprintfは

R_ext/Print.hに定義されている。

関数 REprintfは似ているが、標準出力ストリームと同じかもしれないし、異なるかもし

れないエラーストリーム (stderr)に書き出す。

関数 Rvprintfと REvprintfは vprintfインタフェースを使う類似物である。そのインタ

フェースはC99のインタフェースであるため、R_ext/Print.hがインクルードされたときに、マクロR_USE_C99_IN_CXXが定義されていれば、C++コードで書かれたR_ext/Print.hによっ

てのみ 2つの関数は定義される。

これらの関数を使うことが重要である別の状況は、出力が適切にリダイレクト/記録されるような、計算ノードのクラスタ上での並列計算を用いているときである。

Page 146: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 140

6.5.1 FORTRANからの印字

多くのシステムで、FORTRANの writeと printステートメントは使用できるが、出力はCのそれと上手く混ざらないかもしれず、GUIインタフェース上で見ることはできないであろ

う。これのステートメントは移植性がなく、避けることが最善である。

FORTRANコードからの情報の出力を容易にするため、3つのサブルーチンが提供されている。

subroutine dblepr(label, nchar, data, ndata)

subroutine realpr(label, nchar, data, ndata)

subroutine intpr (label, nchar, data, ndata)

ここで labelは最大 255文字の文字ラベルであり、ncharはその長さである (全体のラベルが使用されるのであれば-1をとりうる)。そして dataは適切な型 (それぞれ double precision、

realと integer)の少なくとも ndataの長さの配列である。これらのルーチンは 1行にラベルを印字し、後続の行に dataを Rのベクトルであるかのように印字する。これらの関数はndataが 0でも動作するので、ラベルを単独で印字するために使うことができる。

6.6 FORTRANからCを呼ぶこととその逆

FORTRANによって生成されるシンボルの命名規則はプラットフォームで異なる: FORTRANの名前はCの末尾にアンダースコアをつけるものであると仮定するのは安全ではない。プラットフォーム特有の違いを覆い隠すために役立つ、使用すべきマクロの集まりがある。

F77_SUB(name)

FORTRANから呼ばれる Cの関数を定義する

F77_NAME(name)

Cで使用前に FORTRANのルーチンを宣言する

F77_CALL(name)

Cから FORTRANルーチンを呼び出す

F77_COMDECL(name)

Cで FORTRANの共通ブロックを宣言する

F77_COM(name)

Cから FORTRANの共通ブロックにアクセスする

現在の大部分のプラットフォームで、これらはすべて同じであるが、これらに頼るのは賢

明ではない。アンダースコアを伴った名前は FORTRAN 77では正当ではなく、上のマクロで移植性のある状態で扱われない。(また、Rによって使用されるすべての FORTRANの名前は小文字であるが、これはマクロでは適用されない。)

例えば、FORTRANから Rの標準正規乱数を呼び出したいとしよう。次の行に沿った Cのラッパが必要となる。

#include <R.h>

void F77_SUB(rndstart)(void) { GetRNGstate(); }

void F77_SUB(rndend)(void) { PutRNGstate(); }

double F77_SUB(normrnd)(void) { return norm_rand(); }

FORTRANからは以下のようにして呼び出される。

Page 147: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 141

subroutine testit()

double precision normrnd, x

call rndstart()

x = normrnd()

call dblepr("X was", 5, x, 1)

call rndend()

end

使用した Cと FORTRANのコンパイラ間で返す規則に互換性がないかもしれないため、これは移植性が保証されていないことに注意。(引数を経由して値を渡すのがより安全である。)

例えば statsのような標準的なパッケージは、更なる例の豊富な情報源である。

6.7 数値解析サブルーチン

Rは自身で使うため、大量の数学関数を含んでいる。例えば、数値線形代数計算や特殊関数がある。

ヘッダファイル R_ext/BLAS.h、R_ext/Lapack.hと R_ext/Linpack.hは、Rに含まれるBLAS、LAPACKと LINPACK/EISPACKの線形代数関数の宣言を含んでいる。これらはFORTRANサブルーチンへの呼び出しとして表現されており、ユーザの FORTRANコードからも利用することができる。公式 APIの一部ではないが、このサブルーチンの集合は変化

しないであろう (ただし、追加はされるであろう)。

ヘッダファイル Rmath.hは利用可能で、以下のサブセクションで文書化されている多くの

他の関数を一覧にしている。それらの多くは、R関数の背後にあるコードへのCインタフェースであり、そのためR関数の文書は更なる詳細を与えるであろう。

6.7.1 分布関数

標準的な統計分布に対して密度、累積分布関数と分位関数を計算するために使われるルーチ

ンはエントリポイントとして利用可能である。

エントリポイントへの引数は標準正規分布に対する様式に従う:

double dnorm(double x, double mu, double sigma, int give_log);

double pnorm(double x, double mu, double sigma, int lower_tail,

int give_log);

double qnorm(double p, double mu, double sigma, int lower_tail,

int log_p);

double rnorm(double mu, double sigma);

すなわち、最初の引数は密度、累積分布関数の位置、分位関数の確率を与え、分布のパラメー

タがそれに続く。引数 lower tailは通常の使用では TRUE (あるいは 1)とすべきであるが、もし分布の上側の確率が欲しい、あるいは指定されている場合は、FALSE (あるいは 0)をとることもある。

最後に、give logはもし結果が対数スケールで求められているのであれば非ゼロの値にしなければならない。また log pはもし pが対数スケールに指定されているのであれば、非ゼロの値にしなければならない。

次のものを使うことで、直接的に累積 (あるいは “統合”)ハザード関数、H(t) = − log(1−F (t))が得られることに注意。

- pdist(t, ..., /*lower_tail = */ FALSE, /* give_log = */ TRUE)

もしくはより簡潔に (そしてより暗号的な)- pdist(t, ..., 0, 1)としても得られる。

Page 148: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 142

乱数生成ルーチン rnormは 1つの標準変量を返す。乱数ルーチンを使う決まりごとについては See Section 6.3 [乱数], page 138を参照せよ。

これらの引数の順序は (名前と rnormが nを持たないことは別として、)大部分は同じ名前の対応するRの関数と同じであり、そのためR関数のドキュメントを使うことができることに注意。指数分布とガンマ分布は rateではなく、scaleによってパラメータ付けされている

ことに注意せよ。

参考のため、以下の表で基本名 (言及されている例外を除き、‘d’、‘p’、‘q’あるいは ‘r’が先頭に付けられる)と、分布の一式に対する、分布固有の引数を与える。

beta beta a, bnon-central beta nbeta a, b, ncpbinomial binom n, pCauchy cauchy location, scalechi-squared chisq df

non-central chi-squared nchisq df, ncpexponential exp scale (and not rate)F f n1, n2non-central F nf n1, n2, ncpgamma gamma shape, scalegeometric geom p

hypergeometric hyper NR, NB, nlogistic logis location, scalelognormal lnorm logmean, logsdnegative binomial nbinom size, probnormal norm mu, sigmaPoisson pois lambda

Student’s t t n

non-central t nt df, deltaStudentized range tukey (*) rr, cc, dfuniform unif a, bWeibull weibull shape, scaleWilcoxon rank sum wilcox m, nWilcoxon signed rank signrank n

アスタリスクで印付けられたエントリは ‘p’と ‘q’の関数のみが利用可能であり、非心分布のすべては ‘r’の関数を持たない。dwilcox、pwilcoxあるいは qwilcoxの呼び出しの後は、関数

wilcox_free()を呼ばなければならず、そして符号付き順位関数に対しても同様に呼ぶ必要

がある。

6.7.2 数学関数

[Function]double gammafn (double x)[Function]double lgammafn (double x)[Function]double digamma (double x)[Function]double trigamma (double x)[Function]double tetragamma (double x)[Function]double pentagamma (double x)

Page 149: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 143

[Function]double psigamma (double x, double deriv)ガンマ関数、その絶対値の自然対数と最初の 4つの導関数と、lgammafnの導関数であるPsiのn次導関数。言い換えると、digamma(x)は(psigamma(x,0)と同じ、trigamma(x)

== psigamma(x,1)など。

[Function]double beta (double a, double b)[Function]double lbeta (double a, double b)

(完全)ベータ関数とその自然対数

[Function]double choose (double n, double k)[Function]double lchoose (double n, double k)

nが任意の実数に一般化された、n個から k個が選ばれる組み合わせの総数と、その絶対値の自然対数。kは最も近い整数に丸められる (必要があれば警告を出す)。

[Function]double bessel_i (double x, double nu, double expo)[Function]double bessel_j (double x, double nu)[Function]double bessel_k (double x, double nu, double expo)[Function]double bessel_y (double x, double nu)

インデックスが nuで、U、J、KとYの型のベッセル関数。bessel_iと bessel_kに対

しては、もし expoが 2であれば、exp(-x) I(x; nu)あるいは exp(x) K(x; nu)を返すオプションがある。(スケール化されていない値に対しては expo == 1を使用せよ。)

6.7.3 数値ユーティリティ

エントリポイントとして利用可能な、他の数値ユーティリティ関数が少しある。

[Function]double R_pow (double x, double y)[Function]double R_pow_di (double x, int i)

R_pow(x, y) and R_pow_di(x, i) x^yと x^iを計算する。それぞれ R_FINITEの検査

を使い、x、yあるいは iが、ゼロ、欠損、無限、あるいは NaNである場合に対して適切

な (Rと同じ)結果を返す。

[Function]double log1p (double x)log(1 + x) (log 1 plus x )を計算し、小さなxに対しても正確に計算する。つまり |x| ≪ 1の場合である。

関数が Rmath.hに含まれていない場合はプラットフォームにより提供されるべきであ

るが、Rmath.hをインクルードしている math.hの中にに (おそらく)ある。

[Function]double log1pmx (double x)log(1 + x) - x (log 1 plus x minus x)を計算し、小さな xに対しても正確に計算する。つまり |x| ≪ 1の場合である。

[Function]double log1pexp (double x)log(1 + exp(x)) (log 1 plus exp)を計算し、特に大きな xに対して正確に計算する。例えば、x > 720のときなど。

[Function]double expm1 (double x)exp(x) - 1 (exp x minus 1 )を計算し、小さい xに対しても正確に計算する。つまり|x| ≪ 1の場合である。

関数が Rmath.hに含まれていない場合はプラットフォームにより提供されるべきであ

るが、Rmath.hをインクルードしている math.hの中にに (おそらく)ある。

Page 150: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 144

[Function]double lgamma1p (double x)log(gamma(x + 1)) (log(gamma(1 plus x)))を計算し、小さい xに対しても正確に計算する。つまり、0 < x < 0.5の場合である。

[Function]double logspace_add (double logx, double logy)[Function]double logspace_sub (double logx, double logy)

各項の対数から和あるいは差の対数を計算する。つまり不必要なオーバーフローや多

くの精度を捨てることを起こすことなく、log (exp(logx) + exp(logy))として “x +

y”、log (exp(logx) - exp(logy))として “x - y”を計算する。

[Function]int imax2 (int x, int y)[Function]int imin2 (int x, int y)[Function]double fmax2 (double x, double y)[Function]double fmin2 (double x, double y)

2つの整数の大きい方 (max)、あるいは小さい方 (min)、または実数値のそれぞれを返す。引数の 1つが NaNである場合は、fmax2と fmin2はC99の fmaxや fminとは異なる

ことに注意: これらのバージョンでは NaNが返される。

[Function]double sign (double x)signum関数を計算する。xが正、0、負であるとき、sign(x)はそれぞれ 1、0、−1となり、xが NaNであるときは NaNとなる。

[Function]double fsign (double x, double y)“符号の乗り換え”を実行し、|x| ∗ sign(y)として定義されている。

[Function]double fprec (double x, double digits)10進法で (小数点以下)digits桁に xを丸めた値を返す。

これはRの round()が使っている関数である。

[Function]double fround (double x, double digits)10進法で有効桁数 digits桁に xを丸めた値を返す。

これはRの signif()が使っている関数である。

[Function]double ftrunc (double x)xをゼロに向けて (整数値に)切り捨てた値を返す。

6.7.4 数学定数

Rは通常 math.hにある定数と統計計算で使われる定数を含む、一般的に使われる数学定数の

集合を持つ。これらのすべては Rmath.hに (少なくとも)30桁の精度で定義されている。以下の定義では、自然対数 (Rにおける log(x))に対して ln(x)を使っている。

Name Definition (ln = log) round(value, 7)M_E e 2.7182818M_LOG2E log2(e) 1.4426950M_LOG10E log10(e) 0.4342945M_LN2 ln(2) 0.6931472M_LN10 ln(10) 2.3025851M_PI π 3.1415927

Page 151: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 145

M_PI_2 π/2 1.5707963M_PI_4 π/4 0.7853982M_1_PI 1/π 0.3183099M_2_PI 2/π 0.6366198M_2_SQRTPI 2/sqrt(π) 1.1283792M_SQRT2 sqrt(2) 1.4142136M_SQRT1_2 1/sqrt(2) 0.7071068M_SQRT_3 sqrt(3) 1.7320508M_SQRT_32 sqrt(32) 5.6568542M_LOG10_2 log10(2) 0.3010300M_2PI 2π 6.2831853M_SQRT_PI sqrt(π) 1.7724539M_1_SQRT_2PI 1/sqrt(2π) 0.3989423M_SQRT_2dPI sqrt(2/π) 0.7978846M_LN_SQRT_PI ln(sqrt(π)) 0.5723649M_LN_SQRT_2PI ln(sqrt(2π)) 0.9189385M_LN_SQRT_PId2 ln(sqrt(π/2)) 0.2257914

Sとの互換性のために、インクルードされるヘッダ R_ext/Constants.hに定義された定数

(PI, DOUBLE_EPS)(など)の集合がある (STRICT_R_HEADERSが定義されていない限り)。

さらに、インクルードされるヘッダ R_ext/Boolean.hは “論理値”変数をCで一貫して使う方法を提供するために Rboolean型の定数 TRUEと FALSE = 0を持つ。

6.8 最適化

optimに内在する Cコードは直接アクセスできる。ユーザは次の型を持つ、最小化すべき関数を計算するための関数を提供する必要がある。

typedef double optimfn(int n, double *par, void *ex);

ここで最初の引数は第 2引数のパラメータの数である。第 3引数は呼び出しルーチンから伝わるポインタであり、通常は補助情報を運ぶために使われる。

いくつかのメソッドは勾配関数を必要とする。

typedef void optimgr(int n, double *par, double *gr, void *ex);

は勾配を gr引数に返す。どの関数も結果で有限差分の微分のためにも、ヘシアンを近似する

ためにも提供されていない。

インタフェース (ヘッダ R_ext/Applic.hで定義されている)は次のものがある。

• Nelder Mead法:

void nmmin(int n, double *xin, double *x, double *Fmin, optimfn fn,

int *fail, double abstol, double intol, void *ex,

double alpha, double beta, double gamma, int trace,

int *fncount, int maxit);

• BFGS法:

void vmmin(int n, double *x, double *Fmin,

optimfn fn, optimgr gr, int maxit, int trace,

int *mask, double abstol, double reltol, int nREPORT,

void *ex, int *fncount, int *grcount, int *fail);

Page 152: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 146

• 共役勾配法:

void cgmin(int n, double *xin, double *x, double *Fmin,

optimfn fn, optimgr gr, int *fail, double abstol,

double intol, void *ex, int type, int trace,

int *fncount, int *grcount, int maxit);

• 範囲による制約付き省メモリ BFGS法:

void lbfgsb(int n, int lmm, double *x, double *lower,

double *upper, int *nbd, double *Fmin, optimfn fn,

optimgr gr, int *fail, void *ex, double factr,

double pgtol, int *fncount, int *grcount,

int maxit, char *msg, int trace, int nREPORT);

• 焼きなまし法:

void samin(int n, double *x, double *Fmin, optimfn fn, int maxit,

int tmax, double temp, int trace, void *ex);

多くの引数はさまざまなメソッドに共通している。nはパラメータ数、xまたは xinはエント

リの開始パラメータである。最後の値は Fminに入れられて返され、xは終了時に最後のパラ

メータとなる。他の引数の大部分は optimのヘルプページで見ることができる: 境界を指定するために使われる nbdの値については、ソースコード src/appl/lbfgsb.cを参照せよ。

6.9 積分

integrateに内在する Cコードは直接アクセスできる。ユーザは次の型を持つ、積分したい関数を計算するベクトル化した Cの関数を提供する必要がある。

typedef void integr_fn(double *x, int n, void *ex);

ここで、x[]は入力と出力の両方であり、長さは nである。すなわち、integr_fnの型を持つ

Cの関数、そう fnは、基本的には for(i in 1:n) x[i] := f(x[i], ex)としなければならな

い。ベクトル化の要件は、関数を n回呼ぶ代わりに非積分関数の速度を上げるために使うこ

とができる。現在の実装ではQUADPACKで構築されており、nは 15または 21のどちらかであることに注意。ex引数は呼び出しルーチンから伝わってくるポインタであり、通常は補

助情報を運ぶために使われている。

定積分と不定積分に対する (ヘッダ R_ext/Applic.hで定義された)インタフェースがある。‘不定’は積分の境界の少なくとも一方が有限でないことを意味する。

• 有限:

void Rdqags(integr_fn f, void *ex, double *a, double *b,

double *epsabs, double *epsrel,

double *result, double *abserr, int *neval, int *ier,

int *limit, int *lenw, int *last,

int *iwork, double *work);

• 無限:

void Rdqagi(integr_fn f, void *ex, double *bound, int *inf,

double *epsabs, double *epsrel,

double *result, double *abserr, int *neval, int *ier,

int *limit, int *lenw, int *last,

int *iwork, double *work);

Page 153: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 147

2つの積分器で 3番目と 4番目の引数だけが異なる; Rdqagsを使う定積分の aと bは積分区間

の境界である。一方、Rdqagiを使う不定積分の boundは (もし積分が双方向に無限でなければ)積分の有限な範囲であり、infは積分範囲の種類を示している。

inf = 1 は (bound, +Inf)に対応し、

inf = -1 は (-Inf, bound)に対応し、

inf = 2 は (-Inf, +Inf)に対応する。

fと exは被積分関数を定義する。上を参照せよ; epsabsと epsrelは要求される絶対精

度と相対精度を指定する。result、abserrと lastは R 関数 integrate の出力要素 value、

abs.errと subdivisionsであり、nevalは被積分関数の評価回数を与える。エラーコード

ierは関数の定義を見るRの integrate() $ messageに訳される。limitは integrate(...,

subdivisions = *)に対応する。2つの作業用配列と 2番目の配列の長さについては、常に次のように定義しなければならないように思われる。

lenw = 4 * limit;

iwork = (int *) R_alloc(limit, sizeof(int));

work = (double *) R_alloc(lenw, sizeof(double));

src/appl/integrate.c中のソースコードのコメントは詳細を与え、特に失敗 (ier >= 1)について書かれている。

6.10 ユーティリティ関数

Rはユーザのコードで利用可能になっているかなりの包括的なソートルーチンを持つ。これらはヘッダファイル R_ext/Utils.h(R.hにインクルードされている)で宣言されており、以下の関数を含んでいる。

[Function]void R_isort (int* x, int n)[Function]void R_rsort (double* x, int n)[Function]void R_csort (Rcomplex* x, int n)[Function]void rsort_with_index (double* x, int* index, int n)

最初の 3つはそれぞれ整数、実数 (倍精度)、複素数のデータをソートする。(複素数は最初に実部、次に虚部でソートする。)NAは一番後ろにソートされる。

rsort_with_indexは xをソートし、同様の順列を indexに適用する。NAは一番後ろに

ソートされる。

[Function]void revsort (double* x, int* index, int n)は rsort_with_indexと似ているが、降順にソートし、NAは処理されない。

[Function]void iPsort (int* x, int n, int k)[Function]void rPsort (double* x, int n, int k)[Function]void cPsort (Rcomplex* x, int n, int k)

これらはすべて (非常に)部分的なソートを提供する: 小さい値が左に、大きな値が右にくるようにし、x[k]が正しい位置にあるように xの並び替える。

[Function]void R_qsort (double *v, int i, int j)[Function]void R_qsort_I (double *v, int *I, int i, int j)[Function]void R_qsort_int (int *iv, int i, int j)

Page 154: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 148

[Function]void R_qsort_int_I (int *iv, int *I, int i, int j)これらのルーチンはRsort(v, method = "quick")ので使われており、Rの関数sortの

ヘルプページで文書化されているようなクイックソートのアルゴリズムを呼び、v[i:j]

または iv[i:j](1-インデクシング、つまり v[1]が最初の要素である)をソートする。..._I()となっているものは、Iに sort.index()ベクトルも返す。順序は安定ではな

いので、同じ値は並び替えられるかもしれないことに注意。

NAは (明示的に)扱われず、もし NAが存在する可能性があるのであれば、別の関数を使

うべきであるということに注意。

[Function]subroutine qsort4 (double precision v, integer indx, integer ii, integerjj)

[Function]subroutine qsort3 (double precision v, integer ii, integer jj)倍精度ベクトルのソート用の FORTRANインタフェースルーチンは qsort3と qsort4

であり、それぞれ R_qsort、R_qsort_Iと同等である。

[Function]void R_max_col (double* matrix, int* nr, int* nc, int* maxes, int*ties_meth)

nr× ncの行列 matrixが列優先 (“FORTRAN”)順で与えられたとき、R_max_col()は

maxes[i-1]に、i番目の行で最大要素の列番号を返す (Rの max.col()と同じ)。同点(複数の最大値)の場合は、1:3の値の整数コードである*ties_methが手法を決定する。

1 = “ランダム”、2 = “最初”、3 = “最後”。Rの?max.colのヘルプページを参照せよ。

[Function]int findInterval (double* xt, int n, double x, Rbooleanrightmost_closed, Rboolean all_inside, int ilo, int* mflag)

長さ nの順序付きベクトル xtが与えられたとき、xt[]にある xの区間または添字を返す。一般的には Rと FORTRAN(Cにはない)にあるような、1-インデクシングを使ったmax(i; 1 ≤ i ≤ n & xt[i] ≤ x) である。もし rightmost closedが trueであれば、xが xt[n]に等しければ n− 1も返す。もし all insideが 0でなければ、xが xt[]の範囲の外部にあるときでさえ、結果は 1:(n-1)に強制変換される。値を返すときに、x < xt[1]であれば、*mflagは−1に等しく、x >= xt[n]であれば+1、それ以外では 0となる。

アルゴリズムは iloが findInterval()の結果が最新の結果に設定され、xが後の呼び出しで増加、あるいは減少となるような数列であるときに、特に高速に動作する。

findInterval()と同じ引数だけでなくポインタまで同じである、findInterval()の

F77_CALL(interv)()版もある。

以下の 2つの関数はHSVからRGB、あるいはその逆の数値的色空間の変換を行う。すべての色は [0,1]になければならないことに注意。

[Function]void hsv2rgb (double h, double s, double v, double *r, double *g,double *b)

[Function]void rgb2hsv (double r, double g, double b, double *h, double *s,double *v)

一時ファイルの名前を生成するためのシステム依存のインタフェースは次で与えられる。

[Function]char * R_tmpnam (const char *prefix, const char *tmpdir)[Function]char * R_tmpnam2 (const char *prefix, const char *tmpdir, const char

*fileext)ディレクトリ tmpdir内に、prefixで始まり、fileextで終わる名前の一時ファイルのパス名を返す。接頭辞と拡張子の NULLは""に置き換えられる。返ってくる値は mallocされ

Page 155: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 149

るので、必要なくなったときには freeしなければならない (システムコール tmpnamと

は異なる)。

いくつかのR関数でファイル名を展開するために使われ、path.expandによって直接呼ば

れる内部関数もある。

[Function]const char * R_ExpandFileName (const char *fn)先頭のチルダを (定義されていれば)ユーザのホームディレクトリに置き換えることで、パス名 fnを展開する。正確な意味はプラットフォームに固有である; もし HOMEが定義

されていれば、普通は HOMEから取られるであろう。

6.11 再エンコーディング

異なった iconvの実装の宣言における非互換性があるため、Rは iconvから提供されている

エンコード変換機能への Cレベルのインタフェースを持つ。

それらはヘッダファイル R_ext/Riconv.hで宣言されている。

[Function]void *Riconv_open (const char *to, const char *from)2つのエンコード間で変換するために使われるエンコーディングオブジェクトへのポイン

タを設定する: ""は現在のロケールを意味する。

[Function]size_t Riconv (void *cd, const char **inbuf, size t *inbytesleft,char **outbuf, size t *outbytesleft)

inbufをできるだけ outbufに変換する。最初に int型の変数はバッファ中の利用可能なバ

イト数を示しており、それらは更新される (そして char型のポインタはバッファ中の次の空き

バイトを指すよう更新される)。返り値は変換された文字の数、あるいは (size_t)-1である

(注意せよ: size_tは通常符号無し型である)。エラーの状態が errnoを E2BIG(出力バッファが満杯)、EILSEQ(入力が変換できず、指定されたエンコーディングで無効であった)、あるいは EINVAL(入力が完全なマルチバイト文字で終了していない)のどれか 1つに設定すると仮定しても安全であるはずである。

[Function]int Riconv_close (void * cd)エンコーディングオブジェクトの資源を解放する。

6.12 割り込み許可

コンパイルしたコードでの長い計算の最中に、Rのどのポートも中断されることはないので、プログラマはコードが適切な場所でコードが中断されるよう準備するべきである。準備は Cから呼ぶ場合は次のようになり、

#include <R_ext/Utils.h>

void R_CheckUserInterrupt(void);

FORTRANからは次のようになる。

subroutine rchkusr()

これらはユーザが割り込み要求をしたかを検査し、もしそうであればRのエラー処理関数に分岐する。

ここで定義されたエントリポイントの 1 つの背後にあるコードで、あなたの C またはFORTRANコードから呼ばれているものは割り込み可能、あるいはエラーを生成することができることに注意。そのため自身のコードへ返ってこない。

Page 156: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 150

6.13 プラットフォームとバージョン情報

ヘッダファイルは USING_Rを定義しており、これはコードが実際にRと一緒に使われているかを検査するために使うことができる。

ヘッダファイル Rconfig.h(R.hにインクルードされている)は、主に他のヘッダファイルでの使用のため、プラットフォーム固有のマクロを定義するために使われる。マクロ WORDS_

BIGENDIANはビッグエンディアン 2システム (例えば Sparcや PowerPCハードウェア上の大部分のOS)で定義されており、リトルエンディアンシステム (例えば i686と x86_64のすべて

の OSや、Alpha、Itanium上の Linux)では定義されていない。このマクロはバイナリファイルを操作するときに役立つことがある。マクロ SUPPORT_OPENMPは R 2.13.0より適切なシステム上で定義されており、OpenMPを使いたいパッケージで SUPPORT_OPENMP_*マクロと

併せて使うことができる。

ヘッダファイル Rversion.h(R.hにインクルードされていない)は整数としてコード化されたバージョン番号を与えるマクロ R_VERSION、加えてコード化するためのマクロ R_Version

を定義している。このヘッダはRのバージョンが十分新しいかを検査するため、あるいは後方互換性の機能を含めるために使うことができる。このマクロを持たないかなり古いRのバージョンを保護するためには、例えば次のような構造を使用せよ。

#if defined(R_VERSION) && R_VERSION >= R_Version(1, 9, 0)

...

#endif

マクロ R_MAJOR、R_MINOR、R_YEAR、R_MONTHと R_DAYにある詳細情報が利用可能である:それらのフォーマットについてはヘッダファイル Rversion.hを参照せよ。マイナーバージョ

ンは (‘9.0’に見られるように)パッチレベルも含まれていることに注意。

6.14 C言語の関数のインライン化

C99のキーワード inlineは現在Rをビルドするために使われるすべてのコンパイラで認識されなければならない。Rの以前のバージョンで使われていたかもしれない移植性のあるコードは、マクロ R_INLINEを使って書くことができる。例えば、パッケージ cluster (http://CRAN.R-project.org/package=cluster)では次のようになっている。

#include <R.h>

static R_INLINE int ind_2(int l, int j)

{

...

}

複数のコンパイル単位で関数のインライン化を使うことは、ほぼ移植性のあるようにでき

ないことに注意。http://www.greenend.org.uk/rjk/2003/03/inline.htmlを見よ。その

ため、インライン化の使用は例にあるように static関数に対するものとなる。Rの構成コードが検査したことのすべては、R_INLINEが Rをビルドするために使用したコンパイラを使い、単独の Cファイルで使えるかということである。我々は広い範囲でインライン化を使用するパッケージには、独自の設定コードを含めることを推奨する。

2 http://en.wikipedia.org/wiki/Endianness。

Page 157: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 151

6.15 可視性の制御

ヘッダ R_ext/Visibilityはエントリポイントの可視性を制御する定義をいくつか持つ。これ

らは ‘HAVE_VISIBILITY_ATTRIBUTE’が定義されているときのみ有効である – これは Rが設定されたときに検査され、(R_ext/Visibility.hでインクルードされる)ヘッダ Rconfig.h

に記録される。最近のコンパイラ (例えば gcc4)を持つ現在のUnix系では一般的に定義されているが、Windows上ではサポートされていない。共有ライブラリのシンボルの可視性を最小化することは、ロードの速度向上 (重要である可能性が低い)と、同じ名前の間違ったエントリポイントへリンクする可能性を小さくすることの両方になる。

attribute_hiddenという接頭辞がつけられたC/C++のエントリポイントは共有オブジェクトでは見えなくなる。FORTRANのエントリポイントに対しては比較できるような仕組みはないが、例えばパッケージ statsに使われている、より包括的な方式がある。可視性の制御が可能な大部分のコンパイラはフラグを通してすべてのシンボルに対する可視性の制御が可

能であり、既知の Cと FORTRAN用のフラグはマクロ ‘C_VISIBILITY’と F77_VISIBILITY

にカプセル化されている。これらは etc/Makeconfに定義されており、そのためパッケージ

コードの通常のコンパイルでも利用可能である。例えば、src/Makevarsは次のものを含んで

いることがある。

PKG_CFLAGS=$(C_VISIBILITY)

PKG_FFLAGS=$(F77_VISIBILITY)

これは見えるエントリポイントがなく終わるので、先がない。しかしフラグの効果は接頭

辞 attribute_visibleを使うことで上書きすることができる。エントリポイントを登録する

共有オブジェクトは 1つの見えるエントリポイント、初期化子を持っていることだけを必要とするので、例えば statsは次のような関数を持つ。

void attribute_visible R_init_stats(DllInfo *dll)

{

R_registerRoutines(dll, CEntries, CallEntries, FortEntries, NULL);

R_useDynamicSymbols(dll, FALSE);

...

}

視認性の仕組みは Windows 上では使えないが、定義ファイル pkgnme/src/pkgname-

win.defを供給することによる、エントリポイントを見えるようにする同等の効果的な制御

方法がある: そのファイルの一覧にあるエントリポイントだけが見える。愛度例として statsを使うと、パッケージでは次のようになっている。

LIBRARY stats.dll

EXPORTS

R_init_stats

6.16 自身のCコード内でこれらの関数を使う

Unix系とWindowsの両方の下でスタンドアロンライブラリ libRmathとして、Rmath.hに

記録されている Rの数学関数の集まりである Mathlibをビルドすることができる。(これはSection 6.7 [数値解析サブルーチン], page 141で文書化されている関数を含んでいる。)

ライブラリは Rがインストールされたときに自動的にビルドされないが、Rのソースにあるディレクトリ src/nmath/standaloneでビルドすることができる: そこにあるファイルREADMEを参照せよ。自身のプログラムでコードを使うためには、次のものを含めよ。

#define MATHLIB_STANDALONE

#include <Rmath.h>

Page 158: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 152

そして、‘-lRmath’(とおそらく ‘-lm’)に対してリンクせよ。参考例のファイル test.cがある。

乱数ルーチンを使うには少し注意が必要となる。次のような一様乱数生成器

double unif_rand(void)

を準備する、あるいは付属のもの (と付属のものと共に使わなければならない動的ライブラリやDLLがある。これはMarsaglia-multicarry法という乱数の種類であり、乱数の種を設定するために次のエントリポイント

set_seed(unsigned int, unsigned int)

を持ち、そして乱数の種を読み出すための

get_seed(unsigned int *, unsigned int *)

を持つ。)を使う必要がある。

6.17 ヘッダファイルの構成

R がインストールするヘッダファイルはディレクトリ R_INCLUDE_DIR(既定値はR_HOME/include)にある。現在のところ、これは次のものを含んでいる。

R.h 多くの他のファイルをインクルードする

S.h Sから移植されたコードに対する異なるバージョン

Rinternals.h R内部の構造体を使うための定義Rdefines.h 上にある S系インタフェースに対するマクロRmath.h スタンドアロンな数学ライブラリ

Rversion.h Rのバージョン情報Rinterface.h フロントエンドのアドオン用 (Unix系限定)Rembedded.h フロントエンドのアドオン用

R_ext/Applic.h 最適化と積分

R_ext/BLAS.h BLASルーチン用の Cの定義R_ext/Callbacks.h C(およびR関数)トップレベルのタスクハンドラR_ext/GetX11Image.h パッケージ trkplotに使用されるX11Imageイン

タフェース

R_ext/Lapack.h いくつかの LAPACKルーチンに対する Cの定義

R_ext/Linpack.h いくつかの LINPACKに対する Cの定義。それらのすべてはRには含められていない。

R_ext/Parse.h Rの構文解析インタフェースのごく一部: 安定したAPIの一部ではない。

R_ext/RConvertors.h

R_ext/RStartup.h フロントエンドのアドオン用

R_ext/Rdynload.h パッケージ中のコンパイル済みコードを登録する

際に必要

R_ext/R-ftp-http.h download.fileの内部メソッドへのインタフェー

R_ext/Riconv.h iconvへのインタフェース

R_ext/Visibility.h 可視性を制御する定義

Page 159: Rの拡張を書く (R 2.15.2)

Chapter 6: The R API: Cコードのエントリポイント 153

R_ext/eventloop.h フロントエンドのアドオン用とRのイベントループ内で共有する必要があるパッケージ用 (すべてのプラットフォーム上で)

以下のヘッダファイルは R.hに含められる:

Rconfig.h 利用可能な構成情報

R_ext/Arith.h NAs、NaNs、Inf/-Infを扱うR_ext/Boolean.h TRUE/FALSE型R_ext/Complex.h Rの complexに対する Cの typederR_ext/Constants.h 定数

R_ext/Error.h エラー処理

R_ext/Memory.h メモリ割り当て

R_ext/Print.h Rprintfとその変形.R_ext/RS.h F77_CALLなどを含んだ、R.hと S.hの共通した定

R_ext/Random.h 乱数生成

R_ext/Utils.h ソートと他のユーティリティ

R_ext/libextern.h Windows上で R.dllからエクスポートするため

の定義

グラフィックシステムはヘッダR_ext/GraphicsEngine.h、R_ext/GraphicsDevice.h(GraphicsEngine.hがインクルードしている)と R_ext/QuartzDevice.hで公開されている。statsからのいくつかのエントリポイントは R_ext/stats_package.h(現在 nlsと nlminbの内部に関係してい

る)にある。

Page 160: Rの拡張を書く (R 2.15.2)

Chapter 7: 総称的関数とメソッド 154

7 総称的関数とメソッド

Rプログラマはしばしば存在する総称的関数にメソッドを追加したいと思っており、また新しい総称的関数を加えることや既存の関数を総称的にしたいと思っているかもしれない。こ

の章ではそのようにするための指針を与え、指針に従わないことで起こる問題の例を併せて

示す。

この章はS3から複製された ‘非公式な’クラスシステムのみを取り上げ、パッケージmethodsの S4(公式な)メソッドを使った場合は取り上げないものとする。

メソッドの鍵となる関数は NextMethodであり、これは次のメソッドをディスパッチする。

メソッド関数がその引数を少し変更する、次のメソッドにディスパッチする、結果を受け取

りそれを少し修正するということはかなりよくある。例は次の通り。

t.data.frame <- function(x)

{

x <- as.matrix(x)

NextMethod("t")

}

また predict.glmについて考える: Rでは歴史的な理由から、predict.glmはたまたま直接

predict.lmを呼び出す。しかし原則として (Sの元々と現在でも)NextMethodを使うことができる。(NextMethodはRのソース内で使われているように見える。この領域では SとRの違いがあることに留意せよ。そして next メソッドという既定のメソッドがあり、クラスが変わったときに新しいメソッドが選択されているわけではないので、上の例は動作する。)

プログラマが書く任意のメソッドは NextMethodによって別のメソッドから前のメソッド

に適切な引数を伴って起動される。さらにプログラマは NextMethodが選ぶのがどのメソッド

か予測できず (夢にもないものになるかもしれない)、ジェネリックを呼ぶエンドユーザは次のメソッドに引数を渡せることができる必要がある。これが機能するために、

メソッドはもしジェネリックがもし...を含んでいたら、それも含め、ジェネリッ

クの引数をすべて持たなければならない。

メソッドが必要とする引数のみを受けとる必要があると考えるのは重大な誤りである。

元の predict.lmの Sバージョンは predictは...を取っていたのに、...引数を取っていな

かった。predict.glmは過分散を処理するために dispersion引数を必要としていたことがす

ぐに明らかになった。predict.lmは dispersion、...引数のどちらも持たないので、もは

や NextMethodは使えなかった。(レガシーな 2つの predict.lmへの直接呼び出しは、Rのpredict.glmに生き続けている。これはVenables & Ripleyによって書かれた S3のための回避策に基づいている。)

さらにユーザはジェネリックを呼ぶときに位置マッチングを使う権利を持ち、UseMethod

によって呼び出されるメソッドへの引数はジェネリックへの呼び出しの引数である。従って、

メソッドはジェネリックと正確に同じ順序で引数を持たなければならない。

この問題の大きさを見るために、以下で定義された総称的関数 scaleを考えよう。

scale <- function (x, center = TRUE, scale = TRUE)

UseMethod("scale")

何も考えていないパッケージの書き手が次のようなメソッドを作成したと仮定する。

scale.foo <- function(x, scale = FALSE, ...) { }

すると、クラス"foo"の xに対し、次の呼び出し

Page 161: Rの拡張を書く (R 2.15.2)

Chapter 7: 総称的関数とメソッド 155

scale(x, , TRUE)

scale(x, scale = TRUE)

はエンドユーザに筋の通った仰天をさせる、違うことをする可能性が高い。

さらにひねりを追加するため、我々の例でユーザが scale(x)を呼び出したとき、どのデ

フォルトが使われているであろうか?

scale.bar <- function(x, center, scale = TRUE) NextMethod("scale")

と xがクラス c("bar", "foo")を持っていたらどうなるであろうか?使われているのはメソッド内に指定された既定値であるが、ジェネリック内で指定された既知値がユーザが見るもの

であるかもしれない。これは次のことを推奨する:

もしジェネリックが既定値を指定していたら、すべてのメソッドは同じ既定値を

使うべきである。

推奨に従う簡単な方法は常にジェネリクスを単純にすることで、例えば次のようにする。

scale <- function(x, ...) UseMethod("scale")

ジェネリックを実装しているすべての可能性のあるメソッド内で意味を持つ場合のみ、ジェ

ネリックにパラメータと既定値を追加する。

7.1 新しいジェネリクスを加える

新しいジェネリック関数を作るとき、その引数リストは数年後別の場所で書かれたメソッド

も含め、メソッドの引数の最大集合になることを心に留めよ。そのため、引数のよい集合を

選ぶことは重要なデザインの問題であり、...引数を含まないよい引数であることが必要とさ

れる。

もし...引数が与えられているのであれば、引数の列でのその位置について考えるべきで

ある。...が続く引数は関数への呼び出しで名づけられていなければならず、完全な名前がつ

けられなければならない (部分的なマッチングは...の後に抑制されている)。...の前の仮引

数は部分マッチングをすることができるので、...に対して意図した引数を ‘飲み込む’かもしれない。...引数を最後の引数にするのは普通であるが、それはいつも正しい選択とは限ら

ない。

ときどきパッケージの書き手は baseパッケージ内にジェネリック関数を作りたいと思い、R内で変更を要求する。これは正当なものであるかもしれないが、デフォルトのメソッドとして、関数を古い定義を持つジェネリックにすることはコストパフォーマンスが低い。パッ

ケージは baseパッケージにある関数を引き継ぐことができ、次のように関数をジェネリックにすることができることから、上のことは決して必要ではない。

foo <- function(object, ...) UseMethod("foo")

foo.default <- function(object, ...) base::foo(object)

このマニュアルの初期のバージョンでは foo.default <- base::fooと代入することを提案

していた。代入すると baseの関数をインストール時に保存し、Rにパッチが当てられる、あるいは更新されると元の base関数が変更されてしまうことから、これは良い考えではない。

同様の考えが名前空間を持つ他のパッケージにある関数にも適用することができる。

Page 162: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 156

8 GUIと他のフロントエンドをRと結びつける

Rへのフロントエンドを構築する方法はいくつもある: 我々はこれを Rへコマンドを渡す、あるいはおそらく結果を受け取る (必ずしもテキスト形式とは限らない)能力を持つ GUIや他のアプリケーションという意味に取る。ここに記載されている以外の手段がある。例えば

パッケージRserve (http://CRAN.R-project.org/package=Rserve)(CRANから、http://

www.rforge.net/Rserve/も参照せよ。)とOmegahatパッケージ ‘SJava’と ‘JRI’(CRAN上

の rJava (http://CRAN.R-project.org/package=rJava)パッケージの一部)にある Javaへの接続がある。

この章に記載されている APIはフロントエンドの代替でのみ使われることを意図していることに注意: Rパッケージで利用可能な APIの一部ではなく、従来のパッケージ内で使うのは危険な可能性がある (パッケージは別のフロントエンドを含んでいるかもしれないが)。

8.1 Unix系でRを組み込む

Rはもし--enable-R-shlibと設定されていれば共有ライブラリ 1 として構築することがで

きる。この共有ライブラリはRを別のフロントエンドのプログラムから実行するために使うことができる。このセクションの以降ではこれが既に実行されているものと仮定する。また

--enable-R-static-libと設定されていれば、Rを静的ライブラリとして構築することもでき、これは同様の方法で使用することができる。

コマンドライン R フロントエンドである R_HOME/bin/exec/Rは 1 つのそのような例であり、かつての GNOME(CRANの ‘Archive’領域にある gnomeGUI パッケージを参照せよ) と Mac OS X コンソールは別である。R_HOME/bin/exec/Rのソースはファイル

src/main/Rmain.cにあり、とても単純である。

int Rf_initialize_R(int ac, char **av); /* ../unix/system.c にある */

void Rf_mainloop(); /* main.c にある */

extern int R_running_as_main_program; /* ../unix/system.c にある */

int main(int ac, char **av)

{

R_running_as_main_program = 1;

Rf_initialize_R(ac, av);

Rf_mainloop(); /* 戻さない */

return 0;

}

実際、誤解を招く単純さである。R_HOME/bin/exec/Rは実行ファイルのための環境をセット

アップするシェルスクリプト R_HOME/bin/Rから実行され、これは以下に挙げることのために

使われている。

• R_HOMEを設定し、それが適切であるか検査すること。インストールされた shareと doc

へのパス R_SHARE_DIRと R_DOC_DIRに対しても同様である。また必要であれば R_ARCH

を設定する。

1 Mac OS X の用語は dynamic ライブラリであり、R をそのプラットフォームでビルドする通常の方法である。

Page 163: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 157

• Rにリンクする際に使われるディレクトリをインクルードするためにLD_LIBRARY_PATHを

設定すること。これはシェルスクリプト R_HOME/etcR_ARCH/ldpathsに R_LD_LIBRARY_

PATHの初期設定として記録されている。

• 引数のいくつかを処理すること。例えばデバッガでRを実行するため、GUIを提供するために別のフロントエンドを起動するためである。

これらの最初の 2つは R CMDによって Rを実行することにより、フロントエンドで達成することができる。そのため、例えば

R CMD /usr/local/lib/R/bin/exec/R

R CMD exec/R

は両方とも標準的な Rのインストールで動作する。(R CMDは最初に R_HOME/binにある実行

形式ファイルを探す。)もしこの方法でフロントエンドを実行したくないのであれば、R_HOMEが設定され、LD_LIBRARY_PATHが適切なものであることを確実にする必要がある。(後者は存在するだろうが、現代のUnix/Linuxシステムは通常/usr/local/lib(あるアーキテクチャでは/usr/local/lib64)を含んでおらず、Rはシステムコンポーネントのためにそこを見る。)

単純すぎるこの例にある別の意義は、すべての内部の既定値は使用され、制御はRのメインループに引き渡されているということである。tests/Embeddingディレクトリには小さな

例 2が多数ある。これらは src/main/Rembedded.cにある Rf_initEmbeddedRを使っており、

本質的には次のものを使用している。

#include <Rembedded.h>

int main(int ac, char **av)

{

/* セットアップを行う */

Rf_initEmbeddedR(argc, argv);

/* さらにセットアップを行う */

/* run_Rmainloop();を介して対話的に行われ、Rにコードを渡す

擬似コンソールの可能な代替は

R_ReplDLLinit();

while(R_ReplDLLdo1() > 0) {

/* 必要があればユーザアクションを追加 */

}

*/

Rf_endEmbeddedR(0);

/* 最終的には、Rが終了した後に片付ける */

}

もしRの引数を渡したくないということであれば、argv配列を次のようにすることで偽造す

ることができる。

char *argv[]= {"REmbeddedPostgres", "--silent"};

Rf_initEmbeddedR(sizeof(argv)/sizeof(argv[0]), argv);

2 だが、これらは自動化されたテスト手順の一部ではなく、そのためほとんどテストされていない。

Page 164: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 158

しかし GUIを作るために、GUIとやりとりするために Rのさまざまな部分の設定をし、そして Rメインループの中で呼ばれるGUIコールバックの準備をした後に run_Rmainloop

を実行したいと我々は通常は思っている。

注目すべき 1つの問題は、いくつかのプラットフォーム上で、Rf_initEmbeddedRと Rf_

endEmbeddedRが FPUの設定を変えることである (例えばエラーを補足できるようにし、拡張倍精度レジスタを設定する)。

標準的なコードは、R_TempDirが Rf_initEmbeddedRに呼ばれる前にNULLでない値に設定されない限り、通常の方法でセッションの一時ディレクトリを設定する。その場合、値は

既存の書き込み可能なディレクトリを含む (何のチェックもされない)と仮定され、Rがシャットダウンされたときにそれは整理されない。

Rf_initEmbeddedRは R をインタラクティブモードにする: これを変えるため、続いてR_Interactive(Rinterface.hに定義されている)を設定することができる。

Rはロケールのカテゴリ ‘LC_NUMERIC’がその既定値である Cに設定されて動作することが

期待されており、そのためRはロケールのカテゴリを変えてしまうようなアプリケーションにRを組み込むべきではない。

8.1.1 Rライブラリに対するコンパイル

R(共有あるいは静的)ライブラリに対するコンパイルとリンクをするための適切なフラグは次に見ることができる。

R CMD config --cppflags

R CMD config --ldflags

もし Rがインストールされていて、pkg-configは利用可能であり、サブアーキテクチャ

が使われていなければ、共有Rライブラリに対する代替案は

pkg-config --cflags libR

pkg-config --libs libR

であり、静的Rライブラリに対する代替案は次のようになる。

pkg-config --cflags libR

pkg-config --libs --static libR

8.1.2 Rのコールバックの設定

Unix系では Rで使われている文書化された標準的なコールバックの方法を変えることができる公開されたヘッダファイル Rinterface.hがある。これは次のようなポインタを (もしR_INTERFACE_PTRSが定義されていれば)定義している。

extern void (*ptr_R_Suicide)(const char *);

extern void (*ptr_R_ShowMessage)(const char *);

extern int (*ptr_R_ReadConsole)(const char *, unsigned char *, int, int);

extern void (*ptr_R_WriteConsole)(const char *, int);

extern void (*ptr_R_WriteConsoleEx)(const char *, int, int);

extern void (*ptr_R_ResetConsole)();

extern void (*ptr_R_FlushConsole)();

extern void (*ptr_R_ClearerrConsole)();

extern void (*ptr_R_Busy)(int);

extern void (*ptr_R_CleanUp)(SA_TYPE, int, int);

extern int (*ptr_R_ShowFiles)(int, const char **, const char **,

Page 165: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 159

const char *, Rboolean, const char *);

extern int (*ptr_R_ChooseFile)(int, char *, int);

extern int (*ptr_R_EditFile)(const char *);

extern void (*ptr_R_loadhistory)(SEXP, SEXP, SEXP, SEXP);

extern void (*ptr_R_savehistory)(SEXP, SEXP, SEXP, SEXP);

extern void (*ptr_R_addhistory)(SEXP, SEXP, SEXP, SEXP);

これらは標準的なRコールバックがGUIにリダイレクトすることを可能にしている。これらの一般にすることは、ファイル src/unix/system.txtに文書化されている。

[Function]void R_ShowMessage (char *message)これは複数行になるかもしれないメッセージを表示するであろう: すぐにユーザの注意をもたらすはずである。

[Function]void R_Busy (int which)この関数は Rが拡張された計算 (which=1)に乗り出したときやそのような状態が終了した (which=0)ときに、アクション (例えばカーソルの変化のような)を起動する。

[Function]int R_ReadConsole (const char *prompt, unsigned char *buf, intbuflen, int hist)

[Function]void R_WriteConsole (const char *buf, int buflen)[Function]void R_WriteConsoleEx (const char *buf, int buflen, int otype)[Function]void R_ResetConsole ()[Function]void R_FlushConsole ()[Function]void R_ClearErrConsole ()

これらの関数はコンソールと相互に作用する。

R_ReadConsoleはコンソールの与えられたプロンプトに印字し、fgets(3)とする。こ

れはバッファbufに buflen文字までを転送するような操作である。最後の 2バイトはおかしくなるのを防ぐため ‘"\n\0"’に設定される。もし histが非 0であれば、保持されているすべてのコマンド履歴に行が加えられる。返り値が 0であることはどの入力も利用可能でなく、返り値が>0であればはそうでないことになる。

R_WriteConsoleExは与えられたバッファをコンソールに書き出し、otypeは出力の種類を指定する (通常の出力、あるいは警告/エラー)。R_WriteConsole(buf, buflen)

の呼び出しは R_WriteConsoleEx(buf, buflen, 0)と同等である。コールバックの後

方互換性を保証するため、ptr_R_WriteConsoleExは ptr_R_WriteConsoleが NULLに

設定されている場合にのみ使用される。stdout()と stderr()の接続がコンソールを指

すことを保証するため、以下により、対応するファイルを NULLに設定せよ。

R_Outputfile = NULL;

R_Consolefile = NULL;

R_ResetConsoleはシステムがエラーの後にリセットされたときに呼び出される。

R_FlushConsoleは任意の保留中の出力をシステムコンソールにフラッシュする。

R_ClearerrConsoleはコンソールからの読み込みに関連付けられたすべてのエラーを

クリアする。

[Function]int R_ShowFiles (int nfile, const char **file, const char **headers,const char *wtitle, Rboolean del, const char *pager)

この関数はファイルの内容を表示するために利用される。

Page 166: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 160

[Function]int R_ChooseFile (int new, char *buf, int len)ファイルを選択し、その名前を長さ lenの bufに入れて返す。返り値が 0であれば成功、>0であればその他となる。

[Function]int R_EditFile (const char *buf)エディタウィンドウにファイルを送信する。

[Function]SEXP R_loadhistory (SEXP, SEXP, SEXP, SEXP);[Function]SEXP R_savehistory (SEXP, SEXP, SEXP, SEXP);[Function]SEXP R_addhistory (SEXP, SEXP, SEXP, SEXP);

loadhistory、savehistoryと timestampの.Internal関数である。

もしコンソールが履歴の仕組みを持たないのであれば、これらの関数は次のように単

純にすることができる。

SEXP R_loadhistory (SEXP call, SEXP op, SEXP args, SEXP env)

{

errorcall(call, "loadhistory is not implemented");

return R_NilValue;

}

SEXP R_savehistory (SEXP call, SEXP op , SEXP args, SEXP env)

{

errorcall(call, "savehistory is not implemented");

return R_NilValue;

}

SEXP R_addhistory (SEXP call, SEXP op , SEXP args, SEXP env)

{

return R_NilValue;

}

ユーザがコンソールに純粋にタイムスタンプを書き出すため timestampを呼び出すか

もしれないので、R_addhistory関数はもし履歴の仕組みが存在しない場合、黙って返

さなければならない。

[Function]void R_Suicide (const char *message)これはメッセージを表示しつつ、Rをできるだけ早く落とそうとする。次のような実装が可能である。

void R_Suicide (const char *message)

{

char pp[1024];

snprintf(pp, 1024, "Fatal error: %s\n", s);

R_ShowMessage(pp);

R_CleanUp(SA_SUICIDE, 2, 0);

}

[Function]void R_CleanUp (SA TYPE saveact, int status, int RunLast)この関数はシステム終了時に起きる任意のアクションを起動する。これはかなり複雑で

ある必要がある:

#include <Rinterface.h>

#include <Rembedded.h> /* Rf_KillAllDevicesのため */

Page 167: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 161

void R_CleanUp (SA_TYPE saveact, int status, int RunLast)

{

if(saveact == SA_DEFAULT) saveact = SaveAction;

if(saveact == SA_SAVEASK) {

/* 何をするか尋ね、saveactを設定する */

}

switch (saveact) {

case SA_SAVE:

if(runLast) R_dot_Last();

if(R_DirtyImage) R_SaveGlobalEnv();

/* R_HistoryFileにコンソール履歴を保存する */

break;

case SA_NOSAVE:

if(runLast) R_dot_Last();

break;

case SA_SUICIDE:

default:

break;

}

R_RunExitFinalizers();

/* エディタの後始末をする。例えば CleanEd() */

R_CleanTempDir();

/* すべてのグラフィックスデバイスを閉じる */

if(saveact != SA_SUICIDE) Rf_KillAllDevices();

fpu_setup(FALSE);

exit(status);

}

これらのコールバックは実行しているRのセッション内で決して変更してはならない (そして、そのため拡張されたパッケージからこれらのコールバックを呼ぶことはできない)。

8.1.3 シンボルの登録

パッケージの場合のようならそうであろうが、シンボルはRによってロードされる動的ライブラリではないので、Rを組み込んでいるアプリケーションはシンボル登録の異なる方法を必要としている。したがって、.C、.Callなどと使われるシンボルを組み込みアプリケーション登録でき

るよう、Rは特別なDllInfoエントリを用意している。このエントリはgetEmbeddingDllInfo

を呼び出すことにより得ることができるので、一般的な使い方は次のようになる。

DllInfo *info = R_getEmbeddingDllInfo();

R_registerRoutines(info, cMethods, callMethods, NULL, NULL);

cMethodと callMethodsによって定義されるネイティブルーチンは組み込みアプリケー

ションになければならない。一般的なシンボル登録の詳細については Section 5.4 [ネイティブルーチンの登録], page 100を参照せよ。

Page 168: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 162

8.1.4 イベントループのかみ合わせ

Rとフロントエンドを結びつけることで最も難しい問題の 1つは、1つ以上のスレッドが使われているときのイベントループの取り扱いである。Rはイベントとタイマーを次に挙げることで用いている。

• グラフィックスデバイスやデータエディタのような X11ウィンドウを実行することと、それらと相互にやりとりすること (例えば locator()を使うこと)

• tcltkパッケージのTcl/Tkイベントをサポートすること (少なくともTkのX11バージョンのため)。

• 入力の準備。• タイミング操作、例えばRコードのプロファイリングや Sys.sleep()。

• 許可された場所での割り込み。

特に Rの Unix系コマンドライン版は、以下に挙げることのため、個別にイベントループを実行している。

• コンソールコマンドラインでの入力の準備。ファイル src/unix/sys-unix.cにある。

• download.file()内の FTPやHTTPの転送の基礎をなす内部関数で、ソケットからの応答を待つため、そして直接ソケットのアクセスを待つため。ファイル src/modules/

internet/nanoftp.c、src/modules/internet/nanohttp.cと src/modules/

internet/Rsock.cにある。

• X11に基づくデータエントリウィンドウを表示するときのマウスとウィンドウのイベント。ファイル src/modules/X11/dataentry.cにある。これはmodal と見なされ、これがアクティブである間、他のイベントは処理されない。

最初の 2種類のイベントループにはイベントハンドラを加えるための決まりごとが存在している。それはヘッダ R_ext/eventloop.hに宣言されている型と関数を使ったものであり、

ファイル src/unix/sys-std.cにコメントが書かれている。特定のファイル記述子にイベン

ト用の入力ハンドラを加える (あるいは削除する)こと、または (R_wait_usecにより)ポーリング間隔、R_PolledEventsにより定期的に呼ばれる関数を設定することが可能である: ポーリングの仕組みは tcltkパッケージで利用されている。

代替のフロントエンドは入力を待つ一方で他のRのイベントに備えて準備をすること、そして 2つ目のイベントの間に締め出されないことを保証することの両方が必要である。これは既存の例では上手く処理されていない。GNOMEフロントエンドは以下のように設定することで、ポーリングされたイベントに対し、自身のハンドラを実行することができる。

extern int (*R_timeout_handler)();

extern long R_timeout_val;

if (R_timeout_handler && R_timeout_val)

gtk_timeout_add(R_timeout_val, R_timeout_handler, NULL);

gtk_main ();

その一方で、フロントエンドはコンソール入力を待っている。これは明らかにGtk windows(例えば gtkDeviceパッケージのグラフィックデバイス)のイベントを扱い、X11ではないイベント (例えば X11()デバイス)は扱わない。あるいは Rで登録された他のイベントハンドラを扱う。Rがソケットを待っている間、ハンドラは自身が生きているようにしようとはしない。R_timeout_handlerのようなポーリングされたハンドラを追加する機能は tcltkパッケージで使用されている。

Page 169: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 163

8.1.5 スレッドの問題

組み込まれたRはメインスレッドで動作することを意図しており、すべての検査はその状況で行われる。スレッドが関係するスタック検査機構には潜在的な問題がある。これは (CSTACK_DEFNSが定義されている場合)次のように Rinterface.hで宣言された 2つの変数を利用する。

extern uintptr_t R_CStackLimit; /* Cスタックの制限 */

extern uintptr_t R_CStackStart; /* 初期スタックアドレス */

uintptr_tは代わりのものがRで定義されたC99の型であるので、コードではHAVE_UINTPTR_

Tを適切に定義する必要があることに注意。

これらの変数は Rf_initialize_Rが呼び出されたときに、メインスレッドに対して適切な

値に設定する。スタック検査は R_CStackLimit = (uintptr_t)-1と設定することで無効にす

ることができるが、もし可能であれば適切な値に設定するのがよい。(これらが何であるか、どのように決めるかは OS固有であり、スタックサイズの制限はセカンダリスレッドで異なることがある。スタックサイズの選択肢がある場合、少なくとも 8Mbにすることが推奨される。)

どのようにシグナルが処理されるかということを考慮したくなるかもしれない: R はSIGINT、SIGSEGV、SIGPIPE、SIGUSR1と SIGUSR2を含め、いくつかのシグナルに対し

シグナルハンドラを設定しているが、これらは (Rinterface.hに宣言されている) 変数R_SignalHandlersを 0に設定することで、すべて抑えることができる。

これらの変数はRのパッケージによって変えられてはならない: パッケージはセカンダリスレッドのスタック検査機構を使うRの内部を呼び出すべきではない。

8.2 WindowsでRを組み込む

すべての RへのWindowsへのインタフェースは DLLR.dllにあるエントリポイントを直接的、または間接的に呼び出す。単純なアプリケーションは (D)COMを経由して間接的な経路

を使用することが簡単であると分かるかもしれない。

8.2.1 (D)COMを使う

(D)COMはWindowsアプリケーションの間でやりとりするために使われる、標準的なWindowsの仕組みである。あるアプリケーション (ここではR)がクライアント、ここではアプリケーションを呼び出すフロントエンドへサービスを提供する COMサーバとして動作する。サービスは ‘タイプライブラリ’に記述され、それらは (多かれ少なかれ)言語依存であるため、呼び出すアプリケーションはC、C++、Visual Basic、Perlあるいは Pythonなどで書くことができる。クライアントとサーバが異なるマシンで実行することができるように、(D)COMの‘D’は ‘distributed’を指している。

基本的な R ディストリビューションは (D)COM サーバではないが、R と直接接続し、(D)COMサーバを提供する 2つのアドオンが現在利用可能である:

• Thomas Baierによって書かれた StatConnectorと呼ばれる (D)COMサーバが http://

CRAN.R-project.org/other-software.htmlまたは http://sunsite.univie.ac.

at/rcom/から入手可能である。Rグラフィックスウィンドウの組み込みと同様に、これは Rと Rコマンドの遠隔実行でデータの転送を支援するためのパッケージ rscproxy(http://CRAN.R-project.org/package=rscproxy) と一緒に動作する。CRAN上の

rcom (http://CRAN.R-project.org/package=rcom)パッケージは、実行している Rセッションで (D)COMサーバを提供する。

Page 170: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 164

• 別の (D)COMサーバ RDCOMServerは http://www.omegahat.org/から入手できる。そ

の哲学は http://www.omegahat.org/RDCOMServer/Docs/Paradigm.htmlで議論され

ており、このセクションの目的からは大きく異なる。

8.2.2 直接R.dllを呼び出す

RのDLLは主にCで書かれており、_cdeclエントリポイントを持つ。それを直接呼ぶことは

Cコード (あるいは少し注意して C++のコード)からを除きやりにくいであろう。

次の関数を呼び出すUnix系バージョンのインタフェースがある。

int Rf_initEmbeddedR(int ac, char **av);

void Rf_endEmbeddedR(int fatal);

このバージョンはR.dllにあるエントリポイントである。その使用例 (と適切なMakefile.win)は tests/Embeddingディレクトリのソースに見ることができる。RのDLLが見つかるよう、R_HOME/binが PATHにあることを確実にする必要があるだろう。

R.dllを直接呼ぶ例は、以下にコードが与えられた簡素なコマンドラインのフロントエン

ド rtest.cを含め、ディレクトリ src/gnuwin32/front-endsで提供されている。

#define Win32

#include <windows.h>

#include <stdio.h>

#include <Rversion.h>

#define LibExtern __declspec(dllimport) extern

#include <Rembedded.h>

#include <R_ext/RStartup.h>

/* askokと askyesnocancelのため */

#include <graphapp.h>

/* シグナル処理コードのため */

#include <psignal.h>

/* 単純な入力、単純な出力 */

/* このバージョンはすべてのイベントを阻止する: 本物のバージョンでは ProcessEvents

を頻繁に呼び出す必要がある。入力に別々のスレッドを用いるアプローチの一つとして rterm.cと../system.cを参照せよ。

*/

int myReadConsole(const char *prompt, char *buf, int len, int addtohistory)

{

fputs(prompt, stdout);

fflush(stdout);

if(fgets(buf, len, stdin)) return 1; else return 0;

}

void myWriteConsole(const char *buf, int len)

{

printf("%s", buf);

}

void myCallBack(void)

{

/* ProcessEventsの入出力、評価、グラフィックスの間に呼ばれる */

}

void myBusy(int which)

{

Page 171: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 165

/* ビジーカーソルの設定。which = 1で...に、which = 0で設定しない*/

}

static void my_onintr(int sig) { UserBreak = 1; }

int main (int argc, char **argv)

{

structRstart rp;

Rstart Rp = &rp;

char Rversion[25], *RHome;

sprintf(Rversion, "%s.%s", R_MAJOR, R_MINOR);

if(strcmp(getDLLVersion(), Rversion) != 0) {

fprintf(stderr, "Error: R.DLL version does not match\n");

exit(1);

}

R_setStartTime();

R_DefParams(Rp);

if((RHome = get_R_HOME()) == NULL) {

fprintf(stderr, "R_HOME must be set in the environment or Registry\n");

exit(1);

}

Rp->rhome = RHome;

Rp->home = getRUser();

Rp->CharacterMode = LinkDLL;

Rp->ReadConsole = myReadConsole;

Rp->WriteConsole = myWriteConsole;

Rp->CallBack = myCallBack;

Rp->ShowMessage = askok;

Rp->YesNoCancel = askyesnocancel;

Rp->Busy = myBusy;

Rp->R_Quiet = TRUE; /* Default is FALSE */

Rp->R_Interactive = FALSE; /* Default is TRUE */

Rp->RestoreAction = SA_RESTORE;

Rp->SaveAction = SA_NOSAVE;

R_SetParams(Rp);

R_set_command_line_arguments(argc, argv);

FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));

signal(SIGBREAK, my_onintr);

GA_initapp(0, 0);

readconsolecfg();

setup_Rmainloop();

#ifdef SIMPLE_CASE

run_Rmainloop();

#else

R_ReplDLLinit();

while(R_ReplDLLdo1() > 0) {

/* 必要に応じてユーザアクションを追加 */

}

/* ここで EOFだけを取得する (q()ではない) */

#endif

Rf_endEmbeddedR(0);

return 0;

}

Page 172: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 166

意図は次の通り。

• フロントエンドとリンクされた R.dllが一致するか確認する – 他のフロントエンドはより緩い照合を許しているかもしれない。

• Rホームディレクトリとユーザのホームディレクトリの発見と設定。前者はWindowsレジストリから利用可能であるかもしれない: 管理者用インストールからだと HKEY_LOCAL_

MACHINE\Software\R-core\R\InstallPathに、もしインストール中にそれ以外を選択

していれば、HKEY_CURRENT_USER\Software\R-core\R\InstallPathにホームディレク

トリがあるだろう (既定値そのままで)。

• 起動条件とコールバックを Rstart構造体により定義する。R_DefParamsは既定値を、R_

SetParamsは更新した値を設定する。

• R_set_command_line_argumentsで使われるコマンドライン引数を、R の関数

commandArgs()による利用のために記録する。

• シグナルハンドラと基本的なユーザインタフェースを設定する。• おそらく我々のアクションが組み合わさったメインのRループを実行する。

• クリーンアップの手配をする。

根底にあるテーマは GUIを ‘存続した’状態にする必要であり、この例ではそれについては行われていない。Rのコールバック R_ProcessEventsはRのウィンドウ内のWindowsイベントが即座に処理されることを確実にするよう、頻繁に呼ばれる必要がある。逆に、Rは(同じプロセスで動作している)GUIコードが必要に応じて自身を更新することを可能にする必要がある – これを許すため、2つの方法が用意されている:

• Rp->callbackによって登録されたコールバックを R_ProcessEventsが呼ぶ。コードは

次のようになるため、このバージョンはWindows環境下で tcltkという Tcl/Tkに関するパッケージを動作させるために使われる。

void R_ProcessEvents(void)

{

while (peekevent()) doevent(); /* GraphApp用のWindowsのイベント */

if (UserBreak) { UserBreak = FALSE; onintr(); }

R_CallBackHook();

if(R_tcldo) R_tcldo();

}

• メインループは各入力行が処理された後に、呼び出しているアプリケーションが何らかの行動をとることができるよう分割することができる: #ifdef SIMPLE_CASE以下にある

別のコードを参照せよ。

これらはページャ、windows()グラフィックスデバイス、Rのデータ、スクリプトエディタ、そして choose.file()や and select.list()のようなさまざまなポップアップを含むが、ど

のR GraphAppウィンドウも考慮する必要がないかもしれない。これらのすべてを置き換えることは可能であろうが、GraphAppがそれらの大部分を扱えるようにすることがより容易であるように思われる。

シングルスレッド内のGUIでRを実行することは可能であるが (RGui.exeが示すように)、複数スレッドを使うことが通常はより容易 3になる。

3 1990年代後半のスレッドだけを使おうとする試みは、その時点で最も普及しているWindowsであったWindows95の環境下では正しく動作しなかった

Page 173: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 167

R の自身のフロントエンドは 10Mb のスタックサイズを使用しているが、その一方で、MinGWの実行ファイルは既定値で 2Mb、Visual C++の実行ファイルは既定値で 1Mbのスタックサイズを使用していることに注意。後者のスタックサイズは、多くのRアプリケーションに対しては小さすぎるので、一般用途のフロントエンドはより大きなスタックサイズを使

わなければならない。

8.2.3 R HOMEを見つける

Rを組み込むアプリケーションと R(Rscript.exe、Rterm.exeまたは R.exeのように)を起動する systemコールを使うアプリケーションのどちらもRの binディレクトリを見つけるこ

とができる必要がある。そのようにするための最も単純な方法はユーザに環境変数 R_HOMEを

設定するよう依頼しそれを使うことであるが、うぶなユーザはどのように使うか、あるいは

使う価値に関して困惑するかもしれない。

RのWindowsインストーラは長い間、Windowsレジストリに R_HOMEの値を登録するこ

とを可能にしてきた: これは任意であるが、デフォルトでは登録すること選択されていた。R_HOMEの値が登録される場所は、一度に複数のバージョンのRをインストールすることを可能にするため、また、32と 64ビットの Rが同じマシンでインストール可能にするために長年にわたって変わってきた。

基本的なレジストリの位置は Software\R-core\Rである。管理者用インストールに

関しては、これは HKEY_LOCAL_MACHINEの下にあり、64 ビット OS 上で HKEY_LOCAL_

MACHINE\Software\R-core\Rは初期設定で 32ビットアプリケーションへリダイレクトされる。そのため、32ビットアプリケーションは最新の 32ビットインストールの情報を見て、64 ビットアプリケーションは最新の 64 ビットインストールの情報を見ることになる。個人的なインストールでは 32 ビットと 64 ビットのアプリケーションの両方から参照されるHKEY_CURRENT_USER\Software\R-core\R以下に情報があり、どちらか一方の最新のアー

キテクチャを登録する。これを回避するために、常に 1 つのアーキテクチャを参照するSoftware\R-core\R32と Software\R-core\R64という記録位置がある。

Rがインストールされ、登録が無効でないとき、キー InstallPathと Current Versionに

関する 2つの文字列がその位置に書き込まれる。これらのキーはRがアンインストールされたときに取り除かれる。他のインストールのバージョンに関する情報が保持されることを可

能にするために、InstallPathの値に 2.11.0、2.11.0 patchedまたは 2.12.0 Pre-release

のような名前がつけられたキーもある。

つまり、R_HOMEを探索するための包括的なアルゴリズムは、次のようなものになる。

• 個人と管理者のインストールのどちらが優先権を持つかを決める。どちらの方法も議論がある: HKEY_CURRENT_USER\Softwareはしばしば前のバージョンに戻ることがある移動プロファイルであると分かっている。HKEY_CURRENT_USERと HKEY_LOCAL_MACHINEの

片方、または両方に対して以下のことを実行せよ。

• もし望ましいアーキテクチャが既知であれば、Software\R-core\R32または

Software\R-core\R64の中を見る。もしそれが存在しない、あるいはアーキテクチャの

実体がない場合は Software\R-core\Rを見る。

• もしキー InstallPathが存在していれば、それが R_HOMEである (バックスラッシュを使って登録されている)。もしそうでなければ 2.11.0 alphaのようなバージョン固有のキーを

探索し、最新のものを取り出し (それ自身は 2.11.0 patched > 2.11.0 > 2.11.0 alpha

> 2.8.1のような複雑なアルゴリズムである)、それの InstallPathの値を使う。

R 2.12.0より前では、R.dllとさまざまなフロントエンドの実行ファイルは R_HOME\binに

あったが、それらは今では R_HOME\bin\i386または R_HOME\bin\x64にある。そのためアー

Page 174: Rの拡張を書く (R 2.15.2)

Chapter 8: GUIと他のフロントエンドをRと結びつける 168

キテクチャ固有のサブディレクトリの中を最初に見て、次に R_HOME\binを見るように下準備

する必要がある。

Page 175: Rの拡張を書く (R 2.15.2)

関数と変数の索引 169

関数と変数の索引

**Riconv_open . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

.

.C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

.Call . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110, 121

.External . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110, 122

.Fortran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

.Last.lib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

.onAttach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

.onLoad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

.onUnload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

.Random.seed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

\\acronym . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\alias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60\arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62\author . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63\bold . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\cite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\concept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72\cr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66\deqn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70\describe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69\description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60\details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62\dfn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\dontrun . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63\dontshow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63\dots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71\dQuote . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\emph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\enc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72\enumerate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\env . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\eqn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70\examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63\figure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71\file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65\href . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73\ifelse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73\itemize . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\kbd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63\ldots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71\link . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

\method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61\name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59\newcommand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74\note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62\option . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73\pkg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\preformatted . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71\RdOpts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73\references . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62\renewcommand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74\S3method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62\samp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\section . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66\seealso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63\Sexpr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73\source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65\sQuote . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\strong . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67\tabular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69\title . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60\url . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60\value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62\var . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68\verb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Bbessel_i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143bessel_j . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143bessel_k . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143bessel_y . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143beta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143BLAS_LIBS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

CCalloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137CAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123CDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123cgmin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146choose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143CITATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14, 56cPsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

Ddebug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87defineVar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118digamma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

Page 176: Rの拡張を書く (R 2.15.2)

関数と変数の索引 170

dump.frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87duplicate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120dyn.load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98dyn.unload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

Eexp_rand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138expm1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42exportClasses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47exportClassPattern . . . . . . . . . . . . . . . . . . . . . . . . . . 48exportMethods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47exportPattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42, 48

FFALSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145findInterval . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148findVar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118FLIBS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20fmax2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144fmin2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144fprec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144Free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137fround . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144fsign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144ftrunc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

Ggammafn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142gctorture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89getAttrib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116getCharCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134GetRNGstate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

Hhsv2rgb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

Iimax2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144imin2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43importClassesFrom . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48importFrom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43importMethodsFrom . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48install . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116iPsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147ISNA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124, 139ISNAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124, 139

LLAPACK_LIBS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

lbeta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143lbfgsb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146lchoose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143lgamma1p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144lgammafn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142library.dynam . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11, 99log1p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143log1pexp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143log1pmx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143logspace_add . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144logspace_sub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

MM_E . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144M_PI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144mkChar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118mkCharCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134mkCharLen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118mkCharLenCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

NNA_REAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139nmmin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145norm_rand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

OOBJECTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21, 104

Ppentagamma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142PKG_CFLAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104PKG_CPPFLAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104PKG_CXXFLAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104PKG_FCFLAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104PKG_FFLAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104PKG_LIBS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104PKG_OBJCFLAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104prompt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59PROTECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111PROTECT_WITH_INDEX . . . . . . . . . . . . . . . . . . . . . . . . . 113psigamma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142PutRNGstate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

Qqsort3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148qsort4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

RR CMD build . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32R CMD check . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29R CMD config . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18R CMD Rd2pdf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

Page 177: Rの拡張を書く (R 2.15.2)

関数と変数の索引 171

R CMD Rdconv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76R CMD SHLIB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104R CMD Stangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76R CMD Sweave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76R_addhistory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160R_alloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137R_Busy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159R_ChooseFile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160R_CleanUp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160R_ClearErrConsole . . . . . . . . . . . . . . . . . . . . . . . . . . 159R_csort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147R_EditFile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160R_ExpandFileName . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149R_FINITE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139R_FlushConsole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159R_GetCCallable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103R_GetCurrentSrcref . . . . . . . . . . . . . . . . . . . . . . . . . 131R_GetSrcFilename . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131R_INLINE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150R_IsNaN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139R_isort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147R_LIBRARY_DIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19R_loadhistory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160R_max_col . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148R_NegInf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139R_PACKAGE_DIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19R_PACKAGE_NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19R_ParseVector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131R_PosInf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139R_pow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143R_pow_di . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143R_qsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147R_qsort_I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147R_qsort_int . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147R_qsort_int_I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147R_ReadConsole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159R_RegisterCCallable . . . . . . . . . . . . . . . . . . . . . . . . 103R_registerRoutines . . . . . . . . . . . . . . . . . . . . . . . . . 100R_ResetConsole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159R_rsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147R_savehistory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160R_ShowFiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159R_ShowMessage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159R_Srcref . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131R_Suicide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160R_tmpnam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148R_tmpnam2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148R_Version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150R_WriteConsole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159R_WriteConsoleEx . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159Rdqagi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146Rdqags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146Realloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137recover . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88reEnc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

REprintf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139REPROTECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113REvprintf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139revsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147rgb2hsv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148Riconv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149Riconv_close . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149Rprintf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139Rprof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77Rprofmem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80rPsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147rsort_with_index . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147Rvprintf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

SS_alloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137S_realloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137S3method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43SAFE_FFLAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21samin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146seed_in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138seed_out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138setAttrib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116setVar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118sign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96system.time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96system2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

Ttetragamma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89traceback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85tracemem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80translateChar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134translateCharUTF8 . . . . . . . . . . . . . . . . . . . . . . . . . . 134trigamma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142TRUE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

Uundebug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89unif_rand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138UNPROTECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111UNPROTECT_PTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113untracemem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80useDynLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

Vvmaxget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137vmaxset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137vmmin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

Page 178: Rの拡張を書く (R 2.15.2)

概念の索引 172

概念の索引

日本語変数の発見 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118文書中の図 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71文書中の相互参照 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69文書中の数学 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70文書中のリストと表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68変数の設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118文章中のテキストを目立たせる . . . . . . . . . . . . . . . . . . 67属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114文字データを扱う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118総称的関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154積分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146可視性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151メモリ使用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79欠損値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124, 139累積ハザード . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141索引 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72ユーザ定義のマクロ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74メソッド関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154割り込み . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149動的ローディング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98動的なページ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73最適化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145数値微分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127共有オブジェクトの作成 . . . . . . . . . . . . . . . . . . . . . . . 104名前空間 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41リストを扱う . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117条件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73ゼロ点を見つける . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126ソースパッケージのビルド . . . . . . . . . . . . . . . . . . . . . . 32デバッグ中に Rオブジェクトを検査する . . . . . . . . 94デバッグ作業 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92エンコーディング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75ドキュメント . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58オブジェクトのコピー . . . . . . . . . . . . . . . . . . . . . . . . . 120オペレーティングシステムへのアクセス . . . . . . . . . 96ガーベージコレクション . . . . . . . . . . . . . . . . . . . . . . . 111ネイティブルーチンの登録 . . . . . . . . . . . . . . . . . . . . . 100クラス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116バイナリパッケージをビルドする . . . . . . . . . . . . . . . 34パッケージ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2パッケージの構造 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3パッケージのチェック . . . . . . . . . . . . . . . . . . . . . . . . . . 29パッケージのサブディレクトリ . . . . . . . . . . . . . . . . . . 11パッケージを作る . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2パッケージバンドル . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15パッケージビルダー . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32コンパイルされたコードへのインタフェース . . . . 96,

121ビニェット . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35プラットフォーム固有の文書 . . . . . . . . . . . . . . . . . . . . 72プロファイリング . . . . . . . . . . . . . . . . . . . . . . . . . . . 79, 81ストレージの割り当て . . . . . . . . . . . . . . . . . . . . . . . . . 113

.

.install extras ファイル . . . . . . . . . . . . . . . . . . . . . . . . 37

.Rbuildignore ファイル . . . . . . . . . . . . . . . . . . . . . . . . . 32

.Rinstignoreファイル . . . . . . . . . . . . . . . . . . . . . . . . . . 13

\\linkS4class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

BBessel functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143Beta function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

CCの乱数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138, 142Cからの印字 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139Cからのメモリ割り当て . . . . . . . . . . . . . . . . . . . . . . . 137Cからの数値解析サブルーチン . . . . . . . . . . . . . . . . 141Cからの分布関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141Cからのエラー処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . 138Cからのバージョン情報 . . . . . . . . . . . . . . . . . . . . . . . 150Cから Rの式を評価する . . . . . . . . . . . . . . . . . . . . . . 124Cから Rのコードを構文解析する . . . . . . . . . . . . . . 130Cのソート関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147Cで Rのオブジェクトを扱う . . . . . . . . . . . . . . . . . . 110C++コードとのインタフェース . . . . . . . . . . . . . . . . . 105C++ code, interfacing . . . . . . . . . . . . . . . . . . . . . . . . . 105citation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14, 56cleanupファイル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3configureファイル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3CRAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38CRANへの提出 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

DDESCRIPTIONファイル . . . . . . . . . . . . . . . . . . . . . . . 4dynamic pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

Eexternal pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

Ffinalizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132FORTRANでの乱数 . . . . . . . . . . . . . . . . . . . . . . . . . . 140FORTRANからの印字 . . . . . . . . . . . . . . . . . . . . . . . . 140FORTRANからのエラー処理 . . . . . . . . . . . . . . . . . 138FORTRANから Cを呼ぶこととその逆 . . . . . . . . 140

Page 179: Rの拡張を書く (R 2.15.2)

概念の索引 173

GGamma function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

IIEEE特殊値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124, 139INDEXファイル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

LLICENCEファイル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3LICENSEファイル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

OOpenMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23, 150

PProfiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

RRの型の詳細 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

Rコードの整理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Rd書式の処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

Rdファイルの編集 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

SSweave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

Ttar書庫 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

Wweak reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133