# 機能設計書 97-動的ローダー

## 概要

本ドキュメントは、Julia言語の動的ローダー機能の設計を記述する。`libjulia`共有ライブラリとその依存ライブラリのロード、シンボル解決、およびREPLエントリーポイントへの制御移譲を担う起動初期段階の機能である。

### 本機能の処理概要

**業務上の目的・背景**：Juliaは`libjulia-internal`（ランタイム本体）と`libjulia-codegen`（コード生成）を分離した構成を取る。動的ローダーは、実行ファイル（`julia`）からこれらの共有ライブラリを正しい順序でロードし、シンボルを再エクスポートすることで、Juliaランタイムの起動を実現する。

**機能の利用シーン**：`julia`コマンドの起動初期段階（main関数実行前の`__attribute__((constructor))`による自動ロード）、Juliaの組み込み利用時のライブラリロード、カスタムランタイム構成時。

**主要な処理内容**：
1. `libjulia`のパス特定（`jl_get_libdir`）
2. 依存ライブラリの順次ロード（DEP_LIBS文字列解析）
3. libstdc++のシステムバージョンプローブ（Linux限定）
4. `libjulia-internal`と`libjulia-codegen`の特別ロード処理
5. ランタイムシンボルの再エクスポート
6. Fast TLS（Thread Local Storage）の設定
7. `jl_load_repl`によるREPLエントリーポイント呼び出し

**関連システム・外部連携**：OS動的リンク機構（dlopen/LoadLibrary）、Fast TLS（ELF TLS）、GLIBC互換性。

**権限による制御**：特にない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ランタイム内部機能のため関連画面なし |

## 機能種別

動的ライブラリロード / シンボル解決

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| DEP_LIBS | コンパイル時定数 | Yes | コロン区切りの依存ライブラリリスト | 先頭`@`はスペシャルライブラリ |
| JULIA_PROBE_LIBSTDCXX | 環境変数 | No | libstdc++プローブの有効/無効 | "0"/"no"で無効 |

### 入力データソース

- コンパイル時に設定されるDEP_LIBS定数
- OS動的リンク機構（dlopen/LoadLibrary）
- 環境変数`JULIA_PROBE_LIBSTDCXX`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| libjulia_internal | void* | libjulia-internalのライブラリハンドル |
| libjulia_codegen | void* | libjulia-codegenのライブラリハンドル（NULLの場合internalにフォールバック） |
| 再エクスポートシンボル | 関数ポインタ | ランタイム/コード生成のエクスポート関数群 |

### 出力先

グローバル変数（libjulia_internal, libjulia_codegen）および関数ポインタテーブル

## 処理フロー

### 処理シーケンス

```
1. jl_load_libjulia_internal（__attribute__((constructor))で自動呼出）
   ├─ Linux: シグナルマスクの全ブロック（inherit用）
   ├─ jl_get_libdirでライブラリパス特定
   ├─ DEP_LIBSをパースしてスペシャルライブラリ数を検証（3つ: libstdc++, libjulia-internal, libjulia-codegen）
   ├─ DEP_LIBSをループして各依存ライブラリをロード
   │   ├─ @libstdc++: システムバージョンプローブ（Linux）
   │   ├─ @libjulia-internal: load_library (必須)
   │   └─ @libjulia-codegen: load_library (オプション)
   ├─ ランタイムシンボルの再エクスポート
   ├─ コード生成シンボルの再エクスポート（codegen不在時はfallback使用）
   ├─ Fast TLS設定（jl_pgcstack_setkey）
   └─ jl_init_options呼出
2. jl_load_repl（loader_exe.cから呼出）
   ├─ libjulia_internal未ロード時のフォールバック
   └─ jl_repl_entrypoint検索・呼出
```

### フローチャート

```mermaid
flowchart TD
    A[プロセス起動] --> B[__attribute__ constructor]
    B --> C[jl_load_libjulia_internal]
    C --> D[jl_get_libdir]
    D --> E[DEP_LIBSパース・検証]
    E --> F[依存ライブラリ順次ロード]
    F --> G{@libstdc++?}
    G -->|Yes, Linux| H[libstdcxxprobe]
    H --> I{システム版が新しい?}
    I -->|Yes| J[システムlibstdc++をdlopen]
    I -->|No| K[バンドル版をロード]
    G -->|No/他OS| L[通常ロード]
    J --> M{@libjulia-internal?}
    K --> M
    L --> M
    M -->|Yes| N[libjulia-internal = load_library]
    M -->|@libjulia-codegen| O[libjulia-codegen = load_library optional]
    N --> P[ランタイムシンボル再エクスポート]
    O --> P
    P --> Q[コード生成シンボル再エクスポート]
    Q --> R[Fast TLS設定]
    R --> S[jl_init_options]
    S --> T[main → jl_load_repl]
    T --> U[jl_repl_entrypoint]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-97-01 | スペシャルライブラリ | `@`接頭辞のライブラリは特別処理、ちょうど3つ必要 | DEP_LIBSパース時 |
| BR-97-02 | codegen不在フォールバック | libjulia-codegenがロードできない場合、libjulia-internalからfallback関数を使用 | libjulia_codegen==NULL |
| BR-97-03 | 既にロード済みチェック | dlopen前にdlopen(RTLD_NOLOAD)で既にロードされているかチェック | load_library |
| BR-97-04 | libstdc++プローブ | GLIBCXX_LEAST_VERSION_SYMBOLに基づきシステムlibstdc++の新しさを判定 | Linux環境のみ |
| BR-97-05 | シグナルマスク継承 | Linux: ライブラリロード前に全シグナルをブロックし、ロード後に復元 | 構築中スレッドへのシグナル防止 |

### 計算ロジック

特になし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ライブラリロード失敗 | dlopen/LoadLibraryExW失敗（ファイル不在以外） | エラーメッセージ出力しexit(1) |
| - | シンボル未発見 | lookup_symbol失敗 | エラーメッセージ出力しexit(1) |
| - | スペシャルライブラリ数不一致 | @接頭辞のライブラリ数が3でない | エラーメッセージ出力しexit(1) |
| - | libjulia-internalロード失敗 | 必須ライブラリのロード失敗 | エラーメッセージ出力しexit(1) |

### リトライ仕様

ライブラリロード失敗は致命的エラーであり、リトライはない。ただし、libjulia-codegenのロード失敗はオプショナルとして処理される（ファイルが存在しない場合のみ）。

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

該当なし

## パフォーマンス要件

- `__attribute__((constructor))`により、main関数実行前にライブラリがロードされる
- 既にロード済みのライブラリは`RTLD_NOLOAD`チェックでスキップ

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

- RTLD_GLOBALでロードされるライブラリはプロセス全体にシンボルが公開される
- libjulia-codegenはRTLD_LOCALでロード（シンボル非公開）
- RPATH相対パスで依存ライブラリを解決するため、ライブラリパスの改ざんに注意

## 備考

- Windows環境では`DllMainCRTStartup`が`__attribute__((constructor))`の代替として使用される
- `GLIBCXX_LEAST_VERSION_SYMBOL`はMakefileで定義される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | loader.h | `cli/loader.h` | プラットフォーム定義、JL_DLLEXPORT、DEP_LIBS、LIBJULIA_NAME |
| 1-2 | jl_exports.h | `cli/jl_exports.h` | エクスポートシンボル名・アドレステーブル |

**読解のコツ**: `dep_libs`は1024バイトの固定バッファで、コンパイル時にDEP_LIBS定数が書き込まれる。コロン区切りで、`@`接頭辞はスペシャルライブラリを示す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | loader_lib.c | `cli/loader_lib.c` | jl_load_libjulia_internal（241行目、constructor） |

**主要処理フロー**:
1. **248-250行目**: Linux: 全シグナルブロック
2. **259行目**: `jl_get_libdir()`でライブラリパス特定
3. **262-295行目**: DEP_LIBSパース、スペシャルライブラリ検証
4. **302-375行目**: 依存ライブラリの順次ロード
5. **390-410行目**: ランタイム/コード生成シンボルの再エクスポート
6. **411-427行目**: Fast TLS設定
7. **431行目**: `jl_init_options`呼び出し

#### Step 3: ライブラリパス特定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | loader_lib.c | `cli/loader_lib.c` | jl_get_libdir（156行目） |

**主要処理フロー**:
- **162-209行目**: Windows: `GetModuleFileNameW` / Unix: `dladdr` でlibjuliaのパスを特定しdirname取得

#### Step 4: REPL起動を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | loader_lib.c | `cli/loader_lib.c` | jl_load_repl（442行目） |

**主要処理フロー**:
- **442-459行目**: `jl_repl_entrypoint`シンボルをlookup_symbolで検索し呼び出し

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

```
[__attribute__((constructor))]
jl_load_libjulia_internal (loader_lib.c:241)
    +-- jl_get_libdir (loader_lib.c:156)
    |       +-- dladdr() / GetModuleFileNameW()
    |       +-- dirname()
    +-- load_library(curr_dep, lib_dir, err) [ループ]
    |       +-- dlopen() / LoadLibraryExW()
    +-- [special_idx==0] libstdcxxprobe() [Linux]
    |       +-- dlopen("libstdc++.so.6", RTLD_NOLOAD)
    |       +-- jl_loader_probe_system_library()
    +-- [special_idx==1] libjulia-internal ロード
    +-- [special_idx==2] libjulia-codegen ロード
    +-- lookup_symbol(libjulia_internal, symbol_name) [ループ]
    +-- jl_pgcstack_setkey() [Fast TLS]
    +-- jl_init_options()

jl_load_repl (loader_lib.c:442)
    +-- lookup_symbol(libjulia_internal, "jl_repl_entrypoint")
    +-- entrypoint(argc, argv)
```

### データフロー図

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

DEP_LIBS (コンパイル時) ─> jl_load_libjulia_internal ──> libjulia_internal ハンドル
                               |                          libjulia_codegen ハンドル
                               +-- load_library()         関数ポインタテーブル
                               +-- lookup_symbol()

lib_dir (dladdr) ─────────> load_library(rel_path) ──────> void* ハンドル

argc/argv ────────────────> jl_load_repl ────────────────> int 終了コード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| loader_lib.c | `cli/loader_lib.c` | ソース | 動的ローダー実装の中核 |
| loader_exe.c | `cli/loader_exe.c` | ソース | 実行ファイルエントリーポイント |
| loader.h | `cli/loader.h` | ヘッダ | ローダー共通定義 |
| jl_exports.h | `cli/jl_exports.h` | ヘッダ | エクスポートシンボル定義 |
| loader_win_utils.c | `cli/loader_win_utils.c` | ソース | Windows固有ユーティリティ |
