# 環境構築手順 (Environment Setup)

新規参加者・別デバイス・環境を作り直す場合の手順．Windows 10 / 11 を前提とする．

## 前提条件 (Prerequisites)

| ツール | 用途 | 入手元 |
| --- | --- | --- |
| Git | リポジトリ操作 | https://git-scm.com/download/win |
| GitHub CLI（`gh`） | PR 作成・マージ | https://cli.github.com/ |
| LLVM | Mitsuba 3 が JIT 実行時に呼ぶ `LLVM-C.dll` を提供（CPU レンダリングに必須） | `winget install LLVM.LLVM`（管理者権限プロンプトを承認） |
| Fusion 360（任意） | 筐体 3D モデル編集．シミュレーション実行のみなら不要 | https://www.autodesk.co.jp/products/fusion-360 |

Python は **uv** が自動で取得するため，手動インストール不要．

## 手順 (Steps)

### 1. uv をインストール

PowerShell を開き，以下を実行する．

```powershell
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
```

バージョンを確認：

```powershell
uv --version
```

### 2. リポジトリをクローン

```powershell
git clone https://github.com/rintoHasegawa/SmTIAS-LightSim.git
cd SmTIAS-LightSim
```

※ 関連リポジトリ（[SmTIAS-Capture](https://github.com/rintoHasegawa/SmTIAS-Capture)・[SmTIAS-Evaluation](https://github.com/rintoHasegawa/SmTIAS-Evaluation)）はローカルに置かず，必要時に `gh` CLI 等で GitHub から直接参照する（CLAUDE.md「外部参照リポジトリ」参照）．

### 3. 依存と Python ランタイムを同期

```powershell
uv sync
```

このコマンドだけで以下が実行される：

- `.python-version` に書かれた Python 3.12 を uv が自動取得
- `pyproject.toml` + `uv.lock` から完全同一の依存関係を再現
- 仮想環境 `.venv/` を作成

### 4. 動作確認

```powershell
uv run python -c "import mitsuba as mi; mi.set_variant('llvm_ad_rgb'); print(mi.__version__, mi.variant())"
```

`3.8.0 llvm_ad_rgb` のように表示されれば OK．エラー（`LLVM-C.dll could not be found`）が出る場合は前提条件の LLVM が入っていない．

### 5. ツール類の確認

```powershell
uv run pytest --version    # テスト実行用
uv run ruff --version      # Lint / Format 用
```

## よくある操作 (Common Tasks)

| やりたいこと | コマンド |
| --- | --- |
| 依存追加 | `uv add <パッケージ名>` |
| 開発用依存追加 | `uv add --dev <パッケージ名>` |
| 依存更新 | `uv lock --upgrade` → `uv sync` |
| スクリプト実行 | `uv run python <スクリプト>` |
| テスト実行 | `uv run pytest` |
| Lint / Format | `uv run ruff check .` / `uv run ruff format .` |

## LLVM のインストール（Windows）

Mitsuba 3 の `llvm_*` variant（CPU JIT レンダリング）は `LLVM-C.dll` を必要とする．
`sm-render` を使う場合はこのセクションの手順を完了してから進むこと．

### インストール手順

1. [LLVM GitHub Releases](https://github.com/llvm/llvm-project/releases) から
   `LLVM-<バージョン>-win64.exe`（最新安定版）をダウンロードする
2. インストーラを実行する．インストール先は既定の `C:\Program Files\LLVM\` を推奨
3. 完了後，以下のコマンドでファイルの存在を確認する：

```powershell
Test-Path 'C:\Program Files\LLVM\bin\LLVM-C.dll'
```

`True` が表示されれば OK．

> **補足**: `winget install LLVM.LLVM` でもインストール可能（管理者権限プロンプトの承認が必要）．

### DRJIT_LIBLLVM_PATH の設定（任意）

**コード側（`sm_tias_lightsim.runtime.llvm_init`）が起動時に標準パスを自動探索するため，
通常は環境変数の手動設定は不要．**

LLVM を非標準パスにインストールした場合のみ，以下の PowerShell コマンドで永続化する：

```powershell
[Environment]::SetEnvironmentVariable(
    'DRJIT_LIBLLVM_PATH',
    'C:\<インストール先>\bin\LLVM-C.dll',
    'User'
)
```

> 注意: 既に起動済みのプロセスには反映されない．新規 PowerShell を開いた時点から有効化．

別の方法として，環境変数 `LLVM_DIR` を LLVM のインストールルートに設定しておくと，
自動探索が `$LLVM_DIR\bin\LLVM-C.dll`（Windows）/ `$LLVM_DIR/lib/libLLVM-C.so`（POSIX）を
優先候補として試す（`DRJIT_LIBLLVM_PATH` を DLL のフルパスで指定する代わりに使える）．

### 動作確認

インストール後，以下のコマンドで sm-render が正常起動することを確認する：

```powershell
uv run sm-render --scene configs/scene_baseline.yaml --output output/_check 2>&1 | Select-Object -First 10
```

初回ログに以下が出力されれば LLVM JIT 経路で正常動作している：

```
INFO ... Mitsuba variant=llvm_ad_rgb, LLVM JIT 経路で実行（DRJIT_LIBLLVM_PATH=C:\Program Files\LLVM\bin\LLVM-C.dll）
```

## トラブルシューティング (Troubleshooting)

### `uv sync` が遅い / 失敗する

- ネットワーク状態を確認．Mitsuba 3 の wheel はサイズが大きい（〜100 MB）
- 企業ネットワーク内ではプロキシ設定が必要：`uv` は環境変数 `HTTPS_PROXY` を尊重する

### scalar_rgb variant や ad-hoc スクリプトで `LLVM API initialization failed` が出る

- `llvm_init.py` の自動探索が働くのは **sm-render 等の CLI が llvm_* variant を要求した場合のみ**．
  以下の 2 ケースでは自動探索が呼ばれず，LLVM がインストール済みでも drjit 自身の探索が
  「jitc_llvm_init(): LLVM API initialization failed」で失敗することがある（2026-08-17 の新規構築マシンで確認）:
  - `variant: scalar_rgb` のシーンを sm-render で実行する場合（drjit は scalar でも LLVM を初期化しようとする）
  - `uv run python` で mitsuba を直接 import する ad-hoc スクリプト
- 対処: コマンド実行前に `$env:DRJIT_LIBLLVM_PATH = 'C:\Program Files\LLVM\bin\LLVM-C.dll'` を明示設定する
  （または「DRJIT_LIBLLVM_PATH の設定」セクションの手順で User scope に永続化する）．
- LLVM 22.1.8（winget 導入）で llvm_ad_rgb / scalar_rgb とも動作確認済み（明示設定時）．

### `LLVM-C.dll could not be found` エラーが出る

- コード側が自動探索を試みるが，LLVM が標準パス以外にインストールされているか，
  未インストールの場合はこのエラーが発生する
- まず `Test-Path 'C:\Program Files\LLVM\bin\LLVM-C.dll'` でファイルの存在を確認する
- ファイルがない場合: `winget install LLVM.LLVM` を管理者として実行
- ファイルはあるが標準パス以外にある場合: `DRJIT_LIBLLVM_PATH` 環境変数で明示指定する
  （「LLVM のインストール」セクション参照）

### Python 3.12 が手元にない

- `uv sync` が自動で取得する．手動インストール不要

## GPU 対応（任意）

CPU で実行が遅すぎる場合のオプション．導入は **任意**：

1. NVIDIA ドライバを更新
2. CUDA Toolkit 12.x をインストール（Mitsuba 3 のドキュメントが指定するバージョンに従う）
3. コード側で `mitsuba.set_variant('cuda_ad_rgb')` に切替え

詳細は Mitsuba 3 公式ドキュメントを参照．

## 研究室サーバ編 (Lab Server Setup)

研究室の GPU サーバでレンダを回すための初回セットアップ．編集は手元（Windows）で行い，`sm-remote` でコードを送ってサーバの tmux 上で実行し，結果を持ち帰る（日常の操作は [ENV_04 開発コマンド](ENV_04_開発コマンド.md) の「研究室サーバでの実行」）．
GitHub の認証情報はサーバに置かない（計算して結果を受け取るだけなので，サーバでは git を使わず常に手元から送る）．

| Host 名 | アドレス | 状態（2026-09-13 時点） |
| --- | --- | --- |
| `Newton` | `Newton.local`（IPv4 `192.168.23.14`） | Ubuntu 22.04，EPYC 64 スレッド，RTX A6000×3．鍵認証・uv・Python 3.12・`uv sync` 済み．通常はここを使う．学外からは `Newton-via-lab`（下記「学外から接続する」） |
| `Einstein` | `192.168.23.13` | パスワードは通るがホームディレクトリが無い（既知事項参照）．使用不可 |
| `Archimedes` | `192.168.23.15` | パスワードログインのみ（鍵は未登録） |

### SSH 接続設定 (SSH Config)

ssh は Windows 11 標準の OpenSSH（`C:\Windows\System32\OpenSSH\ssh.exe`）を使う．PowerShell からも Git Bash からも使える．Windows には rsync が無いため，転送は `sm-remote`（tar over ssh）で行う．

`C:\Users\<ユーザー名>\.ssh\config` に Host を登録する（例）:

```text
Host Newton
    HostName Newton.local
    User hasegawa
    IdentityFile ~/.ssh/id_ed25519

Host Einstein
    HostName 192.168.23.13
    User hasegawa
    IdentityFile ~/.ssh/id_ed25519

Host Archimedes
    HostName 192.168.23.15
    User hasegawa
    IdentityFile ~/.ssh/id_ed25519
```

### 鍵の生成と登録 (SSH Key)

鍵が無ければ生成する（Git Bash．パスフレーズなし）:

```bash
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
```

Windows には `ssh-copy-id` が無いので，PowerShell から公開鍵を流し込んで登録する（パスワードを 1 回聞かれる．重複登録はしない）:

```powershell
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | ssh Newton 'k=$(cat); mkdir -p ~/.ssh && chmod 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && (grep -qxF "$k" ~/.ssh/authorized_keys || echo "$k" >> ~/.ssh/authorized_keys)'
```

`ssh Newton hostname` がパスワード無しで通れば OK．

### uv と Python 3.12 の導入 (uv & Python)

サーバにログインして実行する:

```bash
curl -LsSf https://astral.sh/uv/install.sh | env UV_NO_MODIFY_PATH=1 sh
~/.local/bin/uv python install 3.12
```

- `UV_NO_MODIFY_PATH=1` はシェルの設定ファイルを書き換えないため．Ubuntu の `~/.profile` は `~/.local/bin` があればログイン時に PATH へ足すので，対話ログインでは `uv` で呼べる
- ただし `ssh Newton 'コマンド'` の非ログイン実行では `~/.profile` が読まれず `uv` が PATH に入らない．`sm-remote` は `~/.local/bin/uv` を絶対パスで呼ぶ（`--uv` / 環境変数 `SM_REMOTE_UV` で変更可）．ジョブ内では uv のディレクトリを PATH に足すので，スクリプトが呼ぶ `uv run sm-render` も動く
- tmux は `/usr/bin/tmux` に入っている（`sm-remote run` が使う）

### コードの転送 (Code Transfer)

手元のリポジトリで実行する:

```powershell
uv run sm-remote push
```

- 送り先: `Newton:~/lab/SmTIAS-LightSim`（`--host` / `--remote-dir`，または環境変数 `SM_REMOTE_HOST` / `SM_REMOTE_DIR` で変更可）
- 送らないもの: `.venv/`（Windows 用）・`output/`・`.git/`・`__pycache__/`・`.pytest_cache/`・`.ruff_cache/`・`configs/_tmp_*`（スイープ生成物．約 450 MB．必要なら `--include` / `--only` で個別に送る）
- gitignore 対象でも送るもの: `lightsim/`・`reference_measurement/`・`REFERENCE/`（実測参照データ．サーバでの評価に使う）
- 全体で約 160 MB．初回（2026-09-13，tar + ssh の手動転送）は LAN で 39 秒，以後の `sm-remote push` は 10 秒前後だった．日本語ファイル名（`configs/meshes/*.stl`）もそのまま展開される

### 依存の同期 (uv sync)

```bash
ssh Newton 'cd ~/lab/SmTIAS-LightSim && ~/.local/bin/uv sync'
```

以後の `uv run` は実行のたびに `uv.lock` との差分を自動で同期するので，`pyproject.toml` / `uv.lock` を変えて push した後も明示の `uv sync` は通常不要．

### 動作確認 (Verification)

サーバにログインして実行する:

```bash
cd ~/lab/SmTIAS-LightSim
uv run python -c "import mitsuba as mi; mi.set_variant('cuda_ad_rgb'); print(mi.__version__, mi.variant())"
uv run python -c "import mitsuba as mi; mi.set_variant('llvm_ad_rgb'); print(mi.__version__, mi.variant())"
```

`3.7.1 cuda_ad_rgb` / `3.7.1 llvm_ad_rgb` と表示されれば OK．全テストは手元から次のように回せる（2026-09-13 に全テスト通過を確認済み）:

```powershell
uv run sm-remote run --name pytest-all --yaml-variant -- python -m pytest -m ""
uv run sm-remote logs pytest-all -f
```

PowerShell で `-m '""'` と書くと `""` の 2 文字がそのまま渡り，pytest が「Wrong expression passed to '-m'」で止まる．空文字は `-m ""` と書く．

### VS Code から接続する（任意）(VS Code Remote)

サーバのファイルを見たり，ログを追ったりするだけなら VS Code の Remote - SSH 拡張でも接続できる．

1. 拡張 `ms-vscode-remote.remote-ssh` を入れる（`code --install-extension ms-vscode-remote.remote-ssh`）
2. `F1` →「Remote-SSH: Connect to Host...」→ `Newton` を選ぶ（`~/.ssh/config` の Host 名がそのまま出る）
3. フォルダ `~/lab/SmTIAS-LightSim` を開く

- **サーバ上では編集しない**．`sm-remote push` は手元の作業ツリーで上書き展開するので，サーバで直接直した内容は次の push で消える．編集は常に手元で行う
- サーバの端末で `sm-remote` を実行すると，自分自身へ ssh しようとするので止まって案内が出る．サーバ上で直接回すときは `tmux new -s <名前>` の中で `uv run ...` を実行する

### 学外から接続する（研究室 PC 経由）(Off-campus Access)

Newton は研究室 LAN 内のアドレスなので，学外からは直接つながらない．研究室の自分の PC（`DESKTOP-1QLOO91`．サーバとは別）が Tailscale に登録されているので，これを SSH の踏み台（ProxyJump）にする．Newton 側の設定は不要（手元の鍵がそのまま Newton まで届く）．

```text
手元の PC ──Tailscale──▶ 研究室 PC（100.89.10.108）──研究室 LAN──▶ Newton
```

研究室 PC（リモートデスクトップで操作．**実行前に `hostname` で `DESKTOP-1QLOO91` と出ることを確かめる**）の管理者 PowerShell で，OpenSSH Server を入れて Tailscale からの接続だけを受け付ける:

```powershell
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
Set-NetFirewallRule -Name OpenSSH-Server-In-TCP -RemoteAddress 100.64.0.0/10
```

手元の公開鍵（`~/.ssh/id_ed25519.pub` の中身）を研究室 PC に登録する．研究室 PC のアカウント（`papin`）は管理者なので，Windows の OpenSSH の規則により鍵はユーザーの `.ssh` ではなく `C:\ProgramData\ssh\administrators_authorized_keys` に置き，権限を Administrators と SYSTEM だけに絞る（絞らないと sshd がファイルを無視する）:

```powershell
$key = '<手元の id_ed25519.pub の中身>'
Add-Content -Path C:\ProgramData\ssh\administrators_authorized_keys -Value $key
icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
```

手元の `~/.ssh/config` に追記する:

```text
Host labpc
    HostName 100.89.10.108
    User papin

Host Newton-via-lab
    HostName Newton.local
    User hasegawa
    ProxyJump labpc
```

`ssh labpc hostname` と `ssh Newton-via-lab hostname` がパスワード無しで通れば OK（2026-09-13 に確認．Newton まで 2 秒）．`sm-remote` は接続先を変えるだけで同じように使える:

```powershell
$env:SM_REMOTE_HOST = "Newton-via-lab"   # この PowerShell の間だけ有効．毎回 --host Newton-via-lab を付けてもよい
uv run sm-remote status
```

- 研究室にいるときは従来どおり `Newton` を使う（踏み台を経由しない分速い）
- 手で `ssh Newton-via-lab 'cat ...' > ファイル` のように出力を受け取るとき，応答が返らず止まることがあった（`hostname` のような短いコマンドは通る．原因は未確認）．`ssh -n`（標準入力を閉じる）を付けると通った．`sm-remote` は標準入力を閉じて ssh を呼ぶので影響しない
- Tailscale が直接つながらず中継サーバ（DERP）経由になっていると転送が遅い（`tailscale ping desktop-1qloo91` で `via DERP` と出る）．学外からの push は `--only src` のように変えた部分だけにする
- 失敗パターン: 研究室 PC と手元 PC の管理者 PowerShell はプロンプトが同じ（`PS C:\Windows\system32>`）ため，鍵の登録を手元 PC で実行してしまい，研究室 PC で `Permission denied (publickey,...)` になった．sshd のログ（`Get-WinEvent -LogName OpenSSH/Operational`）には理由が出ず `Connection reset ... [preauth]` だけだった
- 研究室 PC で SSH サーバを動かしてよいかは研究室のルールに照らして確認する（上の設定で受け付けるのは Tailscale の中＝自分のアカウントの機器からだけ）

### 既知事項 (Known Issues)

- Einstein はホームディレクトリ `/home/hasegawa` が無い．ログイン時に「Could not chdir to home directory」「mkdir: cannot create directory '/home/hasegawa': Permission denied」が出て，鍵登録・VS Code Remote ができない．管理者によるホーム作成待ち（Newton では sudo グループだが，Einstein の権限は未確認）
- Archimedes は鍵が未登録．使う場合は「鍵の生成と登録」の手順で登録する
- GPU は他ユーザーが 1・2 番を使っていることがある（研究室の利用ルールは特に無い）．`sm-remote status` で空きを見てから `--gpu` で指定する
- LLVM: Ubuntu では `/usr/lib/x86_64-linux-gnu/libLLVM-15.so`（`libLLVM-<版>.so` 形式）で提供され，`libLLVM-C.so` は無い．`runtime/llvm_init.py` はこの形式と `/usr/lib/llvm-*/lib/` も探索する（以前は見つけられず「libLLVM-C.so が見つかりません」と誤警告していた．Dr.Jit 自身は見つけるので `llvm_ad_rgb` は元から動いていた）
- 共用サーバの CPU: `llvm_ad_rgb` は既定で全 64 スレッドを使う（loadavg が 33 から 87 に上がるのを実測）．CPU で回すときは `sm-remote run --threads N`（環境変数 `SM_DRJIT_THREADS`）で上限を付ける（`--threads 16` で CPU 使用率 1698% を実測）
- サーバの `uv run` は毎回 `build_system.requires = ["uv-build>=0.11.7,<0.12.0"]` does not contain the current uv version 0.12.13 という警告を出す．ビルドバックエンド（uv_build）の版とサーバの uv 本体の版の食い違いを知らせるだけで，動作には影響しない
