# 帳票設計書 17-mruby-strip 出力

## 概要

本ドキュメントは、mruby-stripコマンドによるIREPバイナリからデバッグ情報セクションを除去した軽量バイナリの再出力機能の設計仕様を記述する。

### 本帳票の処理概要

mruby-stripコマンドは、mrbcで生成されたIREPバイナリファイル(.mrb)を読み込み、デバッグ情報セクション(DBGセクション)を除去した状態で同じファイルに再書き込みする。オプションでローカル変数情報セクション(LVARセクション)も除去できる。

**業務上の目的・背景**：mrbcコマンドの-gオプションでコンパイルされたmrbファイルにはデバッグ情報(ファイル名、行番号等)が含まれる。本番デプロイや組み込み環境ではデバッグ情報は不要であり、ファイルサイズの削減が求められる。mruby-stripはバイナリからこれらの不要なセクションを除去することで、軽量なバイナリを生成する。UNIXのstripコマンドに相当するmruby専用のツールである。

**帳票の利用シーン**：mrbcで-gオプション付きでコンパイルされたmrbファイルから、デプロイ用にデバッグ情報を除去する場面で使用される。CI/CDパイプラインでのビルド最適化や、組み込みデバイスへのデプロイ前の軽量化に利用される。

**主要な出力内容**：
1. デバッグ情報セクション(DBG)が除去されたIREPバイナリ
2. オプション(-l/--lvar)でローカル変数セクション(LVAR)も除去可能
3. 出力はRiteBinaryフォーマット(.mrb)に準拠

**帳票の出力タイミング**：mruby-stripコマンドをコマンドラインから実行した時点で、入力ファイルを上書きして出力される。

**帳票の利用者**：mrubyアプリケーションのビルド・デプロイ担当者、CI/CDパイプライン

## 帳票種別

バイナリダンプ(ファイル出力)

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | コンソール/ターミナル | N/A | mruby-strip [options] irepfiles |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | RiteBinaryフォーマット(.mrb) |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | 入力ファイルと同名(上書き) |
| 出力方法 | ファイルへの直接書き込み(fwrite) |
| 文字コード | バイナリ(エンコーディングなし) |

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

出力されるmrbファイルはRiteBinaryフォーマットに準拠し、以下の構造を持つ。デバッグ情報セクションが除去された状態で出力される。

```
┌─────────────────────────────────────┐
│ RiteBinary Header (24 bytes)        │
│ - RITE識別子 (4 bytes)              │
│ - バージョン (4 bytes)              │
│ - バイナリサイズ (4 bytes)          │
│ - コンパイラ情報 (8 bytes)          │
├─────────────────────────────────────┤
│ IREP Section                        │
│ - セクション識別子 "IREP" (4 bytes) │
│ - セクションサイズ (4 bytes)        │
│ - Rite VMバージョン (4 bytes)       │
│ - 命令列データ                      │
├─────────────────────────────────────┤
│ [除去] DBG Section ← strip対象      │
├─────────────────────────────────────┤
│ [除去] LVAR Section ← -lオプション時│
├─────────────────────────────────────┤
│ END Footer (8 bytes)                │
│ - "END\0" (4 bytes)                 │
│ - セクションサイズ (4 bytes)        │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | バイナリ識別子 | "RITE" | RITE_BINARY_IDENT | 4バイト固定 |
| 2 | メジャーバージョン | "04" | RITE_BINARY_MAJOR_VER | 2バイト |
| 3 | マイナーバージョン | "00" | RITE_BINARY_MINOR_VER | 2バイト |
| 4 | バイナリサイズ | 全体サイズ(バイト) | 計算値 | 4バイトBigEndian |
| 5 | コンパイラ名 | "MATZ" | RITE_COMPILER_NAME | 4バイト |
| 6 | コンパイラバージョン | "0000" | RITE_COMPILER_VERSION | 4バイト |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | IREPセクション | 命令列(オペコード)データ | 入力ファイルのIREPセクション | バイナリ | 可変 |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | ENDフッター | "END\0" + セクションサイズ | RITE_BINARY_EOF | 8バイト |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 入力ファイル | 有効なmrbバイナリファイルが指定されていること | Yes |
| MRB_NO_STDIO未定義 | MRB_NO_STDIOが定義されている場合はビルドエラー | Yes |
| ファイルアクセス権 | 入力ファイルの読み書き権限があること | Yes |

### ソート順

N/A (バイナリデータのため順序は入力依存)

### 改ページ条件

N/A

## データベース参照仕様

### 参照テーブル一覧

N/A

### テーブル別参照項目詳細

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| flagsパラメータ | デフォルト: 0 (デバッグ情報除去のみ) | N/A | MRB_DUMP_DEBUG_INFO(=1)が含まれないことでDBGセクションを除去 |
| flagsパラメータ(-l) | MRB_DUMP_NO_LVAR (=4) | N/A | -l指定時にLVARセクションも除去 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[mruby-strip コマンド実行] --> B{引数チェック}
    B -->|引数なし| C[エラー: no files to strip]
    B -->|引数あり| D[parse_args でオプション解析]
    D --> E{オプション解析成功?}
    E -->|失敗| F[print_usage 表示]
    E -->|成功| G[mrb_open_core でmrb_state生成]
    G --> H[strip 関数呼び出し]
    H --> I[各ファイルに対してループ]
    I --> J[fopen rb で読み込み]
    J --> K[mrb_read_irep_file でIREP読み込み]
    K --> L{読み込み成功?}
    L -->|失敗| M[エラー: can't read irep file]
    L -->|成功| N[fclose 読み込みファイル]
    N --> O[fopen wb で書き込み用に再オープン]
    O --> P[mrb_dump_irep_binary で再出力]
    P --> Q{書き込み成功?}
    Q -->|失敗| R[エラー: error occurred during dumping]
    Q -->|成功| S[fclose / mrb_irep_decref]
    S --> T{次のファイルあり?}
    T -->|Yes| I
    T -->|No| U[mrb_close / EXIT_SUCCESS]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 引数なし | argc <= 1 | "no files to strip" + usage | コマンドライン引数にファイルを指定 |
| オプション不正 | 不明なオプションが指定された場合 | usage表示 | 正しいオプション(-l/--lvar)を使用 |
| 読み込み失敗 | fopenが失敗(ファイル不在/権限不足) | "can't open file for reading {filename}" | ファイルパス・パーミッションを確認 |
| IREP読み込み失敗 | mrb_read_irep_fileがNULLを返す(不正フォーマット) | "can't read irep file {filename}" | 有効なmrbファイルを指定 |
| 書き込み失敗 | fopenが失敗(権限不足) | "can't open file for writing {filename}" | ファイルの書き込み権限を確認 |
| ダンプ失敗 | mrb_dump_irep_binaryがMRB_DUMP_OK以外を返す | "error occurred during dumping {filename}" | ディスク容量等を確認 |
| mrb_state初期化失敗 | mrb_open_coreがNULLを返す | "Invalid mrb_state, exiting mruby-strip" | メモリを確保 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | コマンドライン引数で複数ファイル指定可能 |
| 目標出力時間 | ファイルI/O依存(通常は即時) |
| 同時出力数上限 | N/A (順次処理) |

## セキュリティ考慮事項

- 入力ファイルを直接上書きするため、誤操作による元ファイルの破損リスクがある
- mrb_open_coreを使用しており、最小限のmruby実行環境のみ初期化(gemなし)
- 不正なmrbファイルの入力に対しては、mrb_read_irep_fileがNULLを返すことで保護される

## 備考

- mruby-stripはmrb_open_core()を使用しており、フルのmruby環境ではなく最小限のコア環境のみを初期化する。これにより起動が高速でメモリ使用量も少ない
- strip関数内でmrb_dump_irep_binaryを呼び出す際、flagsパラメータにMRB_DUMP_DEBUG_INFO(=1)を含めないことで、デバッグ情報セクションが出力から除外される
- -l/--lvarオプションでMRB_DUMP_NO_LVAR(=4)フラグを追加すると、ローカル変数情報セクション(LVAR)も除去される
- 依存gem: mruby-compiler
- RiteBinaryフォーマットのバージョン: メジャー"04"、マイナー"00"

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

RiteBinaryフォーマットとIREP構造体を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dump.h | `include/mruby/dump.h` | rite_binary_header構造体(行72-79)、MRB_DUMP_*フラグ(行19-22) |
| 1-2 | dump.h | `include/mruby/dump.h` | セクション識別子(行64-66): IREP/DBG/LVAR、rite_binary_footer(行106-108) |
| 1-3 | dump.h | `include/mruby/dump.h` | エラーコード定義(行39-45): MRB_DUMP_OK等 |
| 1-4 | irep.h | `include/mruby/irep.h` | mrb_irep構造体の定義 |

**読解のコツ**: RiteBinaryはヘッダー + 複数セクション(IREP/DBG/LVAR) + フッター(END)の構成。strip処理はDBGセクションとオプションでLVARセクションを除去する。MRB_DUMP_DEBUG_INFO(=1)フラグが設定されていない場合、mrb_dump_irep_binary関数はDBGセクションを出力しない。

#### Step 2: エントリーポイントを理解する

mruby-stripコマンドのmain関数から処理フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mruby_strip.c | `mrbgems/mruby-bin-strip/tools/mruby-strip/mruby_strip.c` | main関数(行110-139) |
| 2-2 | mruby_strip.c | `mrbgems/mruby-bin-strip/tools/mruby-strip/mruby_strip.c` | parse_args関数(行29-61) |

**主要処理フロー**:
1. **行118-122**: argc <= 1の場合はエラー("no files to strip")
2. **行124-128**: parse_argsでオプション解析(-l/--lvar → MRB_DUMP_NO_LVAR)
3. **行129-133**: mrb_open_core()でmrb_state初期化(失敗時はエラー終了)
4. **行135**: strip関数呼び出し
5. **行137-138**: mrb_close()とreturn

#### Step 3: strip処理コアを理解する

strip関数の実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mruby_strip.c | `mrbgems/mruby-bin-strip/tools/mruby-strip/mruby_strip.c` | strip関数(行63-108) |

**主要処理フロー**:
- **行76 (strip)**: fopen(filename, "rb")で入力ファイルを読み込みモードで開く
- **行82 (strip)**: mrb_read_irep_file(mrb, rfile)でIREPを読み込み
- **行89 (strip)**: fopen(filename, "wb")で同じファイルを書き込みモードで再オープン
- **行97 (strip)**: mrb_dump_irep_binary(mrb, irep, args->flags, wfile)で再出力。flagsにMRB_DUMP_DEBUG_INFO(=1)が含まれないため、DBGセクションが除去される
- **行99-100 (strip)**: fclose、mrb_irep_decrefでリソース解放
- **行102-105 (strip)**: dump_result != MRB_DUMP_OKの場合はエラー出力

#### Step 4: mrb_dump_irep_binary関数を理解する

strip関数から呼び出されるダンプ関数の概要を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | dump.c | `src/dump.c` | mrb_dump_irep_binary関数(行913-932) |

**主要処理フロー**:
- **行923 (dump.c)**: mrb_dump_irep()で内部バッファにバイナリ生成(flagsに基づきセクション選択)
- **行925 (dump.c)**: fwrite()でバッファをファイルに出力

### プログラム呼び出し階層図

```
main (mruby_strip.c:110)
    |
    +-- parse_args (mruby_strip.c:29)
    |      +-- -l/--lvar → MRB_DUMP_NO_LVAR設定
    |
    +-- mrb_open_core()  ※最小限のmruby環境
    |
    +-- strip (mruby_strip.c:63)
    |      |
    |      +-- [各ファイルに対してループ]
    |             |
    |             +-- fopen(filename, "rb")  ← 読み込み
    |             +-- mrb_read_irep_file(mrb, rfile)
    |             +-- fclose(rfile)
    |             |
    |             +-- fopen(filename, "wb")  ← 書き込み(上書き)
    |             +-- mrb_dump_irep_binary(mrb, irep, flags, wfile)
    |             |      +-- mrb_dump_irep(mrb, irep, flags, &bin, &bin_size)
    |             |      +-- fwrite(bin, 1, bin_size, wfile)
    |             +-- fclose(wfile)
    |             +-- mrb_irep_decref(mrb, irep)
    |
    +-- mrb_close(mrb)
```

### データフロー図

```
[入力]                    [処理]                         [出力]

mrbファイル        mrb_read_irep_file()
(IREP+DBG+LVAR) ──> (全セクション読み込み)
                          |
                    mrb_dump_irep_binary()
                    (flags=0: DBG除去)
                    (flags=4: DBG+LVAR除去)
                          |
                    fwrite() ──────────────> mrbファイル(上書き)
                                             (IREP + END)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mruby_strip.c | `mrbgems/mruby-bin-strip/tools/mruby-strip/mruby_strip.c` | ソース | mruby-stripコマンドのメイン実装(main/parse_args/strip関数) |
| dump.h | `include/mruby/dump.h` | ヘッダ | RiteBinaryフォーマット定義、MRB_DUMP_*フラグ/エラーコード |
| dump.c | `src/dump.c` | ソース | mrb_dump_irep_binary関数(バイナリダンプ実装) |
| irep.h | `include/mruby/irep.h` | ヘッダ | mrb_irep構造体定義 |
| mrbgem.rake | `mrbgems/mruby-bin-strip/mrbgem.rake` | 設定 | gem仕様、依存関係(mruby-compiler)、bin定義(mruby-strip) |
| mruby_strip.rb | `mrbgems/mruby-bin-strip/bintest/mruby_strip.rb` | テスト | 統合テスト(ファイルなし/ファイル不在/不正形式/正常/DBG除去/LVAR除去) |
