# 機能設計書 59-llvm-rc

## 概要

本ドキュメントは、LLVMプロジェクトにおけるllvm-rcツールの機能設計を記述する。llvm-rcは、Windowsリソーススクリプト（.rc）をコンパイルしてリソースファイル（.res）またはCOFFオブジェクトファイルを生成するツールである。

### 本機能の処理概要

llvm-rcは、Microsoft rc.exeのクロスプラットフォーム互換ツールとして、Windowsリソーススクリプトをコンパイルする。リソースファイルには、アイコン、カーソル、メニュー、ダイアログ、文字列テーブルなどのGUIリソースが含まれる。また、windres互換モードも備えており、GNUツールチェーンからの移行も容易である。

**業務上の目的・背景**：Windowsアプリケーションの開発において、リソーススクリプトのコンパイルは必須のステップである。従来のrc.exeはWindowsでのみ動作するため、クロスコンパイル環境やCI/CD環境で問題となる。llvm-rcは、Linux/macOS上でもWindowsリソースをコンパイル可能にし、クロスプラットフォーム開発を支援する。

**機能の利用シーン**：
- Windows GUIアプリケーションのビルド
- クロスコンパイル環境でのWindowsリソース処理
- MinGW/Cygwin環境でのwindres代替
- CI/CDパイプラインでのリソースコンパイル

**主要な処理内容**：
1. リソーススクリプトのプリプロセス（clangを使用）
2. スクリプトのトークン化とパース
3. 各リソースタイプの処理
4. .resファイルまたはCOFFオブジェクトの生成

**関連システム・外部連携**：
- Clangプリプロセッサとの連携
- WindowsResourceパーサーとの連携

**権限による制御**：本ツールはファイルシステムへの読み書きアクセスと、外部プロセス（clang）の実行権限を必要とする。

## 関連画面

本ツールはCLI（コマンドラインインターフェース）ツールであり、GUI画面は存在しない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | コマンドライン | 主画面 | 入力ファイル、オプションの指定 |

## 機能種別

コンパイル処理 / リソース変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| InputFile | string | Yes | リソーススクリプトファイル（.rc） | ファイルが存在すること |
| /FO | string | No | 出力ファイル名 | - |
| /I | list<string> | No | インクルードディレクトリ | - |
| /D | list<string> | No | プリプロセッサ定義 | - |
| /U | list<string> | No | プリプロセッサ定義解除 | - |
| /no-preprocess | bool | No | プリプロセスをスキップ | - |
| /V | bool | No | 詳細出力モード | - |
| /C | int | No | コードページ指定 | - |
| /L | int | No | 言語ID指定 | - |
| /N | bool | No | 文字列リソースにNULL終端を追加 | - |
| /Y | bool | No | ドライラン（出力しない） | - |
| /X | bool | No | INCLUDEパスを無視 | - |

### 入力データソース

- リソーススクリプトファイル（.rc）
- インクルードファイル（ヘッダー等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ResourceFile | file | コンパイル済みリソースファイル（.res） |
| ObjectFile | file | COFFオブジェクトファイル（windresモード時） |

### 出力先

- 指定された出力ファイル（デフォルト: 入力ファイル名.res）

## 処理フロー

### 処理シーケンス

```
1. オプション解析
   └─ rcモードとwindresモードを判定
2. 入力形式判定
   ├─ .rc: リソーススクリプト
   └─ .res: 既存リソースファイル
3. プリプロセス（.rc入力時）
   └─ clangを呼び出してプリプロセス
4. トークン化・パース
   └─ ResourceScriptParserでスクリプト解析
5. リソース処理
   └─ ResourceFileWriterで各リソースを処理
6. 出力生成
   ├─ .res: リソースファイル出力
   └─ COFF: doCvtresでオブジェクト変換
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[オプション解析]
    B --> C{windresモード?}
    C -->|Yes| D[parseWindresOptions]
    C -->|No| E[parseRcOptions]
    D --> F{入力形式?}
    E --> F
    F -->|.rc| G[プリプロセス]
    F -->|.res| H[直接読み込み]
    G --> I[トークン化]
    I --> J[パース]
    J --> K[ResourceFileWriter]
    K --> L{出力形式?}
    H --> L
    L -->|.res| M[.res出力]
    L -->|COFF| N[doCvtres]
    M --> O[終了]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | モード自動判定 | 実行ファイル名からrc/windresモードを判定 | 常時 |
| BR-02 | プリプロセッサ検索 | clangを検索してプリプロセスに使用 | プリプロセス有効時 |
| BR-03 | コードページ | デフォルトはWindows-1252、UTF-8もサポート | 常時 |
| BR-04 | 言語ID | デフォルトは英語（en-US, 0x0409） | 常時 |
| BR-05 | 出力拡張子推論 | 入力ファイル拡張子から出力拡張子を推論 | 出力ファイル未指定時 |

### 計算ロジック

リソースコンパイル：
1. Cプリプロセッサでマクロ展開
2. ResourceScriptTokenizerでトークン化
3. ResourceScriptParserでASTに変換
4. ResourceFileWriterで各リソースをバイナリ化

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

本ツールはデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | 入力エラー | 入力ファイルが存在しない | ファイルパスを確認 |
| 1 | プリプロセスエラー | clangが見つからない | --no-preprocessを使用 |
| 1 | パースエラー | スクリプト構文エラー | スクリプトを修正 |
| 1 | 出力エラー | 出力ファイル作成失敗 | パスと権限を確認 |

### リトライ仕様

リトライ処理は実装されていない。

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

該当なし（ファイル入出力処理）。

## パフォーマンス要件

ビルド時間に影響するため、合理的な速度での処理が期待される。

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

- 外部プログラム（clang）を実行するため、信頼できるパスを使用
- 入力ファイルの検証を実施

## 備考

- Microsoft rc.exe互換とGNU windres互換の両方をサポート
- サポートするコードページは0（ACP）、1252、65001（UTF-8）

---

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

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

### 推奨読解順序

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

リソースコンパイルに使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ResourceScriptStmt.h | `llvm/tools/llvm-rc/ResourceScriptStmt.h` | リソース文のAST定義 |
| 1-2 | ResourceScriptToken.h | `llvm/tools/llvm-rc/ResourceScriptToken.h` | トークン定義 |

**読解のコツ**: RCTokenがトークン、各種Resource系クラスがリソース文を表す。

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

処理の起点となるmain関数を読み解く。

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

**主要処理フロー**:
1. **742-752行目**: オプション解析とモード判定
2. **754-766行目**: 入力形式に応じた処理分岐
3. **600-686行目**: doRc関数 - リソースコンパイル本体
4. **688-738行目**: doCvtres関数 - COFF変換

#### Step 3: オプション解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | llvm-rc.cpp | `llvm/tools/llvm-rc/llvm-rc.cpp` | parseRcOptions（507-587行目） |
| 3-2 | llvm-rc.cpp | `llvm/tools/llvm-rc/llvm-rc.cpp` | parseWindresOptions（350-505行目） |
| 3-3 | llvm-rc.cpp | `llvm/tools/llvm-rc/llvm-rc.cpp` | isWindres（296-307行目） |

#### Step 4: プリプロセス処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | llvm-rc.cpp | `llvm/tools/llvm-rc/llvm-rc.cpp` | preprocess関数（236-294行目） |
| 4-2 | llvm-rc.cpp | `llvm/tools/llvm-rc/llvm-rc.cpp` | findClang関数（133-165行目） |

#### Step 5: リソースコンパイルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ResourceScriptParser.cpp | `llvm/tools/llvm-rc/ResourceScriptParser.cpp` | パース実装 |
| 5-2 | ResourceFileWriter.cpp | `llvm/tools/llvm-rc/ResourceFileWriter.cpp` | 出力実装 |

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

```
llvm_rc_main()
    │
    ├─ isWindres()
    ├─ getOptions()
    │      ├─ parseWindresOptions()
    │      └─ parseRcOptions()
    │
    ├─ doRc()
    │      ├─ preprocess()
    │      │      └─ findClang()
    │      │             └─ sys::ExecuteAndWait()
    │      │
    │      ├─ MemoryBuffer::getFile()
    │      ├─ filterCppOutput()
    │      ├─ tokenizeRC()
    │      ├─ RCParser::parseSingleResource() [ループ]
    │      └─ ResourceFileWriter
    │             └─ Resource::visit()
    │
    └─ doCvtres()
           ├─ WindowsResource::createWindowsResource()
           ├─ WindowsResourceParser::parse()
           └─ writeWindowsResourceCOFF()
```

### データフロー図

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

.rcファイル     ───▶ preprocess()        ───▶ プリプロセス済み
                        │
                        ▼
                  tokenizeRC()
                        │
                        ▼
                  RCParser
                        │
                        ▼
                  ResourceFileWriter  ───▶ .resファイル
                        │
                        ▼
                  [COFF出力時]
                  doCvtres()          ───▶ .objファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| llvm-rc.cpp | `llvm/tools/llvm-rc/llvm-rc.cpp` | ソース | メインエントリーポイント |
| ResourceScriptParser.cpp | `llvm/tools/llvm-rc/ResourceScriptParser.cpp` | ソース | パーサー実装 |
| ResourceScriptParser.h | `llvm/tools/llvm-rc/ResourceScriptParser.h` | ヘッダー | パーサー定義 |
| ResourceScriptToken.cpp | `llvm/tools/llvm-rc/ResourceScriptToken.cpp` | ソース | トークナイザー |
| ResourceScriptToken.h | `llvm/tools/llvm-rc/ResourceScriptToken.h` | ヘッダー | トークン定義 |
| ResourceScriptStmt.cpp | `llvm/tools/llvm-rc/ResourceScriptStmt.cpp` | ソース | 文AST実装 |
| ResourceScriptStmt.h | `llvm/tools/llvm-rc/ResourceScriptStmt.h` | ヘッダー | 文AST定義 |
| ResourceFileWriter.cpp | `llvm/tools/llvm-rc/ResourceFileWriter.cpp` | ソース | 出力実装 |
| ResourceFileWriter.h | `llvm/tools/llvm-rc/ResourceFileWriter.h` | ヘッダー | 出力定義 |
| ResourceScriptCppFilter.cpp | `llvm/tools/llvm-rc/ResourceScriptCppFilter.cpp` | ソース | プリプロセス出力フィルタ |
| ResourceVisitor.h | `llvm/tools/llvm-rc/ResourceVisitor.h` | ヘッダー | ビジターパターン定義 |
| Opts.td | `llvm/tools/llvm-rc/Opts.td` | TableGen | rcオプション定義 |
| WindresOpts.td | `llvm/tools/llvm-rc/WindresOpts.td` | TableGen | windresオプション定義 |
