# 機能設計書 32-llvm-ar

## 概要

本ドキュメントは、LLVM llvm-arツールの機能設計を記述する。llvm-arは、アーカイブ（静的ライブラリ）の作成・管理を行うユーティリティであり、GNU arおよびranlibの互換ツールとして機能する。

### 本機能の処理概要

llvm-arは、オブジェクトファイルをアーカイブ（.aファイル）にまとめて静的ライブラリを作成・管理するツールである。アーカイブへのメンバー追加、削除、置換、抽出、一覧表示などの操作を提供する。

**業務上の目的・背景**：静的ライブラリは、複数のオブジェクトファイルを単一のファイルにまとめ、リンク時に必要なシンボルのみを取り込むことでビルドプロセスを効率化する。llvm-arは、LLVMツールチェインの一部として、GNU binutilsに依存せずに静的ライブラリの作成・管理を可能にする。クロスプラットフォーム開発やLLVMベースのビルドシステムにおいて重要なツールである。

**機能の利用シーン**：プロジェクトビルド時の静的ライブラリ作成、既存ライブラリへのオブジェクト追加・更新、ライブラリ内容の確認、シンボルテーブル（インデックス）の生成・更新、ライブラリからの特定オブジェクト抽出などで利用される。

**主要な処理内容**：
1. コマンドライン引数の解析と操作の決定
2. アーカイブファイルの読み込みまたは新規作成
3. 指定された操作（追加/削除/置換/抽出/表示）の実行
4. シンボルテーブルの生成（ranlibモード）
5. アーカイブファイルの書き出し

**関連システム・外部連携**：LLVM Archive/ArchiveWriterライブラリを使用。また、llvm-ranlibとして実行した場合はシンボルテーブル作成専用モードで動作。llvm-libとして実行した場合はMicrosoft lib.exe互換モードで動作。

**権限による制御**：ファイルシステムの読み書き権限に依存。-Dオプションでuid/gid/タイムスタンプを0に設定し決定的なアーカイブを生成可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLI | 主画面 | コマンドライン実行による全機能の制御 |

## 機能種別

アーカイブ操作 / ファイル管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| operation | char | Yes | 操作種別（d/m/p/q/r/s/t/x） | 単一操作のみ許可 |
| archive | string | Yes | アーカイブファイル名 | - |
| members | string[] | No | メンバーファイル名リスト | 操作により必須 |
| [a] | modifier | No | relposの後に配置 | m/r操作時のみ |
| [b]/[i] | modifier | No | relposの前に配置 | m/r操作時のみ |
| [c] | modifier | No | アーカイブ新規作成時の警告抑制 | - |
| [D] | modifier | No | 決定的モード（タイムスタンプ/uid/gid=0） | デフォルト有効 |
| [U] | modifier | No | 非決定的モード（実際の値を使用） | -Dと排他 |
| [o] | modifier | No | 抽出時に元の日時を保持 | x操作時のみ |
| [O] | modifier | No | メンバーオフセット表示 | t操作時のみ |
| [P] | modifier | No | フルパス名でマッチング | - |
| [s] | modifier | No | シンボルテーブル作成 | - |
| [S] | modifier | No | シンボルテーブル作成しない | -sと排他 |
| [T] | modifier | No | thinアーカイブ作成（非推奨） | --thin推奨 |
| [u] | modifier | No | 新しいファイルのみ更新 | r操作時のみ |
| [v] | modifier | No | 詳細出力 | - |
| [L] | modifier | No | アーカイブ内容を追加 | q操作時のみ |
| [N] | modifier | No | N番目のインスタンスを指定 | count引数必要 |
| --format | string | No | アーカイブ形式 | default/gnu/darwin/bsd/bigarchive/coff |
| --thin | flag | No | thinアーカイブ作成 | - |
| --output | string | No | 抽出先ディレクトリ | x操作時のみ |
| -M | flag | No | MRIスクリプトモード | - |
| -X | string | No | オブジェクトモード（AIX用） | 32/64/32_64/any |

### 入力データソース

- アーカイブファイル（既存の場合）
- メンバーファイル（オブジェクトファイル、ビットコードファイル等）
- MRIスクリプト（-Mオプション時、標準入力から）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| アーカイブファイル | binary | 生成/更新されたアーカイブ |
| 抽出ファイル | binary | x操作で抽出されたメンバーファイル |
| メンバー一覧 | text | t操作での一覧出力 |
| メンバー内容 | text | p操作での内容出力 |

### 出力先

- アーカイブファイル（指定パス）
- 抽出ファイル（--output指定ディレクトリまたはカレントディレクトリ）
- 標準出力（t/p操作時）

## 処理フロー

### 処理シーケンス

```
1. ツール名の判定
   └─ ar/ranlib/lib/dlltoolを判定
2. コマンドライン引数の解析
   └─ 操作コードとモディファイアを解析
3. MRIスクリプトモードの処理（-M指定時）
   └─ 標準入力からスクリプトを読み込み実行
4. アーカイブファイルの読み込み
   └─ 既存ファイルの場合はメモリにロード
5. 操作の実行
   └─ 読み込み操作（p/t/x）または書き込み操作（d/m/q/r/s）
6. アーカイブファイルの書き出し
   └─ 書き込み操作の場合、更新されたアーカイブを出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{ツール名判定}
    B -->|ar| C[ar_main]
    B -->|ranlib| D[ranlib_main]
    B -->|lib| E[libDriverMain]
    B -->|dlltool| F[dlltoolDriverMain]
    C --> G[parseCommandLine]
    D --> H[CreateSymTab操作]
    G --> I{MRIモード?}
    I -->|Yes| J[runMRIScript]
    I -->|No| K[performOperation]
    J --> L[終了]
    K --> M{操作種別}
    M -->|Print| N[doPrint]
    M -->|DisplayTable| O[doDisplayTable]
    M -->|Extract| P[doExtract]
    M -->|Delete/Move/QuickAppend/ReplaceOrInsert| Q[performWriteOperation]
    M -->|CreateSymTab| R[createSymbolTable]
    N --> L
    O --> L
    P --> L
    Q --> L
    R --> L
    H --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 単一操作制約 | 一度のコマンド実行で指定できる操作は1つのみ | 常時 |
| BR-02 | 位置指定制約 | a/b/iモディファイアは1つのみ指定可能 | m/r操作時 |
| BR-03 | 決定的モードデフォルト | -Dがデフォルトで有効（uid/gid/timestamp=0） | 常時 |
| BR-04 | Thinアーカイブパス | Thinアーカイブでは-Pが暗黙的に有効 | --thin指定時 |
| BR-05 | フォーマット自動検出 | 既存アーカイブ更新時は元のフォーマットを維持 | --format未指定時 |
| BR-06 | シンボルテーブル自動生成 | デフォルトでシンボルテーブルを生成 | -S未指定時 |

### 計算ロジック

特になし

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

該当なし（ファイル操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | 引数エラー | 操作が指定されていない | エラーメッセージ出力して終了 |
| 1 | 引数エラー | 複数の操作が指定された | エラーメッセージ出力して終了 |
| 1 | 引数エラー | アーカイブ名が指定されていない | エラーメッセージ出力して終了 |
| 1 | ファイルエラー | アーカイブファイルが開けない | エラーメッセージ出力して終了 |
| 1 | ファイルエラー | メンバーファイルが見つからない | エラーメッセージ出力して終了 |
| 1 | フォーマットエラー | 不正なアーカイブ形式 | エラーメッセージ出力して終了 |

### リトライ仕様

リトライ処理なし（即時終了）

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

該当なし（アトミックなファイル操作）

## パフォーマンス要件

特に規定なし。アーカイブサイズおよびメンバー数に比例した処理時間。

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

- -Dオプション（決定的モード）により再現可能なビルドをサポート
- パスの正規化による意図しないファイルアクセス防止

## 備考

- GNU arとの互換性を重視した実装
- 複数の実行名（llvm-ar/llvm-ranlib/llvm-lib/llvm-dlltool）で異なる動作
- AIX Big Archiveフォーマットをサポート

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Archive.h | `llvm/include/llvm/Object/Archive.h` | Archive, Archive::Child クラス構造 |
| 1-2 | ArchiveWriter.h | `llvm/include/llvm/Object/ArchiveWriter.h` | NewArchiveMember構造体とwriteArchive関数 |

**読解のコツ**: ArchiveはMemoryBufferベースでアーカイブを読み込み、ArchiveWriterでNewArchiveMemberのベクタから新しいアーカイブを生成する設計。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | llvm-ar.cpp | `llvm/tools/llvm-ar/llvm-ar.cpp` | llvm_ar_main関数がエントリーポイント |

**主要処理フロー**:
1. **1512-1541行目**: llvm_ar_main()でツール名判定
2. **1531-1538行目**: dlltool/ranlib/lib/arの分岐
3. **1338-1423行目**: ar_main()でar本体処理

#### Step 3: コマンドライン解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | llvm-ar.cpp | `llvm/tools/llvm-ar/llvm-ar.cpp` | parseCommandLine関数 |

**主要処理フロー**:
- **313-487行目**: parseCommandLine()で操作とモディファイアを解析
- **333-429行目**: 各オプション文字の処理（d/m/p/q/r/t/x/c/o/P/s/S/u/v/a/b/i/D/U/N/T/L）
- **449-486行目**: 操作とモディファイアの組み合わせ検証

#### Step 4: 各操作の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | llvm-ar.cpp | `llvm/tools/llvm-ar/llvm-ar.cpp` | performReadOperation, performWriteOperation |

**主要処理フロー**:
- **692-743行目**: performReadOperation() - Print/DisplayTable/Extract
- **1007-1082行目**: performWriteOperation() - Delete/Move/QuickAppend/ReplaceOrInsert
- **491-499行目**: doPrint() - メンバー内容出力
- **513-553行目**: doDisplayTable() - メンバー一覧表示
- **577-626行目**: doExtract() - メンバー抽出
- **909-1005行目**: computeNewArchiveMembers() - 新アーカイブメンバー計算

#### Step 5: MRIスクリプト処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | llvm-ar.cpp | `llvm/tools/llvm-ar/llvm-ar.cpp` | runMRIScript関数 |

**主要処理フロー**:
- **1184-1273行目**: runMRIScript() - MRIスクリプトの各コマンド処理
- **1207-1215行目**: コマンド判定（AddLib/AddMod/Create/CreateThin/Delete/Save/End）

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

```
llvm_ar_main()
    │
    ├─ dlltoolDriverMain() [dlltoolモード]
    ├─ ranlib_main() [ranlibモード]
    │      └─ performOperation(CreateSymTab)
    ├─ libDriverMain() [libモード]
    └─ ar_main() [arモード]
           │
           ├─ parseCommandLine()
           │      ├─ getRelPos()
           │      ├─ getCountParam()
           │      └─ getArchive()
           │
           ├─ runMRIScript() [-Mモード]
           │      └─ performOperation(ReplaceOrInsert)
           │
           └─ performOperation()
                  ├─ performReadOperation()
                  │      ├─ doPrint()
                  │      ├─ doDisplayTable()
                  │      └─ doExtract()
                  │
                  ├─ performWriteOperation()
                  │      ├─ computeNewArchiveMembers()
                  │      └─ writeArchive()
                  │
                  └─ createSymbolTable()
```

### データフロー図

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

アーカイブファイル ───▶ Archive::create() ───▶ Archive オブジェクト
      │                      │
      │                      ▼
メンバーファイル ───▶ NewArchiveMember生成 ───▶ メンバーリスト
      │                      │
      │                      ▼
操作指定 ──────────▶ computeNewArchiveMembers() ───▶ 新メンバーリスト
                             │
                             ▼
                      writeArchive() ───▶ 新アーカイブファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| llvm-ar.cpp | `llvm/tools/llvm-ar/llvm-ar.cpp` | ソース | メイン処理、全操作の実装 |
| Archive.h | `llvm/include/llvm/Object/Archive.h` | ヘッダ | Archiveクラス定義 |
| Archive.cpp | `llvm/lib/Object/Archive.cpp` | ソース | Archiveクラス実装 |
| ArchiveWriter.h | `llvm/include/llvm/Object/ArchiveWriter.h` | ヘッダ | アーカイブ書き込みAPI |
| ArchiveWriter.cpp | `llvm/lib/Object/ArchiveWriter.cpp` | ソース | アーカイブ書き込み実装 |
| LibDriver.h | `llvm/include/llvm/ToolDrivers/llvm-lib/LibDriver.h` | ヘッダ | lib.exe互換ドライバ |
| DlltoolDriver.h | `llvm/include/llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h` | ヘッダ | dlltool互換ドライバ |
