🏗️ Refactor: Major LLVM codegen modularization + Phase 15 docs cleanup + Phase 21 DDD concept
## LLVM Codegen Refactoring (by ChatGPT5) - Split massive boxcall.rs into focused submodules: - strings.rs: String method optimizations (concat, length) - arrays.rs: Array operations (get, set, push, length) - maps.rs: Map operations (get, set, has, size) - fields.rs: getField/setField handling - invoke.rs: Tagged invoke implementation - marshal.rs: Helper functions for marshaling - Improved code organization and maintainability - No functional changes, pure refactoring ## Phase 15 Documentation Cleanup - Restructured phase-15 folder: - implementation/: Technical implementation docs - planning/: Planning and sequence docs - archive/: Redundant/old content - Removed duplicate content (80k→20k line reduction mentioned 5 times) - Converted all .txt files to .md for consistency - Fixed broken links in README.md - Removed redundant INDEX.md ## Phase 21: Database-Driven Development (New) - Revolutionary concept: Source code in SQLite instead of files - Instant refactoring with SQL transactions - Structured management of boxes, methods, dependencies - Technical design with security considerations - Vision: World's first DB-driven programming language 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -0,0 +1,469 @@
|
||||
# Phase 15: セルフホスティング技術詳細
|
||||
|
||||
## 1. アーキテクチャ設計
|
||||
|
||||
### 1.1 全体構成
|
||||
|
||||
```
|
||||
NyashCompiler (Nyashで実装)
|
||||
├── Frontend
|
||||
│ ├── Lexer (トークナイザー)
|
||||
│ ├── Parser (構文解析)
|
||||
│ └── AST Builder
|
||||
├── Middle-end
|
||||
│ ├── Type Checker
|
||||
│ ├── Name Resolver
|
||||
│ ├── MIR Lowerer (→13命令)
|
||||
│ └── Optimizer
|
||||
└── Backend(複数選択可能)
|
||||
├── CraneliftBox (JITラッパー)
|
||||
├── X86EmitterBox (直接エミッタ)
|
||||
├── TemplateStitcherBox (超小型)
|
||||
└── Runtime Linker
|
||||
```
|
||||
|
||||
### 1.2 CompilerBox設計
|
||||
|
||||
```nyash
|
||||
box CompilerBox {
|
||||
init {
|
||||
lexer, // トークン解析器
|
||||
parser, // 構文解析器
|
||||
lowerer, // MIR生成器
|
||||
optimizer, // 最適化器
|
||||
backend // コード生成器
|
||||
}
|
||||
|
||||
// ソースコードからASTを生成
|
||||
parse(source) {
|
||||
local tokens = me.lexer.tokenize(source)
|
||||
local ast = me.parser.parse(tokens)
|
||||
return ast
|
||||
}
|
||||
|
||||
// ASTからMIRを生成
|
||||
lower(ast) {
|
||||
local mir = me.lowerer.lower(ast)
|
||||
return me.optimizer.optimize(mir)
|
||||
}
|
||||
|
||||
// MIRから実行可能コードを生成
|
||||
codegen(mir) {
|
||||
return me.backend.generate(mir)
|
||||
}
|
||||
|
||||
// 完全なコンパイルパイプライン
|
||||
compile(source) {
|
||||
local ast = me.parse(source)
|
||||
local mir = me.lower(ast)
|
||||
return me.codegen(mir)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. パーサー実装(Nyash版)
|
||||
|
||||
### 2.1 Lexer実装例
|
||||
|
||||
```nyash
|
||||
box Lexer {
|
||||
init { keywords, operators }
|
||||
|
||||
constructor() {
|
||||
me.keywords = new MapBox()
|
||||
me.keywords.set("box", TokenType.BOX)
|
||||
me.keywords.set("if", TokenType.IF)
|
||||
me.keywords.set("loop", TokenType.LOOP)
|
||||
// ... 他のキーワード
|
||||
|
||||
me.operators = new MapBox()
|
||||
me.operators.set("+", TokenType.PLUS)
|
||||
me.operators.set("-", TokenType.MINUS)
|
||||
// ... 他の演算子
|
||||
}
|
||||
|
||||
tokenize(source) {
|
||||
local tokens = new ArrayBox()
|
||||
local position = 0
|
||||
|
||||
loop(position < source.length()) {
|
||||
local char = source.charAt(position)
|
||||
|
||||
if me.isWhitespace(char) {
|
||||
position = position + 1
|
||||
continue
|
||||
}
|
||||
|
||||
if me.isDigit(char) {
|
||||
local token = me.readNumber(source, position)
|
||||
tokens.push(token)
|
||||
position = token.end
|
||||
continue
|
||||
}
|
||||
|
||||
if me.isLetter(char) {
|
||||
local token = me.readIdentifier(source, position)
|
||||
tokens.push(token)
|
||||
position = token.end
|
||||
continue
|
||||
}
|
||||
|
||||
// ... 他のトークン種別
|
||||
}
|
||||
|
||||
return tokens
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Parser実装例
|
||||
|
||||
```nyash
|
||||
box Parser {
|
||||
init { tokens, current }
|
||||
|
||||
parse(tokens) {
|
||||
me.tokens = tokens
|
||||
me.current = 0
|
||||
return me.parseProgram()
|
||||
}
|
||||
|
||||
parseProgram() {
|
||||
local statements = new ArrayBox()
|
||||
|
||||
loop(not me.isAtEnd()) {
|
||||
local stmt = me.parseStatement()
|
||||
statements.push(stmt)
|
||||
}
|
||||
|
||||
return new ASTNode("Program", statements)
|
||||
}
|
||||
|
||||
parseStatement() {
|
||||
if me.match(TokenType.BOX) {
|
||||
return me.parseBoxDeclaration()
|
||||
}
|
||||
|
||||
if me.match(TokenType.IF) {
|
||||
return me.parseIfStatement()
|
||||
}
|
||||
|
||||
// ... 他の文種別
|
||||
|
||||
return me.parseExpression()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. MIR生成器実装
|
||||
|
||||
### 3.1 Lowerer実装例
|
||||
|
||||
```nyash
|
||||
box MIRLowerer {
|
||||
init {
|
||||
current_block,
|
||||
value_counter,
|
||||
block_counter,
|
||||
locals
|
||||
}
|
||||
|
||||
lower(ast) {
|
||||
me.value_counter = 0
|
||||
me.block_counter = 0
|
||||
me.locals = new MapBox()
|
||||
|
||||
local mir = new MIRModule()
|
||||
me.lowerNode(ast, mir)
|
||||
return mir
|
||||
}
|
||||
|
||||
lowerExpression(node, mir) {
|
||||
if node.type == "BinaryOp" {
|
||||
local left = me.lowerExpression(node.left, mir)
|
||||
local right = me.lowerExpression(node.right, mir)
|
||||
local result = me.newValue()
|
||||
|
||||
mir.addInstruction(new BinOp(
|
||||
node.operator,
|
||||
left,
|
||||
right,
|
||||
result
|
||||
))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
if node.type == "Literal" {
|
||||
local result = me.newValue()
|
||||
mir.addInstruction(new Const(node.value, result))
|
||||
return result
|
||||
}
|
||||
|
||||
// ... 他の式種別
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. バックエンド実装
|
||||
|
||||
### 4.1 CraneliftBox実装
|
||||
|
||||
```nyash
|
||||
box CraneliftBox {
|
||||
init { jit_module, func_ctx }
|
||||
|
||||
constructor() {
|
||||
// CraneliftをFFI経由で初期化
|
||||
me.jit_module = ExternCall("cranelift_new_module")
|
||||
me.func_ctx = ExternCall("cranelift_new_context")
|
||||
}
|
||||
|
||||
compile(mir) {
|
||||
local compiled_funcs = new MapBox()
|
||||
|
||||
// 各関数をコンパイル
|
||||
for func in mir.functions {
|
||||
local code = me.compileFunction(func)
|
||||
compiled_funcs.set(func.name, code)
|
||||
}
|
||||
|
||||
return compiled_funcs
|
||||
}
|
||||
|
||||
compileFunction(mir_func) {
|
||||
// MIR → Cranelift IR変換
|
||||
ExternCall("cranelift_begin_function", me.func_ctx)
|
||||
|
||||
for inst in mir_func.instructions {
|
||||
me.emitInstruction(inst)
|
||||
}
|
||||
|
||||
// JITコンパイル
|
||||
return ExternCall("cranelift_finalize_function", me.func_ctx)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 X86EmitterBox実装(直接x86生成)
|
||||
|
||||
```nyash
|
||||
box X86EmitterBox {
|
||||
init { code_buffer, label_map }
|
||||
|
||||
constructor() {
|
||||
me.code_buffer = new ArrayBox()
|
||||
me.label_map = new MapBox()
|
||||
}
|
||||
|
||||
compile(mir) {
|
||||
// MIR 13命令を直接x86-64に変換!
|
||||
for func in mir.functions {
|
||||
me.emitFunction(func)
|
||||
}
|
||||
|
||||
return me.code_buffer
|
||||
}
|
||||
|
||||
emitInstruction(inst) {
|
||||
// MIR命令をx86テンプレートに変換
|
||||
if inst.type == "Const" {
|
||||
// mov rax, imm64
|
||||
me.emit_mov_imm(inst.dst, inst.value)
|
||||
}
|
||||
|
||||
if inst.type == "BinOp" {
|
||||
if inst.op == "Add" {
|
||||
// add rax, rbx
|
||||
me.emit_add(inst.dst, inst.left, inst.right)
|
||||
}
|
||||
}
|
||||
|
||||
if inst.type == "BoxCall" {
|
||||
// mov rdi, receiver
|
||||
// mov rax, [rdi] ; vtable
|
||||
// call [rax+slot*8] ; method call
|
||||
me.emit_boxcall(inst.recv, inst.slot)
|
||||
}
|
||||
|
||||
// ... 残り10命令のテンプレート
|
||||
}
|
||||
|
||||
emit_mov_imm(reg, value) {
|
||||
// REX.W + mov r64, imm64
|
||||
me.code_buffer.push(0x48) // REX.W
|
||||
me.code_buffer.push(0xB8 + reg) // mov opcode
|
||||
|
||||
// 64ビット即値をリトルエンディアンで
|
||||
for i in range(0, 8) {
|
||||
me.code_buffer.push((value >> (i * 8)) & 0xFF)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 テンプレート・スティッチャ実装(超小型バイナリ)
|
||||
|
||||
```nyash
|
||||
box TemplateStitcherBox {
|
||||
init { stub_addresses, jump_table }
|
||||
|
||||
constructor() {
|
||||
// 各MIR命令の共通スタブアドレス
|
||||
me.stub_addresses = new MapBox()
|
||||
me.stub_addresses.set("Const", 0x1000)
|
||||
me.stub_addresses.set("UnaryOp", 0x1100)
|
||||
me.stub_addresses.set("BinOp", 0x1200)
|
||||
me.stub_addresses.set("Compare", 0x1300)
|
||||
me.stub_addresses.set("TypeOp", 0x1400)
|
||||
me.stub_addresses.set("Load", 0x1500)
|
||||
me.stub_addresses.set("Store", 0x1600)
|
||||
me.stub_addresses.set("Branch", 0x1700)
|
||||
me.stub_addresses.set("Jump", 0x1800)
|
||||
me.stub_addresses.set("Return", 0x1900)
|
||||
me.stub_addresses.set("Phi", 0x1A00)
|
||||
me.stub_addresses.set("BoxCall", 0x1B00)
|
||||
me.stub_addresses.set("ExternCall", 0x1C00)
|
||||
}
|
||||
|
||||
compile(mir) {
|
||||
me.jump_table = new ArrayBox()
|
||||
|
||||
// プログラムはスタブへのジャンプ列として表現
|
||||
for inst in mir.instructions {
|
||||
local stub_addr = me.stub_addresses.get(inst.type)
|
||||
|
||||
// jmp rel32
|
||||
me.jump_table.push(0xE9) // jmp opcode
|
||||
me.jump_table.push_rel32(stub_addr)
|
||||
|
||||
// 命令固有のパラメータをデータセクションに配置
|
||||
me.encodeParameters(inst)
|
||||
}
|
||||
|
||||
return me.jump_table
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. ブートストラップ手順
|
||||
|
||||
### 5.1 段階的移行
|
||||
|
||||
1. **Stage 0**: Rustコンパイラで初期Nyashコンパイラをビルド
|
||||
2. **Stage 1**: Stage 0コンパイラでNyashコンパイラ(Nyash版)をコンパイル
|
||||
3. **Stage 2**: Stage 1コンパイラで自分自身をコンパイル
|
||||
4. **検証**: Stage 1とStage 2の出力が同一であることを確認
|
||||
|
||||
### 5.2 検証スクリプト
|
||||
|
||||
```nyash
|
||||
box BootstrapVerifier {
|
||||
verify() {
|
||||
// Stage 0でStage 1をビルド
|
||||
local stage0 = new CompilerBox() // Rust版
|
||||
local stage1_code = stage0.compile(readFile("compiler.nyash"))
|
||||
|
||||
// Stage 1でStage 2をビルド
|
||||
local stage1 = stage1_code.instantiate()
|
||||
local stage2_code = stage1.compile(readFile("compiler.nyash"))
|
||||
|
||||
// バイナリ比較
|
||||
if stage1_code.equals(stage2_code) {
|
||||
print("🎉 Bootstrap successful!")
|
||||
return true
|
||||
} else {
|
||||
print("❌ Bootstrap failed - outputs differ")
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 性能最適化
|
||||
|
||||
### 6.1 ホットパス最適化
|
||||
|
||||
```nyash
|
||||
box OptimizingCompiler from CompilerBox {
|
||||
init { profiler }
|
||||
|
||||
constructor() {
|
||||
from CompilerBox.constructor()
|
||||
me.profiler = new ProfilerBox()
|
||||
}
|
||||
|
||||
compile(source) {
|
||||
// プロファイル収集モード
|
||||
if me.profiler.isEnabled() {
|
||||
me.profiler.start()
|
||||
}
|
||||
|
||||
local result = from CompilerBox.compile(source)
|
||||
|
||||
// ホット関数をJIT再コンパイル
|
||||
if me.profiler.hasHotFunctions() {
|
||||
for func in me.profiler.getHotFunctions() {
|
||||
me.recompileWithOptimization(func)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7. エラー処理とデバッグ
|
||||
|
||||
### 7.1 エラーレポート
|
||||
|
||||
```nyash
|
||||
box CompilerError {
|
||||
init { message, location, suggestions }
|
||||
|
||||
format() {
|
||||
local output = "Error at " + me.location + ": " + me.message
|
||||
|
||||
if me.suggestions.length() > 0 {
|
||||
output = output + "\nSuggestions:"
|
||||
for suggestion in me.suggestions {
|
||||
output = output + "\n - " + suggestion
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 8. テストフレームワーク
|
||||
|
||||
```nyash
|
||||
box CompilerTest {
|
||||
testParser() {
|
||||
local parser = new Parser()
|
||||
local ast = parser.parse("box Test { }")
|
||||
|
||||
assert(ast.type == "Program")
|
||||
assert(ast.children.length() == 1)
|
||||
assert(ast.children[0].type == "BoxDeclaration")
|
||||
}
|
||||
|
||||
testMIRGeneration() {
|
||||
local compiler = new CompilerBox()
|
||||
local mir = compiler.lower(compiler.parse("1 + 2"))
|
||||
|
||||
assert(mir.instructions.length() == 3) // 2 Const + 1 BinOp
|
||||
}
|
||||
|
||||
testEndToEnd() {
|
||||
local compiler = new CompilerBox()
|
||||
local code = compiler.compile("print('Hello')")
|
||||
local output = code.run()
|
||||
|
||||
assert(output == "Hello")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
このようにして、NyashでNyashコンパイラを実装することで、真のセルフホスティングを実現します。
|
||||
@ -0,0 +1,139 @@
|
||||
# Phase 15 自己ホスティング準備メモ - 箱積み上げ戦略
|
||||
|
||||
Date: 2025-09-03
|
||||
Author: Claude + にゃ
|
||||
|
||||
## 基本理念:箱を下にして積み重ねる
|
||||
|
||||
- フォールバック不要、Rust依存なし(EXEライブラリのみ)
|
||||
- 一度置いた箱は動かさない
|
||||
- 下の箱が安定なら、上も安定
|
||||
- 複雑さは敵、シンプルさは友
|
||||
|
||||
## 基礎Box群の階層構造
|
||||
|
||||
### 第1層(最下層):これがないと何も始まらない
|
||||
- **MemoryBox**: メモリ管理
|
||||
- **StringBox**: 文字列処理
|
||||
- **ArrayBox**: 配列操作
|
||||
- **MapBox**: 連想配列
|
||||
- **ErrorBox**: エラー処理
|
||||
|
||||
### 第2層:言語処理の基礎
|
||||
- **TokenBox**: 字句解析
|
||||
- **ASTBox**: 構文木
|
||||
- **SymbolBox**: シンボルテーブル
|
||||
- **ScopeBox**: スコープ管理
|
||||
|
||||
### 第3層:コンパイラコア
|
||||
- **ParserBox**: パーサー
|
||||
- **MIRBox**: 中間表現(13命令)
|
||||
- **OptimizerBox**: 最適化
|
||||
- **GeneratorBox**: コード生成
|
||||
|
||||
### 第4層:実行系
|
||||
- **InterpreterBox**: インタープリター
|
||||
- **VMBox**: 仮想マシン
|
||||
- **JITBox**: JITコンパイラ(Cranelift)
|
||||
- **LinkerBox**: リンカー(lld)
|
||||
|
||||
## 準備期間の研究項目
|
||||
|
||||
### 1. 依存関係マップ作成
|
||||
- 何が何に依存?
|
||||
- 最小限の依存で最大の効果
|
||||
- 循環依存の排除
|
||||
|
||||
### 2. インターフェース設計
|
||||
- 全Boxの共通プロトコル
|
||||
- 入力/出力の標準化
|
||||
- エラー処理の統一
|
||||
|
||||
### 3. ビルド順序の科学
|
||||
- Day 1: 基礎Box群
|
||||
- Day 2: 言語処理層
|
||||
- Day 3: コンパイラ層
|
||||
- 完成まで一直線
|
||||
|
||||
### 4. 最小ブートストラップセット
|
||||
- 自分自身をコンパイルできる最小構成
|
||||
- 必須機能の特定
|
||||
- 段階的な機能追加
|
||||
|
||||
## 箱の品質保証原則
|
||||
|
||||
1. **単体で完結** - 他に依存しすぎない
|
||||
2. **明確な責務** - 1つの箱は1つの仕事
|
||||
3. **テスト可能** - 単独で動作確認
|
||||
4. **不変インターフェース** - 一度決めたら変更なし
|
||||
|
||||
## 実装戦略
|
||||
|
||||
1. Rust実装の機能分解(Box単位)
|
||||
2. 各Boxの仕様書作成
|
||||
3. テストケースの移植計画
|
||||
4. Box間プロトコル設計
|
||||
5. 最小実装から始める
|
||||
6. 増分的に機能追加
|
||||
|
||||
## 成功の鍵
|
||||
|
||||
- 準備こそすべて
|
||||
- 急いで実装より、じっくり設計
|
||||
- 箱を積み重ねれば必ず頂上に到達
|
||||
- フォールバックなし、後戻りなし、前進あるのみ
|
||||
|
||||
## 革新的アイデア
|
||||
|
||||
### 1. BoxDNA設計書
|
||||
- 各Boxの入力/出力/依存を明文化
|
||||
- 遺伝子のように継承・組み合わせ
|
||||
|
||||
### 2. 増分コンパイル対応
|
||||
- 変更部分だけ再コンパイル
|
||||
- 開発効率の向上
|
||||
|
||||
### 3. 可視化ツール
|
||||
- 進捗の見える化
|
||||
- 依存関係の図示
|
||||
|
||||
## 数値目標
|
||||
|
||||
- **80,000行 → 20,000行**(75%削減)
|
||||
- **MIR13命令**で全機能実現
|
||||
- **ビルド時間**:1分以内
|
||||
- **テストカバレッジ**:90%以上
|
||||
|
||||
## コンテキスト圧縮対策
|
||||
|
||||
### 1. ANCP活用(Phase 12.7)
|
||||
- 90%圧縮でAIコンテキスト節約
|
||||
- [ANCP仕様書](../../../phase-12.7/ancp-specs/ANCP-Token-Specification-v1.md)
|
||||
|
||||
### 2. モジュール分割開発
|
||||
- 各Boxを独立して開発
|
||||
- 統合は最後に実施
|
||||
|
||||
### 3. AI協調開発
|
||||
- Claude:実装担当
|
||||
- ChatGPT5:リファクタリング
|
||||
- Gemini:レビュー
|
||||
- Codex:デバッグ支援
|
||||
|
||||
## 関連ドキュメント
|
||||
|
||||
- [自己ホスティングlld戦略](./lld-strategy.md)
|
||||
- [Phase 15 README](../README.md)
|
||||
- [Phase 12.7 ANCP](../../../phase-12.7/)
|
||||
- [MIR13命令セット](../../../../../reference/mir/INSTRUCTION_SET.md)
|
||||
|
||||
## 次のアクション
|
||||
|
||||
1. このメモをベースに詳細設計
|
||||
2. Box依存関係グラフの作成
|
||||
3. 最小実装セットの確定
|
||||
4. 各Boxの仕様書ドラフト
|
||||
|
||||
---
|
||||
|
||||
「箱を積み上げて、世界一美しいコンパイラを作るにゃ!」
|
||||
@ -0,0 +1,196 @@
|
||||
# Phase 15 自己ホスティング実装戦略 - MIR→Cranelift→lld
|
||||
|
||||
Author: ChatGPT5 + Claude協議
|
||||
Date: 2025-09-03
|
||||
Version: 1.0
|
||||
|
||||
## 📋 概要
|
||||
|
||||
Nyash完全自己ホスティングを実現するための具体的実装戦略。
|
||||
**「MIR→Craneliftで.o/.objを作る→lldでEXEを組む」**をNyashツールチェーンに内蔵する。
|
||||
|
||||
## 🎯 最終形(自己ホスト時の一発ボタン)
|
||||
|
||||
```bash
|
||||
nyash build main.ny \
|
||||
--backend=cranelift \
|
||||
--target=x86_64-pc-windows-msvc # or x86_64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
内部処理フロー:
|
||||
1. **frontend**: AST→MIR13
|
||||
2. **codegen**: MIR→Cranelift→`.obj/.o`
|
||||
3. **link**: `lld-link`(Win) / `ld.lld`(Linux)でEXE生成
|
||||
4. 依存ランタイム`nyashrt`を自動リンク(静的/動的選択)
|
||||
|
||||
## 🏗️ 実装の芯(最小で美しいやつ)
|
||||
|
||||
### 1. コード生成ライブラリ(C ABIファサード)
|
||||
|
||||
```c
|
||||
// 最小限の美しいインターフェース
|
||||
ny_mir_to_obj(mir_bin, target_triple) -> obj_bytes
|
||||
ny_mir_jit_entry(mir_bin) -> exit_code // 開発用
|
||||
ny_free_buf(buffer) // メモリ解放
|
||||
|
||||
// エラーハンドリング
|
||||
// 例外は戻り値+NyErr(unwind禁止)
|
||||
```
|
||||
|
||||
実装のポイント:
|
||||
- 返却メモリは`ny_free_buf`で解放
|
||||
- 例外は戻り値+NyErrで統一(unwind禁止)
|
||||
- C ABIで安定した境界を作る
|
||||
|
||||
### 2. リンカー・ラッパ(プラットフォーム別)
|
||||
|
||||
#### Windows
|
||||
- 既定: `lld-link`
|
||||
- 主要フラグ:
|
||||
```bash
|
||||
lld-link <objs...> nyashrt.lib /SUBSYSTEM:CONSOLE \
|
||||
/OUT:a.exe /ENTRY:nyash_entry \
|
||||
/LIBPATH:<sdk/lib> /MACHINE:X64
|
||||
```
|
||||
- MSVC互換が要る配布向けに`/fallback:link.exe`オプションも用意可
|
||||
|
||||
#### Linux
|
||||
- 既定: `ld.lld`(開発で`mold`併用可)
|
||||
```bash
|
||||
ld.lld -o a.out main.o -L. -lnyashrt -lc -lm -pthread \
|
||||
--gc-sections --icf=all
|
||||
```
|
||||
|
||||
#### macOS(将来)
|
||||
- 日常は`ld64.lld`、配布はXcodeの`ld64` + コード署名(要Entitlements)
|
||||
|
||||
### 3. 同梱/検出戦略
|
||||
|
||||
**優先順**: 埋め込み`lld` → システム`lld` → 代替(mold/link.exe/ld64)
|
||||
|
||||
```bash
|
||||
nyash toolchain doctor # 検出&パス設定
|
||||
--linker=lld|mold|link.exe|ld64 # 明示上書き
|
||||
```
|
||||
|
||||
### 4. ランタイム同梱
|
||||
|
||||
- `nyashrt`を**static(.a/.lib)**と**shared(.so/.dll)**両用意
|
||||
- 既定は**static**(配布が楽)、`--shared-rt`で動的リンクに切替
|
||||
- Windowsは**PDB生成**、Linuxは`-g`/`-Wl,--build-id`でデバッグ容易に
|
||||
|
||||
## 🔧 エラー整合(ビルド失敗をわかりやすく)
|
||||
|
||||
| エラー種別 | 戻り値 | 説明・対処 |
|
||||
|----------|-------|-----------|
|
||||
| `ny_mir_to_obj`失敗 | `NYCG_ERR_*` | ターゲット不一致/CLIF生成失敗など |
|
||||
| リンク失敗 | リンカ標準出力 | ファイル名/未解決シンボルを整形表示 |
|
||||
|
||||
診断オプション:
|
||||
```bash
|
||||
--emit=clif,asm,obj,link-cmd # 診断をファイル出力(再現しやすい)
|
||||
```
|
||||
|
||||
## 💾 キャッシュ&クロスコンパイル
|
||||
|
||||
### オブジェクトキャッシュ
|
||||
`hash(MIR, target, codegen_ver)` → `.obj/.o`を再利用
|
||||
|
||||
### クロスコンパイル
|
||||
```bash
|
||||
--target=<triple> # .obj/.oとリンク器/SDKを切替
|
||||
```
|
||||
- Win用: `x86_64-pc-windows-msvc`(`lld-link` + MSVCライブラリ)
|
||||
- Linux: `x86_64-unknown-linux-gnu`(`ld.lld` + glibc)
|
||||
|
||||
**Zig toolchain**を併用するとクロス用のCRT/SDKが楽(内部はlld)
|
||||
|
||||
## 🎨 使いやすいCLI例
|
||||
|
||||
```bash
|
||||
nyash build main.ny --backend=cranelift --release
|
||||
nyash build main.ny --emit=obj,asm,clif # 解析用
|
||||
nyash run main.ny --backend=cranelift # JITで即実行
|
||||
nyash toolchain doctor # lld/SDK検出
|
||||
```
|
||||
|
||||
## ⚡ 地味に効く最適化スイッチ
|
||||
|
||||
### リンカ最適化
|
||||
- `ld.lld`: `--gc-sections --icf=all`(不要コード除去&同一関数折りたたみ)
|
||||
|
||||
### Cranelift最適化
|
||||
- `opt_level=speed`
|
||||
- TypedArrayの**bounds-check併合**をLowerで実装
|
||||
|
||||
### 実行時最適化
|
||||
- 起動時CPUIDで**関数ポインタ切替**(AVX2/512の専用小関数)
|
||||
|
||||
## ✅ 最初の"動くまで"チェックリスト
|
||||
|
||||
- [ ] `ny_mir_to_obj`(C ABI)で`.o/.obj`を返せる
|
||||
- [ ] `nyash link <obj> --target=<triple>`が`lld`でEXEを作れる
|
||||
- [ ] Windows/Linuxそれぞれ"Hello, Box!"実行成功
|
||||
- [ ] `--emit=clif,asm`でダンプが落ちる
|
||||
- [ ] 失敗時のエラーメッセージが**ファイル名+未解決シンボル**まで出る
|
||||
- [ ] `nyash toolchain doctor`でlld/SDK検出
|
||||
|
||||
## 📐 実装設計詳細
|
||||
|
||||
### LinkerBox設計
|
||||
```nyash
|
||||
box LinkerBox {
|
||||
init { platform, linker_path, libraries, flags }
|
||||
|
||||
link(objects, output_path) {
|
||||
local cmd = me.build_link_command(objects, output_path)
|
||||
local result = me.execute_linker(cmd)
|
||||
|
||||
if result.exit_code != 0 {
|
||||
me.format_link_error(result.stderr)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
detect_linker() {
|
||||
// 優先順: 内蔵lld → システムlld → 代替
|
||||
if me.has_embedded_lld() {
|
||||
return me.extract_embedded_lld()
|
||||
}
|
||||
return me.find_system_linker()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### CraneliftBox統合
|
||||
```nyash
|
||||
box CraneliftBox {
|
||||
init { target_triple, opt_level }
|
||||
|
||||
compile(mir) {
|
||||
// MIR13 → Cranelift IR → Object
|
||||
local module = me.create_module()
|
||||
|
||||
for inst in mir.instructions {
|
||||
me.lower_instruction(module, inst)
|
||||
}
|
||||
|
||||
return module.compile()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🌟 まとめ
|
||||
|
||||
- **Yes**: CraneliftでEXEにするには**内部でlldを叩く機能を埋め込む**のが正攻法
|
||||
- 仕組みは**MIR→Cranelift .o/.obj → lld**
|
||||
- C ABIファサード経由でcodegenを呼び、リンカは**内蔵ドライバ**で統一
|
||||
- これで**自己ホスト→即EXE生成**の"気持ちいい体験"が完成!
|
||||
|
||||
## 🔗 関連ドキュメント
|
||||
|
||||
- [Phase 15メインドキュメント](README.md)
|
||||
- [C ABI境界設計](../phase-12/c-abi-spec.md)
|
||||
- [MIR 13命令セット](../../reference/mir/INSTRUCTION_SET.md)
|
||||
- [Cranelift統合](../phase-10/)
|
||||
Reference in New Issue
Block a user