# 機能設計書 89-ビルド構成

## 概要

本ドキュメントは、mrubyのビルドシステム全体の設計を記述する。Rakefileを起点としたビルドパイプライン、ビルド構成の管理、ツールチェーンの抽象化、クロスコンパイル対応、プリシンボル（presym）生成、テスト・ベンチマーク・インストールのタスク体系を含む。

### 本機能の処理概要

**業務上の目的・背景**：mrubyは組み込み用途を含む多様なプラットフォーム向けにビルドされる。ホストビルドとクロスビルドの両方をサポートし、ツールチェーン（gcc/clang/visualcpp）の自動検出、gem依存関係の解決、コード生成（gem_init.c, mrblib.c, presymヘッダ）を統合的に管理するビルドシステムが必要である。

**機能の利用シーン**：`rake`コマンドによるmrubyのビルド、テスト、インストール。`build_config.rb`による構成カスタマイズ。クロスコンパイル構成の定義。

**主要な処理内容**：
1. ビルド構成の読み込みと初期化（Rakefile, build_config）
2. ツールチェーン自動検出と設定（gcc/clang/visualcpp）
3. gem依存関係の解決とセットアップ
4. コアソースのコンパイルとライブラリ生成（libmruby.a, libmruby_core.a）
5. mrblib Rubyコードのコンパイルとirep生成
6. gem_init.c自動生成による全gemの初期化コード生成
7. プリシンボル（presym）のスキャンとヘッダ生成
8. バイナリのビルドとインストーラ生成
9. テスト・ベンチマークタスクの定義
10. LEGAL文書の自動生成
11. ロックファイルによるgem依存バージョン固定

**関連システム・外部連携**：Ruby（Rake）、C/C++コンパイラ、リンカ、アーカイバ、yacc、gperf、git

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLI | ビルド結果表示 | rake実行時のビルドサマリー出力 |

## 機能種別

ビルドシステム

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| MRUBY_CONFIG / CONFIG | 環境変数 | No | ビルド構成ファイルパス | ファイル存在チェック |
| MRUBY_BUILD_DIR | 環境変数 | No | ビルド出力ディレクトリ（デフォルト: build/） | - |
| INSTALL_DIR | 環境変数 | No | インストール先ディレクトリ（デフォルト: bin/） | - |
| PREFIX / INSTALL_PREFIX | 環境変数 | No | インストールプレフィックス（デフォルト: /usr/local） | - |
| DESTDIR | 環境変数 | No | インストール先ルート | - |
| CC / CXX | 環境変数 | No | Cコンパイラの指定 | ツールチェーン推定に使用 |

### 入力データソース

- `build_config/default.rb` または `MRUBY_CONFIG`で指定されたビルド構成ファイル
- `mrbgems/`以下の各gemのmrbgem.rakeファイル
- `*.gembox`ファイル（gemのグループ定義）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| libmruby.a | ファイル | mrubyメインライブラリ |
| libmruby_core.a | ファイル | mrubyコアライブラリ（gems除外） |
| mrbc | 実行ファイル | mrubyコンパイラ |
| mruby | 実行ファイル | mrubyインタプリタ |
| mirb | 実行ファイル | mruby REPL |
| mrbtest | 実行ファイル | テストランナー |
| gem_init.c | 生成コード | gem初期化コード |
| mrblib.c | 生成コード | mrblibコンパイル済みコード |
| presym_id.h / presym_table.h | ヘッダ | プリシンボル定義 |
| LEGAL | テキスト | ライセンス文書 |
| *.lock | YAML | ロックファイル |
| libmruby.flags.mak | Makefile | 外部利用向けフラグ定義 |

### 出力先

`build/{target_name}/` ディレクトリ以下

## 処理フロー

### 処理シーケンス

```
1. Rakefile読み込み
   ├─ MRUBY_ROOT設定
   ├─ lib/mruby/build.rb読み込み
   ├─ MRUBY_CONFIG取得（環境変数 or デフォルト）
   ├─ build_config読み込み・実行
   │   └─ MRuby::Build.new ブロック実行
   │       ├─ ツールチェーン設定
   │       ├─ gembox/gem読み込み
   │       └─ オプション設定（debug, test, bintest等）
   ├─ gems.setup(self) で全gemセットアップ
   └─ define_rules で全ターゲットのコンパイルルール定義

2. タスクファイル読み込み
   ├─ tasks/core.rake    → コアソースのオブジェクトファイル定義
   ├─ tasks/mrblib.rake  → mrblib.c生成定義
   ├─ tasks/mrbgems.rake → gem_init.c/LEGAL生成定義
   ├─ tasks/libmruby.rake → libmruby.a/libmruby_core.a生成定義
   ├─ tasks/bin.rake     → バイナリビルド・インストーラ定義
   ├─ tasks/presym.rake  → プリシンボル生成定義
   ├─ tasks/test.rake    → テストタスク定義
   ├─ tasks/benchmark.rake → ベンチマークタスク定義
   ├─ tasks/install.rake → インストールタスク定義
   └─ tasks/amalgam.rake → アマルガメーション定義

3. rake all（デフォルトタスク）
   ├─ gensymタスク → presymヘッダ生成
   ├─ buildタスク → 全ターゲットのproductsをビルド
   ├─ ビルドサマリー出力
   └─ Lockfile.write
```

### フローチャート

```mermaid
flowchart TD
    A[rake起動] --> B[build_config読込]
    B --> C{ターゲット種別?}
    C -->|host| D[MRuby::Build.new]
    C -->|cross| E[MRuby::CrossBuild.new]
    D --> F[ツールチェーン設定]
    E --> F
    F --> G[gem/gembox読込]
    G --> H[gems.setup - 依存解決]
    H --> I[define_rules]
    I --> J[gensym - presym生成]
    J --> K[コアソースコンパイル]
    K --> L[mrblib.c生成・コンパイル]
    L --> M[gem_init.c生成・コンパイル]
    M --> N[libmruby.a/libmruby_core.aアーカイブ]
    N --> O[バイナリリンク]
    O --> P[インストーラ生成]
    P --> Q[ビルドサマリー出力]
    Q --> R[Lockfile書込]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-89-1 | ツールチェーン自動検出 | CC環境変数→clang判定、プラットフォーム判定（darwin/bsd→clang, cygwin→gcc, VS環境→visualcpp）の順で検出 | ツールチェーン未指定時 |
| BR-89-2 | ビルド構成探索 | MRUBY_CONFIG → CONFIG → ./build_config.rb → build_config/default.rbの優先順で探索 | ビルド開始時 |
| BR-89-3 | mrbc自動生成 | host buildまたはmruby-bin-mrbcが含まれる場合、内部mrbc buildを自動生成 | libmruby有効かつ外部mrbc未指定時 |
| BR-89-4 | CXX例外対応 | gem内にC++ソース(.cpp/.cxx/.cc)が存在する場合、自動的にC++例外を有効化 | gem読み込み時 |
| BR-89-5 | gem初期化順序 | TSort（トポロジカルソート）による依存関係順で初期化 | gem_init.c生成時 |
| BR-89-6 | presymスキャン | 全オブジェクトの前処理ファイル(.pi)をスキャンしてシンボルを収集 | gensymタスク実行時 |
| BR-89-7 | LEGAL自動生成 | MITライセンス本文＋各gemのライセンス・著者情報を集約 | ビルド時 |
| BR-89-8 | ロックファイル | gem依存のURLと{branch, commit}をYAMLで固定 | lock有効時 |

### 計算ロジック

特になし

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------
| - | RuntimeError | ツールチェーンが見つからない | "Unknown {name} toolchain" |
| - | RuntimeError | gem依存が見つからない | "The GEM '{name}' depends on the GEM '{dep}' but it could not be found" |
| - | RuntimeError | gem循環依存 | "Circular mrbgem dependency found" (TSort::Cyclic) |
| - | RuntimeError | gemバージョン不一致 | "{name} version should be..." |
| - | RuntimeError | gemコンフリクト | "Conflicts of gem '{name}' found" |
| - | RuntimeError | mrbc未解決 | "external mrbc or mruby-bin-mrbc gem...is required" |
| - | RuntimeError | gem必須フィールド欠落 | "{name} required to set name, license(s) and author(s)" |
| - | RuntimeError | CXX例外の重複設定 | "cxx_exception already enabled" / "cxx_exception disabled" |
| - | RuntimeError | gembox未発見 | "Can't find gembox '{gembox}'" |

### リトライ仕様

該当なし

## トランザクション仕様

- GCアリーナのsave/restoreによる各gem初期化のメモリ管理
- mrb_final_mrbgemsでgem終了処理をmrb_protect_errorで保護

## パフォーマンス要件

特になし

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

- git cloneでのdepth 1による浅いクローン（commit指定がない場合）
- ロックファイルによるcommitハッシュ固定で再現性を保証
- gembox/gem読み込み時にinstance_evalによるRubyコード実行が行われるため、信頼できるソースのみを使用すること

## 備考

- Windows環境ではバッチファイルラッパー(.bat)が生成される
- クロスビルドではホストビルドのmrbcを自動的に使用する
- presymによりシンボルテーブルの事前解決が行われ、実行時のシンボル探索が高速化される
- `rake deep_clean`でgem_clone_dirも含めた完全クリーンが可能
- ビルドサマリーでは各ビルドターゲットの名前、出力ディレクトリ、含まれるgem一覧が表示される
- `compile_as_cxx`によりCソースをC++としてコンパイル可能（vm.c, error.c, gc.c）

---

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

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

### 推奨読解順序

#### Step 1: ビルドシステムのエントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Rakefile | `Rakefile` | MRUBY_ROOT設定（3行目）、build.rb読み込み（13行目）、MRUBY_CONFIG取得（16-17行目）、タスクファイルの読み込み順序（30-40行目）、デフォルトタスク定義（44-56行目） |

**読解のコツ**: Rakefileはmrubyビルドの起点。`MRuby::Build.mruby_config_path`でビルド構成ファイルのパスを決定し、`load MRUBY_CONFIG`で構成を実行する。その後、各タスクファイルを順次読み込む。`task :all`（46-56行目）がデフォルトビルドの実体で、`:gensym`→`:build`→サマリー表示→ロックファイル書込の流れ。

#### Step 2: ビルド構成クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | build.rb | `lib/mruby/build.rb` | MRuby::Buildクラス（56-561行目）：initialize（94-162行目）でコンパイラ・リンカ等全コマンドオブジェクト生成、ツールチェーン検出（Toolchain.guess, 31-41行目）、create_mrbc_build（537-560行目）で内部mrbcビルド自動生成 |
| 2-2 | build.rb | `lib/mruby/build.rb` | MRuby::CrossBuild（563-615行目）：CrossBuild#initializeでホストビルド自動生成（573-580行目） |

**読解のコツ**: `MRuby::Build.new`のブロック内で`conf.toolchain`、`conf.gembox`、`conf.gem`等を呼び出す。ブロック終了後にensure節（157-161行目）で`create_mrbc_build`と`Presym.new`が実行される。`@products`配列にビルド成果物が登録され、`task :build`がこれらに依存する。

#### Step 3: ビルド構成ファイルの例を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | default.rb | `build_config/default.rb` | ビルド構成の基本パターン（1-83行目）：toolchain呼出（3行目）、gembox指定（17行目）、enable_bintest/enable_test（81-82行目） |

**読解のコツ**: build_config/default.rbはコメント付きのテンプレート的ファイル。実際に有効なのは`conf.toolchain`、`conf.gembox 'default'`、`conf.enable_bintest`、`conf.enable_test`の4行のみ。コメント部分がコンパイラ・リンカ等の全カスタマイズオプションを示している。

#### Step 4: コード生成タスクを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | core.rake | `tasks/core.rake` | コアソースのコンパイル（1-12行目）、CXX例外有効時のcompile_as_cxx対応（5-6行目） |
| 4-2 | mrblib.rake | `tasks/mrblib.rake` | mrblib.c生成（4-28行目）：mrblib/*.rbをmrbcでコンパイルし、mrb_init_mrblib関数を生成 |
| 4-3 | mrbgems.rake | `tasks/mrbgems.rake` | gem_init.c生成（11-93行目）：全gemのGENERATED_TMP関数を配列化し、mrb_init_mrbgems/mrb_final_mrbgemsを生成 |
| 4-4 | presym.rake | `tasks/presym.rake` | presymスキャン（34-44行目）：全.piファイルからシンボルを収集し、id/tableヘッダを生成 |

**主要処理フロー**:
- **mrbgems.rake 11-93行目**: gem_init.cの生成。gem_func_gemsからinit/final関数の宣言・テーブルを構築。`mrb_init_mrbgems`関数でforループによる順次初期化。`mrb_final_mrbgems`でmrb_protect_errorによる安全な逆順終了処理。`mrb_state_atexit`で終了時コールバック登録。
- **mrbgems.rake 108-151行目**: LEGAL文書の自動生成。各gemのauthors/licensesを集約。

#### Step 5: ライブラリ生成・インストールを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | libmruby.rake | `tasks/libmruby.rake` | libmruby_core.a生成（2-4行目）、libmruby.a生成（11-14行目）、ヘッダ公開タスク（16-37行目）、flags.mak生成（39-87行目） |
| 5-2 | bin.rake | `tasks/bin.rake` | バイナリビルド（1-23行目）：gemのbinsからexeを生成しインストーラ定義 |
| 5-3 | install.rake | `tasks/install.rake` | システムインストール（1-40行目）：PREFIX/DESTDIR対応、install:full/install:bin |

#### Step 6: テストタスクを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | test.rake | `tasks/test.rake` | テストタスク構成（1-84行目）：test:build:lib、test:run:lib、test:run:binの依存関係。各ターゲットでmrbtestのビルドと実行。 |

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

```
Rakefile
    |
    +-- lib/mruby/build.rb
    |     +-- MRuby::Build.new(name, &block)
    |     |     +-- Toolchain.guess / toolchain(name)
    |     |     +-- gembox(gemboxfile) [LoadGems]
    |     |     |     +-- gem(gem_src) [LoadGems]
    |     |     |           +-- GemLoader.new.fetch!
    |     |     |           +-- load mrbgem.rake
    |     |     +-- create_mrbc_build
    |     |     +-- Presym.new
    |     |
    |     +-- MRuby::CrossBuild.new(name, &block)
    |           +-- super (Build.new)
    |           +-- 自動host build生成
    |
    +-- gems.setup(self)
    |     +-- Gem::List#setup
    |     |     +-- each(&:setup)  [Gem::Specification#setup]
    |     |     +-- setup_dependencies
    |     +-- Gem::List#check
    |           +-- generate_gem_table
    |           +-- tsort_dependencies (TSort)
    |           +-- setup_compilers
    |           +-- import_include_paths
    |
    +-- define_rules
    |
    +-- tasks/core.rake      → libmruby_core_objs
    +-- tasks/mrblib.rake    → mrblib.c → objfile
    +-- tasks/mrbgems.rake   → gem_init.c → objfile, LEGAL
    +-- tasks/libmruby.rake  → libmruby_core.a, libmruby.a, flags.mak
    +-- tasks/bin.rake       → exefiles, installers
    +-- tasks/presym.rake    → presym_id.h, presym_table.h
    +-- tasks/test.rake      → test:build, test:run
    +-- tasks/install.rake   → install:full, install:bin
```

### データフロー図

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

build_config.rb ──────────▶ MRuby::Build.new ──────────▶ ターゲット定義
                                    |
*.gembox ─────────────────▶ gembox() ──────────────────▶ gem一覧
                                    |
mrbgem.rake ──────────────▶ gem() → GemLoader.fetch! ──▶ Gem::Specification
                                    |
                              gems.setup()
                                    |
                           ┌────────┼────────┐
                           ▼        ▼        ▼
                     core.rake  mrblib.rake  mrbgems.rake
                        |          |            |
src/*.c ──────────▶  compile    mrblib.c    gem_init.c
                        |       generate    generate
                        ▼          ▼            ▼
                    obj files   obj file    obj file
                        |          |            |
                        └──────────┴────────────┘
                                    |
                              libmruby.rake
                                    |
                           ┌────────┴────────┐
                           ▼                 ▼
                    libmruby_core.a     libmruby.a
                                             |
                                        bin.rake
                                             |
                                    ┌────────┴────────┐
                                    ▼                 ▼
                              mrbc, mruby,      install.rake
                              mirb, mrbtest          |
                                                     ▼
                                              /usr/local/bin/
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Rakefile | `Rakefile` | ビルド | ビルドエントリーポイント、タスク定義 |
| build.rb | `lib/mruby/build.rb` | ライブラリ | MRuby::Build/CrossBuild/Toolchainクラス定義 |
| load_gems.rb | `lib/mruby/build/load_gems.rb` | ライブラリ | gem/gembox読み込み、GemLoader、GemCheckout |
| lockfile.rb | `lib/mruby/lockfile.rb` | ライブラリ | ロックファイル管理 |
| default.rb | `build_config/default.rb` | 設定 | デフォルトビルド構成 |
| core.rake | `tasks/core.rake` | タスク | コアソースコンパイル |
| mrblib.rake | `tasks/mrblib.rake` | タスク | mrblib.c生成 |
| mrbgems.rake | `tasks/mrbgems.rake` | タスク | gem_init.c/LEGAL生成 |
| libmruby.rake | `tasks/libmruby.rake` | タスク | libmruby.a生成 |
| bin.rake | `tasks/bin.rake` | タスク | バイナリビルド |
| presym.rake | `tasks/presym.rake` | タスク | プリシンボルヘッダ生成 |
| test.rake | `tasks/test.rake` | タスク | テストタスク定義 |
| install.rake | `tasks/install.rake` | タスク | インストールタスク定義 |
