# 機能設計書 150-LLD_jll

## 概要

本ドキュメントは、Julia標準ライブラリに含まれるLLD_jllパッケージの機能設計を記述する。LLD_jllは、LLVM LLDリンカのJLLバイナリラッパーであり、Juliaのコード生成パイプラインで使用されるリンカ実行ファイルを提供する。

### 本機能の処理概要

LLD_jllは、LLVM LLDリンカの実行ファイルをJuliaのパッケージシステムを通じて提供するJLLラッパーパッケージである。他のJLLパッケージとは異なり、共有ライブラリではなく実行ファイル（lld）を提供する。実行ファイルのパス検索、環境変数の調整、Cmdオブジェクトの生成機能を持つ。

**業務上の目的・背景**：LLDはLLVMプロジェクトのリンカであり、Juliaのコンパイルパイプラインにおいてオブジェクトファイルのリンクに使用される。LLD_jllは、このリンカのバイナリ配布とパス解決を管理し、プラットフォーム間で一貫したリンク処理を提供する。JuliaのAOTコンパイル（システムイメージ/パッケージイメージの生成）やネイティブコード生成において重要な役割を果たす。

**機能の利用シーン**：システムイメージの構築、パッケージのプリコンパイル、ネイティブコード生成時のオブジェクトファイルリンク等で利用される。

**主要な処理内容**：
1. lld実行ファイルの検索（Juliaバンドル版を優先、なければPATHから検索）
2. プラットフォーム別のライブラリパス環境変数（LIBPATH）の調整
3. 環境変数を適切に設定したCmdオブジェクトの生成
4. コールバック関数パターンによるlldパスの提供

**関連システム・外部連携**：Zlib_jll、libLLVM_jllへの依存（Project.toml上）。LLVM LLDプロジェクト（https://lld.llvm.org/）のバージョン20.1.8に対応。

**権限による制御**：特になし。全ユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はUI画面を持たない。コンパイラのコード生成パイプラインから使用される |

## 機能種別

データ連携（ネイティブ実行ファイル配布・パス解決・環境変数管理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Sys.KERNEL | Symbol | Yes | 実行プラットフォームのカーネル識別子 | Windows/macOS/Linux等 |
| Sys.BINDIR | String | Yes | Juliaバイナリのインストールディレクトリ | 有効なディレクトリパス |
| adjust_PATH | Bool | No | PATH環境変数を調整するか（デフォルト: true） | true/false |
| adjust_LIBPATH | Bool | No | LIBPATH環境変数を調整するか（デフォルト: true） | true/false |

### 入力データソース

- ファイルシステム: lld実行ファイルの存在チェック（isfile）
- 環境変数: PATH, LD_LIBRARY_PATH/DYLD_FALLBACK_LIBRARY_PATH
- Juliaインストールパス: Sys.BINDIR, Base.PRIVATE_LIBEXECDIR, Base.LIBDIR

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| lld_path | String | lld実行ファイルの絶対パス |
| lld() | Cmd | 環境変数調整済みのlldコマンドオブジェクト |
| lld(f) | Any | コールバック関数にlld_pathを渡して実行した結果 |
| artifact_dir | String | アーティファクトディレクトリ |

### 出力先

- メモリ内グローバル変数としてモジュール内に保持
- Cmdオブジェクトとしてプロセス実行に使用

## 処理フロー

### 処理シーケンス

```
1. モジュール定義（baremodule）
   └─ Base, Libdl をusing
2. プラットフォーム別定数の定義
   ├─ lld_exe: 実行ファイル名（"lld" or "lld.exe"）
   ├─ LIBPATH_env: ライブラリパス環境変数名
   ├─ LIBPATH_default: デフォルトライブラリパス
   └─ pathsep: パス区切り文字
3. adjust_ENV!()関数の定義
   └─ PATH/LIBPATH環境変数の調整ロジック
4. lld()関数の定義（2つのメソッド）
   ├─ lld(f::Function): コールバック形式
   └─ lld(): Cmdオブジェクト形式
5. init_lld_path()関数の定義
   └─ バンドル版lldの検索（3箇所のパス候補）
   └─ 見つからない場合はSys.which()でPATHから検索
6. __init__()実行
   └─ init_lld_path(), PATH, LIBPATH の設定
```

### フローチャート

```mermaid
flowchart TD
    A["__init__() 実行"] --> B[init_lld_path 呼び出し]
    B --> C{BINDIR/PRIVATE_LIBEXECDIR/lld 存在?}
    C -->|Yes| D[そのパスを使用]
    C -->|No| E{BINDIR/../tools/lld 存在?}
    E -->|Yes| F[そのパスを使用]
    E -->|No| G{BINDIR/lld 存在?}
    G -->|Yes| H[そのパスを使用]
    G -->|No| I["Sys.which('lld') でPATHから検索"]
    D --> J[lld_path 設定]
    F --> J
    H --> J
    I --> J
    J --> K[PATH, LIBPATH 設定]
    K --> L[初期化完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-150-01 | バンドル版優先 | Juliaにバンドルされたlldを優先使用し、なければPATHから検索 | __init__時 |
| BR-150-02 | 検索順序 | 1. PRIVATE_LIBEXECDIR, 2. ../tools, 3. BINDIR直下, 4. Sys.which の順で検索 | init_lld_path時 |
| BR-150-03 | 環境変数調整 | lld()呼び出し時にPATH/LIBPATHを適切に調整したCmdオブジェクトを生成 | lld()呼び出し時 |
| BR-150-04 | プラットフォーム別LIBPATH | Windows: PATH, macOS: DYLD_FALLBACK_LIBRARY_PATH, Linux: LD_LIBRARY_PATH | lld()呼び出し時 |
| BR-150-05 | dev_jll禁止 | stdlib JLLsはdev_jllできない（dev_jll()はエラーを投げる） | dev_jll()呼び出し時 |

### 計算ロジック

特になし。

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

### 操作別データベース影響一覧

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ErrorException | dev_jll()の呼び出し | `error("stdlib JLLs cannot be dev'ed")` |
| - | 実行失敗 | lld実行ファイルが見つからない | Sys.which()のフォールバックで"lld"文字列を返す |

### リトライ仕様

リトライは行わない。

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

該当なし。

## パフォーマンス要件

- lld_pathの検索はisfile()による逐次チェック（最大4箇所）
- 一度見つかったパスはグローバル変数にキャッシュ

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

- lld_pathの検索はJuliaインストールディレクトリ内を優先し、外部パスは最後の手段
- adjust_ENV!()でPATH/LIBPATHを調整する際、既存環境変数を保持しつつ先頭に追加

## 備考

- バージョン: LLD 20.1.8+0
- UUID: d55e3150-da41-5e91-b323-ecfd1eec6109
- JuliaBinaryWrappersの上流リポジトリ: https://github.com/JuliaBinaryWrappers/LLD_jll.jl
- 他のJLLパッケージとは異なり、共有ライブラリではなく実行ファイルを提供
- LazyLibraryは使用せず、独自のパス検索ロジックを実装
- JLLWrappers API互換シム（is_available, find_artifact_dir, dev_jll, best_wrapper）を提供

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | LLD_jll.jl | `stdlib/LLD_jll/src/LLD_jll.jl` | プラットフォーム別定数の定義（18-36行目） |

**読解のコツ**: LLD_jllは他のJLLパッケージとは構造が大きく異なる。LazyLibraryを使用せず、実行ファイルのパス検索と環境変数調整に特化している。Cmdオブジェクトの生成パターンに注目。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LLD_jll.jl | `stdlib/LLD_jll/src/LLD_jll.jl` | モジュール全体の定義（106行） |

**主要処理フロー**:
1. **5行目**: `baremodule LLD_jll` - モジュール定義開始
2. **11行目**: `export lld` - lld関数をエクスポート（ライブラリではなく関数/実行ファイル）
3. **18-22行目**: lld_exe定数。Windowsでは"lld.exe"、他は"lld"
4. **24-36行目**: LIBPATH_env, LIBPATH_default, pathsep のプラットフォーム別定数定義
5. **38-57行目**: `adjust_ENV!()`関数。環境変数のPATH/LIBPATH調整ロジック
6. **59-68行目**: `lld()`関数。2つのメソッド（コールバック形式/Cmd形式）
7. **70-82行目**: `init_lld_path()`関数。3箇所のパス候補を順に検索
8. **84-96行目**: `__init__()`関数。パス初期化とLIBPATH設定
9. **101-104行目**: JLLWrappers API互換シム

#### Step 3: パス検索ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LLD_jll.jl | `stdlib/LLD_jll/src/LLD_jll.jl` | init_lld_path()（70-82行目） |

**主要処理フロー**:
- **73行目**: 検索パス1: `Sys.BINDIR / Base.PRIVATE_LIBEXECDIR / lld_exe` - プライベートlibexecディレクトリ
- **74行目**: 検索パス2: `Sys.BINDIR / "../tools" / lld_exe` - ソースツリー内ビルド時のパス
- **75行目**: 検索パス3: `Sys.BINDIR / lld_exe` - BINDIRの直下
- **76-80行目**: 各パスについてisfile()で存在チェック。見つかればabspath()で絶対パスに変換
- **81行目**: 見つからない場合は`Sys.which(lld_exe)`でPATHから検索。それも失敗すれば"lld"文字列をそのまま返す

#### Step 4: 環境変数調整ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | LLD_jll.jl | `stdlib/LLD_jll/src/LLD_jll.jl` | adjust_ENV!()（38-57行目） |

**主要処理フロー**:
- **39-46行目**: LIBPATH調整。既存値がある場合はパス区切りで連結、ない場合は新規設定
- **47-56行目**: PATH調整。LIBPATHがPATH以外の場合のみPATH環境変数も更新

#### Step 5: テストを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | runtests.jl | `stdlib/LLD_jll/test/runtests.jl` | lld_pathの存在確認とバージョン実行テスト |

**主要処理フロー**:
- **6行目**: `isfile(LLD_jll.lld_path)` - パスが有効なファイルであることを確認
- **7行目**: OS別にlldの"flavor"（darwin/link/gnu）を判定
- **8行目**: `success(\`$(LLD_jll.lld()) -flavor $flavor --version\`)` - 実際にlldを実行してバージョン表示が成功することを確認

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

```
LLD_jll.__init__()
    |
    +-- init_lld_path()
    |       |
    |       +-- isfile(BINDIR/PRIVATE_LIBEXECDIR/lld)
    |       +-- isfile(BINDIR/../tools/lld)
    |       +-- isfile(BINDIR/lld)
    |       +-- Sys.which("lld") [フォールバック]
    |
    +-- PATH[] = dirname(lld_path)
    |
    +-- LIBPATH_list 設定
    |       +-- [Windows] BINDIR/LIBDIR/julia, BINDIR
    |       +-- [他] BINDIR/LIBDIR/julia, BINDIR/LIBDIR
    |
    +-- LIBPATH[] = join(LIBPATH_list, pathsep)

LLD_jll.lld() [Cmd形式]
    |
    +-- adjust_ENV!(copy(ENV), PATH[], LIBPATH[], ...)
    |       +-- 環境変数のPATH/LIBPATH調整
    |
    +-- Cmd([lld_path]; env=adjusted_env)

LLD_jll.lld(f::Function) [コールバック形式]
    |
    +-- adjust_ENV!(copy(ENV), ...)
    +-- withenv(env...) do
            f(lld_path)
        end
```

### データフロー図

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

Sys.BINDIR (Juliaパス) ----------> init_lld_path() 検索 --------> lld_path
Sys.KERNEL (OS種別) -------------> プラットフォーム定数決定 -----> LIBPATH_env, pathsep
ENV (環境変数) ------------------> adjust_ENV!() 調整 -----------> 調整済みCmdオブジェクト
                                      |
                                      v
                               Cmd([lld_path]; env) -----------> リンカ実行可能状態
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LLD_jll.jl | `stdlib/LLD_jll/src/LLD_jll.jl` | ソース | メインモジュール定義。lldパス検索と環境変数管理 |
| Project.toml | `stdlib/LLD_jll/Project.toml` | 設定 | パッケージメタデータ・依存関係・バージョン情報 |
| runtests.jl | `stdlib/LLD_jll/test/runtests.jl` | テスト | lldパス存在確認とバージョン実行テスト |
| libdl.jl | `base/libdl.jl` | ソース | Libdl基盤（LLD_jllではLazyLibraryは未使用） |
