# 機能設計書 80-標準ライブラリパス検出

## 概要

本ドキュメントは、serve-dにおける標準ライブラリパス検出ユーティリティの設計を記述する。D言語の標準ライブラリパス（druntime・phobos）をコンパイラの設定ファイルや環境変数から自動検出するユーティリティモジュールである。

### 本機能の処理概要

**業務上の目的・背景**：D言語の開発環境ではdruntime（ランタイムライブラリ）とphobos（標準ライブラリ）のインポートパスが必要であり、DCDやD-Scannerによるコード解析にはこれらのパスが不可欠である。本ユーティリティは、DMD/LDC/GDCのコンパイラ設定ファイルを解析し、標準ライブラリパスを自動検出することで、ユーザーの手動設定を不要にする。

**機能の利用シーン**：serve-dの初期化時に`d.stdlibPath`設定が`auto`に設定されている場合に呼び出される。コンパイラのパスから設定ファイルを探索し、DFLAGSの`-I`オプションからインポートパスを抽出する。

**主要な処理内容**：
1. 標準ライブラリパス自動検出（autoDetectStdlibPaths）：コンパイラ種別を判定し適切な検出メソッドを呼び出す
2. DMD設定ファイル解析（detectDMDStdlibPaths）：dmd.conf/sc.iniからインポートパスを抽出
3. LDC設定ファイル解析（detectLDCStdlibPaths）：ldc2.confからインポートパスを抽出
4. DFLAGS解析（parseDflagsImports）：DFLAGSの`-I`オプションからインポートパスを抽出
5. PATH検索（searchPathFor）：PATH環境変数からコンパイラの実行可能ファイルを検索

**関連システム・外部連携**：DMDコンパイラの設定ファイル（dmd.conf/sc.ini）、LDCコンパイラの設定ファイル（ldc2.conf）、ファイルシステム、PATH環境変数。

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

## 関連画面

本ユーティリティは直接的に画面と関連しない。初期化時やDCDのインポートパス設定時に間接的に使用される。

## 機能種別

ユーティリティ / 環境検出

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cwd (autoDetectStdlibPaths) | string | No | 現在の作業ディレクトリ | - |
| compilerPath (autoDetectStdlibPaths) | string | No | コンパイラの実行可能ファイルパス | - |
| confPath (parseDmdConfImports) | string | Yes | 設定ファイルのパス | ファイルが存在すること |
| confDirPath | string | Yes | 設定ファイルのディレクトリパス | - |
| options (parseDflagsImports) | string | Yes | DFLAGSオプション文字列 | - |
| executable (searchPathFor) | string | Yes | 検索する実行可能ファイル名 | - |

### 入力データソース

- コンパイラの設定ファイル（dmd.conf、sc.ini、ldc2.conf）
- PATH環境変数
- HOME環境変数
- ファイルシステム

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| string[] (autoDetectStdlibPaths) | string[] | 検出されたインポートパスの配列（druntime/import, phobos） |
| bool (detectDMDStdlibPaths) | bool | 検出に成功したかどうか |
| string (searchPathFor) | string | 見つかった実行可能ファイルのフルパス、見つからなければnull |

### 出力先

serve-dの初期化処理、DCDコンポーネントのインポートパス設定

## 処理フロー

### 処理シーケンス

```
1. コンパイラ種別判定
   └─ コンパイラパスのバイナリ名からdmd/ldc/gdcを判定
2. コンパイラ固有の検出
   └─ DMD: dmd.conf/sc.iniを検索・解析
   └─ LDC: ldc2.confを検索・解析
   └─ GDC: 未サポート、フォールバック
3. 設定ファイル検索順序
   └─ CWD → HOME → コンパイラディレクトリ → システムディレクトリ
4. DFLAGSパース
   └─ -Iオプションからインポートパスを抽出
5. フォールバック
   └─ 検出失敗時はハードコードされたデフォルトパスを返却
```

### フローチャート

```mermaid
flowchart TD
    A[autoDetectStdlibPaths] --> B{コンパイラパス指定?}
    B -->|Yes| C{バイナリ名判定}
    B -->|No| D[DMD/LDCフォールバック検出]
    C -->|dmd| E[detectDMDStdlibPaths]
    C -->|ldc/ldc2| F[detectLDCStdlibPaths]
    C -->|gdc/gcc| G[警告: 未サポート]
    G --> D
    E --> H{検出成功?}
    F --> H
    D --> H
    H -->|Yes| I[パス返却]
    H -->|No| J[ハードコードデフォルトパス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-80-01 | コンパイラ自動判定 | コンパイラパスのbaseName（拡張子除去）からdmd/ldc/ldc2/gdc/gccを判定 | コンパイラパス指定時 |
| BR-80-02 | DMD設定ファイル検索順序 | CWD → HOME → コンパイラディレクトリ → (Windows: 相対パス) / (POSIX: /etc, /usr/local/etc) | DMD検出時 |
| BR-80-03 | LDC設定ファイル検索順序 | CWD → コンパイラディレクトリ → HOME/.ldc → (Windows: HOME, レジストリ) / (POSIX: /etc, /etc/ldc, /usr/local/etc, /usr/local/etc/ldc) | LDC検出時 |
| BR-80-04 | DFLAGS -Iパース | DFLAGSの-Iオプションを引用符・エスケープを考慮してパースし、%@P%をcwdに置換 | 設定ファイル解析時 |
| BR-80-05 | LDC %%ldcbinarypath%% | ldc2.confの%%ldcbinarypath%%プレースホルダーをコンパイラのバイナリパスに置換 | LDC設定解析時 |
| BR-80-06 | GDC未サポート | GDC/GCCは自動検出未サポート、DMD/LDCにフォールバック | GDC指定時 |
| BR-80-07 | デフォルトフォールバック | 全検出失敗時、OS別のハードコードパスを返却（Windows: C:\D\dmd2\...、macOS: /Library/D/...、Linux: /usr/include/dmd/...） | 全検出失敗時 |
| BR-80-08 | 環境セクション優先 | dmd.confの[Environment64]は[Environment32]より優先 | DMD設定ファイル解析時 |

### 計算ロジック

特になし。

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

本機能ではデータベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | warning | PATH上にDMDが見つからない場合 | ハードコードされたシステムパスで設定ファイルを検索 |
| - | warning | dmd.confからphobos/druntimeパスが見つからない場合 | 次の検索場所に進む |
| - | warning | ldc2.confからパスが見つからない場合 | 次の検索場所に進む |
| - | Exception | ldc2設定ファイルの解析に失敗した場合 | "Could not read ldc2 config file"例外を発生 |
| - | warning | 全ての検出が失敗した場合 | ハードコードされたデフォルトフォールバックパスを使用 |

### リトライ仕様

リトライは行わない。各検索場所を順に試行し、最初に成功したものを返却する。

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

不要（読み取り専用の環境検出処理）。

## パフォーマンス要件

サーバー起動時に1回呼び出される処理であり、パフォーマンス要件は緩い。ファイルシステムアクセスが主な処理。

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

ファイルシステムの読み取りのみ行う。PATH環境変数やレジストリ（Windows）からの読み取りを行うが、書き込みは一切行わない。

## 備考

- Windows環境ではLDCのインストールパスをレジストリ（`HKLM\SOFTWARE\ldc-developers\LDC\0.11.0`）からも検索する
- DMD設定ファイル名はWindows: `sc.ini`、その他: `dmd.conf`
- LDC設定ファイル名は全プラットフォーム共通で`ldc2.conf`
- DFLAGSパースではシェルのクォーティングルール（シングルクォート、ダブルクォート、エスケープ）を正確に処理する
- ユニットテストで代表的なDFLAGSパターンの動作検証が可能（487-504行目）

---

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

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

### 推奨読解順序

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

本モジュールは構造体定義を持たず、関数ベースのユーティリティである。入出力は全てstring/string[]。

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

メインのautoDetectStdlibPaths関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | stdlib_detect.d | `source/served/utils/stdlib_detect.d` | `autoDetectStdlibPaths`関数（17-73行目）: 統合検出エントリーポイント |

**主要処理フロー**:
1. **21-22行目**: 相対パスの場合はsearchPathForで絶対パスに解決
2. **26-48行目**: baseName.stripExtensionでコンパイラ種別を判定し、dmd/ldc/gdc別の処理に分岐
3. **52行目**: コンパイラ指定なしまたは失敗時はDMD→LDCの順でフォールバック検出
4. **59-66行目**: 全検出失敗時はOS別のハードコードされたデフォルトパスを返却

#### Step 3: DMD設定ファイル解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | stdlib_detect.d | `source/served/utils/stdlib_detect.d` | `detectDMDStdlibPaths`関数（75-162行目）: DMD設定ファイルの検索と解析 |
| 3-2 | stdlib_detect.d | `source/served/utils/stdlib_detect.d` | `parseDmdConfImports`関数（321-358行目）: dmd.confのDFLAGS解析 |

**主要処理フロー**:
- **82-90行目**: Windows: `sc.ini`/`dmd.exe`、POSIX: `dmd.conf`/`dmd`の定数定義
- **92-94行目**: CWDに設定ファイルがあるか確認
- **96-99行目**: HOMEディレクトリに設定ファイルがあるか確認
- **104-109行目**: コンパイラのディレクトリに設定ファイルがあるか確認
- **323-328行目**: Region列挙（none, env32, env64）で環境セクションを追跡
- **339-351行目**: [Environment32]/[Environment64]セクションとDFLAGS行を識別

#### Step 4: LDC設定ファイル解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | stdlib_detect.d | `source/served/utils/stdlib_detect.d` | `detectLDCStdlibPaths`関数（164-239行目）: LDC設定ファイルの検索と解析 |
| 4-2 | stdlib_detect.d | `source/served/utils/stdlib_detect.d` | `parseLdcConfImports`関数（360-409行目）: ldc2.confの解析 |

**主要処理フロー**:
- **192-199行目**: CWD → コンパイラディレクトリの順で検索
- **201-211行目**: HOME/.ldc → (Windows: HOME)の順で検索
- **214-235行目**: コンパイラの親ディレクトリ/etc → (Posix: /etc, /etc/ldc等)
- **370-371行目**: `-I`で始まるスイッチからインポートパスを抽出
- **384行目**: `%%ldcbinarypath%%`をバイナリパスに置換

#### Step 5: DFLAGSパースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | stdlib_detect.d | `source/served/utils/stdlib_detect.d` | `parseDflagsImports`関数（416-434行目）: -Iオプション抽出 |
| 5-2 | stdlib_detect.d | `source/served/utils/stdlib_detect.d` | `parseArgumentWord`関数（436-485行目）: シェルクォーティング対応のパース |

**主要処理フロー**:
- **419行目**: `-I`の出現位置を検索
- **422-428行目**: 直前の文字がクォートまたは空白であることを確認
- **436-485行目**: シングルクォート、ダブルクォート、エスケープ（`\`）を正確に処理

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

```
serve-d 初期化 / DCDコンポーネント
    │
    └─ autoDetectStdlibPaths (17行目)
           │
           ├─ searchPathFor (283行目)
           │      └─ PATH環境変数走査
           │
           ├─ detectDMDStdlibPaths (75行目)
           │      ├─ searchPathFor (dmd検索)
           │      └─ parseDmdConfImports (321行目)
           │             └─ parseDflagsImports (416行目)
           │                    └─ parseArgumentWord (436行目)
           │
           └─ detectLDCStdlibPaths (164行目)
                  ├─ searchPathFor (ldc2検索)
                  ├─ getUserHomeDirectoryLDC (258行目)
                  ├─ [Windows] readLdcPathFromRegistry (241行目)
                  └─ parseLdcConfImports (360行目)
                         └─ parseConfigFile (external.ldc.config)
```

### データフロー図

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

コンパイラパス ──────────▶ autoDetectStdlibPaths ──────▶ string[]
                             (コンパイラ種別判定)           (インポートパス配列)

dmd.conf/sc.ini ────────▶ parseDmdConfImports ─────────▶ string[]
                             (DFLAGS解析)                  ([druntime, phobos])

ldc2.conf ──────────────▶ parseLdcConfImports ─────────▶ string[]
                             (-I スイッチ解析)               ([druntime, phobos])

PATH環境変数 ───────────▶ searchPathFor ────────────────▶ string
                             (実行ファイル検索)               (フルパス or null)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| stdlib_detect.d | `source/served/utils/stdlib_detect.d` | ソース | 標準ライブラリパス検出の全実装 |
| extension.d | `source/served/extension.d` | ソース | serve-dメインモジュール（autoDetectStdlibPathsの呼び出し元） |
| dcd.d | `workspace-d/source/workspaced/com/dcd.d` | ソース | DCDコンポーネント（インポートパスの設定先） |
