# 機能設計書 136-プラットフォーム検出

## 概要

本ドキュメントは、Julia の `BinaryPlatforms` モジュールによる OS・アーキテクチャ・libc の検出と JLL 互換性チェック機能について、その設計・処理仕様を記述するものである。

### 本機能の処理概要

`BinaryPlatforms` モジュールは、実行環境のプラットフォーム情報（CPU アーキテクチャ、OS、libc 実装、ABI 情報など）を構造化されたタグ-値マッピングとして表現し、JLL パッケージのバイナリ互換性チェックに使用する機能である。

**業務上の目的・背景**：Julia のパッケージエコシステムでは、C/C++ ライブラリのプリビルトバイナリを JLL パッケージとして配布する。異なるプラットフォーム向けのバイナリを正しく選択するために、実行環境のプラットフォーム情報を正確に検出し、バイナリとの互換性を判定する必要がある。

**機能の利用シーン**：JLL パッケージのバイナリ選択、パッケージのプリコンパイル時のプラットフォーム判定、CI/CD でのクロスコンパイル対象の決定、プラットフォーム固有の条件分岐など。

**主要な処理内容**：
1. `Platform` 型によるプラットフォーム情報の構造化表現
2. `HostPlatform()` による現在の実行環境の検出
3. `platforms_match()` による2つのプラットフォーム間の互換性判定
4. `select_platform()` によるプラットフォーム辞書からの最適バイナリ選択
5. `triplet()` によるプラットフォームのトリプレット文字列生成
6. `detect_libgfortran_version` / `detect_libstdcxx_version` / `detect_cxxstring_abi` による ABI 検出
7. CPUID サブモジュールによる CPU 機能検出

**関連システム・外部連携**：JLL パッケージシステム、Artifacts システム、Pkg パッケージマネージャ、Libdl（動的ライブラリ操作）と連携する。

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

## 関連画面

本機能は特定の画面との紐付けはない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | JLL パッケージの読み込み時やパッケージインストール時に内部的に使用される |

## 機能種別

システム情報取得 / バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| arch | String | Yes（Platform） | CPU アーキテクチャ（"x86_64", "aarch64" 等） | CPUID.normalize_arch で正規化 |
| os | String | Yes（Platform） | オペレーティングシステム（"linux", "windows", "macos" 等） | lowercase で正規化 |
| kwargs | NamedTuple | No | 追加タグ（libc, call_abi, libgfortran_version 等） | 予約タグの値バリデーション |

### 入力データソース

システム情報（`Sys.ARCH`, `Sys.KERNEL`）、動的ライブラリの検出（`Libdl.dlopen`）、CPUID命令。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Platform | Platform | タグ-値マッピングとしてのプラットフォーム情報 |
| triplet | String | "x86_64-linux-gnu" 形式のトリプレット文字列 |
| platforms_match結果 | Bool | 2つのプラットフォームの互換性判定結果 |
| select_platform結果 | Any / Nothing | 互換バイナリの選択結果 |

### 出力先

呼び出し元への戻り値。

## 処理フロー

### 処理シーケンス

```
1. Platform オブジェクトの構築
   └─ arch / os の正規化、追加タグの設定
2. デフォルト値の自動設定
   └─ Linux のデフォルト libc は "glibc"、ARM のデフォルト call_abi は "eabihf"
3. タグバリデーション（validate_strict モード）
   └─ 予約タグの値が許容範囲内かチェック
4. HostPlatform の検出
   └─ Sys.ARCH / Sys.KERNEL から arch / os を取得
   └─ detect_* 関数で ABI 情報を検出
5. platforms_match による互換性判定
   └─ 各タグの compare_strategy に基づく比較
6. select_platform によるバイナリ選択
   └─ platforms_match で互換な候補を選択
```

### フローチャート

```mermaid
flowchart TD
    A["Platform(arch, os; kwargs...)"] --> B["arch の正規化 (CPUID.normalize_arch)"]
    B --> C["os の lowercase"]
    C --> D["追加タグの設定 (add_tag!)"]
    D --> E{"Linux かつ libc 未指定?"}
    E -->|Yes| F["libc = 'glibc' を設定"]
    E -->|No| G{"ARM かつ call_abi 未指定?"}
    F --> G
    G -->|Yes| H["call_abi = 'eabihf' を設定"]
    G -->|No| I{"validate_strict?"}
    H --> I
    I -->|Yes| J["validate_tags() でバリデーション"]
    I -->|No| K["Platform オブジェクト返却"]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-136-01 | タグ正規化 | 全タグと値は小文字に正規化される | 常時 |
| BR-136-02 | Linux デフォルト libc | Linux プラットフォームでは libc 未指定時に "glibc" がデフォルト | os == "linux" |
| BR-136-03 | ARM デフォルト ABI | 32ビット ARM では call_abi 未指定時に "eabihf" がデフォルト | arch in ("armv7l", "armv6l") |
| BR-136-04 | julia_version 比較 | julia_version タグはメジャー・マイナーバージョンのみで比較 | julia_version タグ存在時 |
| BR-136-05 | 予約タグ | arch / os / os_version / libc / call_abi / libgfortran_version / libstdcxx_version / cxxstring_abi / julia_version は予約タグ | 常時 |
| BR-136-06 | 無効文字禁止 | タグ名と値に `+`, `-`, ` `, `/` 等の特殊文字は使用不可 | add_tag! 時 |

### 計算ロジック

特になし。

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

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

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentError | arch / os の二重指定 | kwargs で arch/os を渡さない |
| - | ArgumentError | タグ名・値に無効文字が含まれる | 英数字とピリオドのみ使用 |
| - | ArgumentError | validate_strict で無効なタグ値 | 有効な値を指定 |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- Platform 構築は Dict ベースであり軽量
- HostPlatform の検出は初期化時に1回のみ実行されることが想定される
- ABI 検出（detect_* 関数）は Libdl.dlopen を使用するため I/O コストがある

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

- Libdl.dlopen による動的ライブラリの検出は、ライブラリ検索パスに依存する
- プラットフォーム情報は JLL バイナリ選択に使用されるため、偽装されるとセキュリティリスクとなりうる

## 備考

- `BinaryPlatforms` は `base/binaryplatforms.jl` で定義され、`CPUID` サブモジュール（`base/cpuid.jl`）を含む
- Platform の compare_strategies により、タグごとにカスタム比較ロジックを設定可能
- `AnyPlatform` は全プラットフォームにマッチする特殊な Platform 型

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | binaryplatforms.jl | `base/binaryplatforms.jl` | **17行目**: `abstract type AbstractPlatform` -- プラットフォーム型の基底 |
| 1-2 | binaryplatforms.jl | `base/binaryplatforms.jl` | **38-42行目**: `struct Platform <: AbstractPlatform` -- tags (Dict{String,String}) と compare_strategies |

**読解のコツ**: Platform は本質的に `Dict{String,String}` のラッパーであり、"arch"=>"x86_64", "os"=>"linux" のようなタグ-値マッピングを保持する。compare_strategies は各タグのカスタム比較ロジックを持てる。

#### Step 2: コンストラクタとバリデーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | binaryplatforms.jl | `base/binaryplatforms.jl` | **44-112行目**: Platform の主要コンストラクタ（Dict ベース） |
| 2-2 | binaryplatforms.jl | `base/binaryplatforms.jl` | **115-121行目**: キーワード引数ベースのコンストラクタ |
| 2-3 | binaryplatforms.jl | `base/binaryplatforms.jl` | **128-145行目**: add_tag! 関数（タグ追加・バリデーション） |
| 2-4 | binaryplatforms.jl | `base/binaryplatforms.jl` | **194-199行目**: validate_tags 関数（厳密バリデーション） |

#### Step 3: プラットフォーム情報取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | binaryplatforms.jl | `base/binaryplatforms.jl` | arch() / os() / libc() 等のアクセサ関数群 |
| 3-2 | binaryplatforms.jl | `base/binaryplatforms.jl` | triplet() 関数 -- トリプレット文字列の生成 |
| 3-3 | cpuid.jl | `base/cpuid.jl` | CPUID サブモジュール -- CPU 機能検出 |

#### Step 4: 互換性判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | binaryplatforms.jl | `base/binaryplatforms.jl` | platforms_match() 関数 -- 2つの Platform の互換性判定 |
| 4-2 | binaryplatforms.jl | `base/binaryplatforms.jl` | select_platform() 関数 -- 互換バイナリの選択 |

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

```
BinaryPlatforms
    |
    +-- Platform(arch, os; kwargs...)
    |       +-- CPUID.normalize_arch(arch)
    |       +-- add_tag!(tags, tag, value)
    |       +-- validate_tags(tags) [validate_strict=true の場合]
    |
    +-- HostPlatform()
    |       +-- Sys.ARCH / Sys.KERNEL
    |       +-- detect_libgfortran_version()
    |       +-- detect_libstdcxx_version()
    |       +-- detect_cxxstring_abi()
    |
    +-- platforms_match(a, b)
    |       +-- 各タグの compare_strategy による比較
    |
    +-- select_platform(platforms_dict)
    |       +-- platforms_match で互換候補を検索
    |
    +-- triplet(p)
            +-- タグから "arch-os-libc" 形式の文字列を生成
```

### データフロー図

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

Sys.ARCH / Sys.KERNEL     --> HostPlatform() 構築
detect_libgfortran_ver()       +-- Platform タグ設定       --> Platform("x86_64", "linux";
detect_libstdcxx_ver()                                         libc="glibc", ...)
detect_cxxstring_abi()

Platform(host) +           --> platforms_match(host, p)
Platform(candidate)            +-- 各タグ比較              --> Bool (互換性判定)

Dict{Platform, path}       --> select_platform(dict)
                               +-- platforms_match         --> path or nothing
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| binaryplatforms.jl | `base/binaryplatforms.jl` | ソース | BinaryPlatforms モジュールの主要実装 |
| cpuid.jl | `base/cpuid.jl` | ソース | CPUID サブモジュール（CPU機能検出） |
| sysimg.jl | `base/sysimg.jl` | ソース | BinaryPlatforms の include |
| test/binaryplatforms.jl | `test/binaryplatforms.jl` | テスト | BinaryPlatforms の回帰テスト |
