# 機能設計書 68-llvm-readtapi

## 概要

本ドキュメントは、LLVM llvm-readtapi ツールの機能設計について記載する。llvm-readtapiは、TAPI（Text-based API）ファイルの読み込み、変換、比較を行うツールである。

### 本機能の処理概要

llvm-readtapiは、Apple社のTAPIファイル（.tbdファイル）を読み込み、各種操作を行うツールである。TAPIファイルは動的ライブラリのAPIインターフェースをテキスト形式で記述したもので、SDKのサイズ削減やビルド時間の短縮に使用される。

**業務上の目的・背景**：macOSおよびiOSのSDK開発において、TAPIファイルは実際のdylibの代替として使用される。llvm-readtapiは、これらのTAPIファイルの読み込み、変換、マージ、比較などの操作を提供する。

**機能の利用シーン**：
- TAPIファイルのフォーマット変換（TBD v3/v4/v5間）
- 複数TAPIファイルのマージ
- TAPIファイル間の差分比較
- dylibからTAPIファイル（スタブ）の生成
- 特定アーキテクチャの抽出・除去

**主要な処理内容**：
1. 読み込み/書き出し: TAPIファイルの読み込みと指定フォーマットでの出力
2. --compare: 2つのTAPIファイルの比較
3. --merge: 複数TAPIファイルのマージ
4. --stubify: dylibからTAPIスタブの生成
5. --extract / --remove: アーキテクチャの抽出/除去

**関連システム・外部連携**：LLVM TextAPI ライブラリ

**権限による制御**：特になし（ファイルシステムへのアクセス権限のみ必要）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLIツール | 主機能 | コマンドラインインターフェースによる操作 |

## 機能種別

ファイル変換 / メタデータ操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| 入力ファイル | string[] | Yes | TAPIファイル、dylib、ユニバーサルバイナリ | - |
| -o | string | No | 出力ファイルパス | - |
| --compare | flag | No | 2つのファイルを比較 | 入力2つ必須 |
| --merge | flag | No | 複数ファイルをマージ | 入力2つ以上必須 |
| --stubify | flag | No | dylibからスタブ生成 | - |
| --extract | flag | No | 指定アーキテクチャを抽出 | --arch必須 |
| --remove | flag | No | 指定アーキテクチャを除去 | --arch必須 |
| --arch | arch | No | 対象アーキテクチャ | 有効なアーキテクチャ名 |
| --filetype | type | No | 出力フォーマット（tbd-v3/v4/v5） | tbd-v3以上 |
| --compact | flag | No | コンパクト出力 | - |
| --ignore-arch | arch | No | 比較時に無視するアーキテクチャ | 有効なアーキテクチャ名 |
| --delete-input | flag | No | スタブ化後に入力を削除 | --stubify時のみ |
| --delete-private-libraries | flag | No | プライベートライブラリを削除 | --stubify時のみ |
| -t | flag | No | 処理されたライブラリをトレース | --stubify時のみ |

### 入力データソース

- TAPIファイル（.tbdファイル）
- Mach-O動的ライブラリ（.dylib）
- ユニバーサルバイナリ
- ディレクトリ（--stubify時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| TAPIファイル | テキスト | YAML形式のTBDファイル |
| 比較結果 | テキスト | 差分情報 |

### 出力先

- 標準出力（-o未指定時）
- 指定ファイル（-oオプション指定時）
- 入力と同じディレクトリ（--stubify時、拡張子.tbd）

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数解析
   └─ TAPIOptTable.parseArgs()

2. 入力ファイルの読み込み
   └─ getInterfaceFile()
       ├─ identify_magic()でフォーマット判定
       ├─ DylibReader::get() [dylib/スタブ]
       └─ TextAPIReader::get() [TAPIファイル]

3. アクションに応じた処理
   ├─ アクション未指定: handleWriteAction()
   ├─ --compare: handleCompareAction()
   ├─ --merge: handleMergeAction()
   ├─ --extract: handleSingleFileAction(extract)
   ├─ --remove: handleSingleFileAction(remove)
   └─ --stubify: handleStubifyAction()

4. 結果の出力
   └─ TextAPIWriter::writeToStream()
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[引数解析]
    B --> C{アクション?}
    C -->|なし| D[handleWriteAction]
    C -->|compare| E[handleCompareAction]
    C -->|merge| F[handleMergeAction]
    C -->|extract| G[handleSingleFileAction extract]
    C -->|remove| H[handleSingleFileAction remove]
    C -->|stubify| I[handleStubifyAction]
    D --> J[TextAPIWriter出力]
    E --> K[DiffEngine比較]
    F --> L[InterfaceFile.merge]
    L --> J
    G --> J
    H --> J
    I --> M[stubifyImpl/stubifyDirectory]
    M --> J
    J --> N[終了]
    K --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-68-1 | 単一アクション | 複数のアクションは同時に指定できない | 常時 |
| BR-68-2 | 比較は2ファイル | --compareは2つの入力ファイルが必須 | --compare時 |
| BR-68-3 | マージは2ファイル以上 | --mergeは2つ以上の入力ファイルが必須 | --merge時 |
| BR-68-4 | extract/removeはarch必須 | --extract/--removeは--archオプションが必須 | --extract/--remove時 |
| BR-68-5 | TBD v3未満は非対応 | 出力フォーマットはtbd-v3以上のみ | --filetype指定時 |
| BR-68-6 | ディレクトリスタブ化 | ディレクトリ指定時は再帰的に処理 | --stubify時 |

### 計算ロジック

特になし

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

該当なし（データベースを使用しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 2 | NON_TAPI_EXIT_CODE | TAPI操作以外のエラー | エラーメッセージを表示し終了 |
| - | ファイルタイプ不正 | サポートしていないファイル形式 | エラーメッセージを表示し終了 |
| - | 入力ファイル数不正 | compareに2ファイル以外を指定 | エラーメッセージを表示し終了 |
| - | アーキテクチャ不正 | 無効なアーキテクチャ名を指定 | エラーメッセージを表示し終了 |
| - | フォーマット不正 | 非対応の出力フォーマット | エラーメッセージを表示し終了 |

### リトライ仕様

なし

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

該当なし

## パフォーマンス要件

特に定義なし

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

- 入力ファイルへの読み取りアクセス権限が必要
- 出力ファイルへの書き込みアクセス権限が必要
- --delete-input使用時は入力ファイルの削除権限が必要

## 備考

- TAPIファイルはYAML形式で記述される
- TBD v5が最新のフォーマット（デフォルト）
- シンボリックリンクの処理にも対応

---

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

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

### 推奨読解順序

#### Step 1: データ構造とコンテキストを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | StubOptions構造体（70-74行目） |
| 1-2 | llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | CompareOptions構造体（76-78行目） |
| 1-3 | llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | Context構造体（80-88行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | main関数（490-581行目） |

**主要処理フロー**:
1. **497-498行目**: TAPIOptTable.parseArgs()で引数解析
2. **551-555行目**: アクション未指定時はhandleWriteAction()
3. **566-578行目**: アクションに応じた処理分岐

#### Step 3: 各アクション処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | handleWriteAction関数（196-206行目） |
| 3-2 | llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | handleCompareAction関数（159-194行目） |
| 3-3 | llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | handleMergeAction関数（208-223行目） |
| 3-4 | llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | handleStubifyAction関数（438-464行目） |

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

```
main()
    │
    ├─ TAPIOptTable.parseArgs()
    │
    ├─ [アクション未指定]
    │      └─ handleWriteAction()
    │             └─ TextAPIWriter::writeToStream()
    │
    ├─ [--compare]
    │      └─ handleCompareAction()
    │             ├─ getInterfaceFile() x2
    │             └─ DiffEngine.compareFiles()
    │
    ├─ [--merge]
    │      └─ handleMergeAction()
    │             ├─ getInterfaceFile() xN
    │             ├─ InterfaceFile::merge()
    │             └─ handleWriteAction()
    │
    ├─ [--extract/--remove]
    │      └─ handleSingleFileAction()
    │             ├─ getInterfaceFile()
    │             ├─ InterfaceFile::extract/remove()
    │             └─ handleWriteAction()
    │
    └─ [--stubify]
           └─ handleStubifyAction()
                  ├─ [ファイル] stubifyImpl()
                  └─ [ディレクトリ] stubifyDirectory()
```

### データフロー図

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

TAPIファイル ──┐
              ├──▶ getInterfaceFile()
dylib ────────┤         │
              │         ▼
ユニバーサル ──┘   InterfaceFile
                        │
                        ▼
              ┌─────────┴─────────┐
              │                   │
        [読み込み]            [操作]
              │                   │
              │         ┌─────────┼─────────┐
              │         │         │         │
              ▼         ▼         ▼         ▼
           write     compare    merge   stubify
              │         │         │         │
              └─────────┴─────────┴─────────┘
                              │
                              ▼
                    TextAPIWriter.writeToStream()
                              │
                              ▼
                         出力ファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| llvm-readtapi.cpp | `llvm/tools/llvm-readtapi/llvm-readtapi.cpp` | ソース | メインプログラム |
| DiffEngine.h | `llvm/tools/llvm-readtapi/DiffEngine.h` | ヘッダ | 比較エンジン |
| DiffEngine.cpp | `llvm/tools/llvm-readtapi/DiffEngine.cpp` | ソース | 比較エンジン実装 |
| TapiOpts.td | `llvm/tools/llvm-readtapi/TapiOpts.td` | 定義 | コマンドラインオプション定義 |
| CMakeLists.txt | `llvm/tools/llvm-readtapi/CMakeLists.txt` | ビルド | ビルド設定 |
