チュートリアル

このチュートリアルでは、Konpeito のインストールから実際のコードを動かすところまでを一通り体験します。

1. インストール

前提条件

依存 バージョン 用途
Ruby 4.0.1+ 必須(コンパイラ本体の実行)
LLVM 20 CRuby ネイティブバックエンド、mruby バックエンド
Java 21+ JVM バックエンド
mruby 3.x or 4.x mruby バックエンド

LLVM、Java、mruby は使うバックエンドに応じて必要になります。いずれか1つだけでも動きます。

Konpeito のインストール

gem install konpeito

LLVM 20 のインストール(CRuby バックエンド用)

macOS:

brew install llvm@20
ln -sf /opt/homebrew/opt/llvm@20/lib/libLLVM-20.dylib /opt/homebrew/lib/
gem install ruby-llvm

Ubuntu / Debian:

sudo apt install llvm-20 clang-20
gem install ruby-llvm

Fedora:

sudo dnf install llvm20 clang20
gem install ruby-llvm

Java 21 のインストール(JVM バックエンド用)

macOS:

brew install openjdk@21

Ubuntu / Debian:

sudo apt install openjdk-21-jdk

Fedora:

sudo dnf install java-21-openjdk-devel

環境チェック

konpeito doctor              # CRuby バックエンドを確認
konpeito doctor --target jvm # JVM バックエンドを確認

必要なツールがすべてインストールされていれば、緑のチェックマークが表示されます。以下の2つの WARNING は正常なので無視して構いません:

  • ASM tool: WARNING — JVM バックエンド用のバイトコードアセンブラです。初回の JVM ビルド時に自動でビルドされるため、事前の対応は不要です。
  • Config: WARNING — カレントディレクトリに konpeito.toml が見つからないという意味です。プロジェクトをまだ作成していない場合は正常です。konpeito init で作成するか、ソースファイルを直接 konpeito build に渡せば問題ありません。

2. Hello World

CRuby バックエンド(ネイティブ拡張)

# hello.rb
module Hello
  def self.greet(name)
    "Hello, #{name}!"
  end
end
konpeito build hello.rb   # → hello.bundle (macOS) / hello.so (Linux)

Ruby から使う:

require_relative "hello"
puts Hello.greet("World")   # => "Hello, World!"

コンパイルされた拡張は標準の CRuby C 拡張です。C で書かれた gem と同じように、どの Ruby プロセスからでもロードできます。モジュールで囲むことでトップレベルの名前空間を汚さないようにします — 拡張ライブラリではこのパターンが推奨です。

JVM バックエンド(スタンドアロン JAR)

# hello_jvm.rb
puts "Hello from Konpeito!"
konpeito build --target jvm --run hello_jvm.rb

初回ビルド時は “Building ASM tool” というメッセージが出ます。これは一度きりのセットアップです。

出力例:

     Compiling hello_jvm.rb (jvm)
Building ASM tool (first-time setup)...
ASM tool ready.
Running: java -jar hello_jvm.jar
Hello from Konpeito!
      Finished in 0.9s -> hello_jvm.jar (36 KB)

生成された JAR はスタンドアロン — 実行マシンに Ruby は不要です。


3. Konpeito の仕組み

Konpeito がコードをコンパイルするとき、各操作は2つのカテゴリに分類されます:

  • ネイティブ — コンパイラが型を解決し、ネイティブ CPU 命令(例: LLVM: add i64, fadd double, getelementptr)または型付き JVM バイトコード(例: iadd, dadd)を出力。Ruby のメソッド探索オーバーヘッドなし。
  • 動的フォールバック — 型が特定できない場合、rb_funcallv(LLVM)または invokedynamic(JVM)にフォールバック。通常の Ruby と同じ速度で動作。コンパイラが警告を出すので、どこが境界かわかります。

RBS 型注釈を追加すると、動的フォールバックをネイティブディスパッチに昇格できます。速度が不要な箇所はそのままにしても問題ありません。

Gem とランタイム依存

require "some_gem" を書いた場合:

  • ロードパス上にある場合(-I で指定) — gem のソースも一緒にコンパイルされ、直接ディスパッチ・単相化・インライン化が適用されます。
  • ロードパス上にない場合rb_require("some_gem") が発行され、CRuby が実行時にロード。動的ディスパッチ経由ですが正しく動作します。

4. CRuby バックエンド: 実用例

パターン1: 拡張ライブラリ

計算集約的な関数だけコンパイルし、通常の Ruby アプリから require して使うパターンです。

ステップ1: コードを書く

# physics.rb
module Physics
  def self.distance(x1, y1, x2, y2)
    dx = x2 - x1
    dy = y2 - y1
    dx * dx + dy * dy
  end

  def self.sum_distances(xs, ys, n)
    total = 0.0
    i = 0
    while i < n - 1
      total = total + distance(xs[i], ys[i], xs[i + 1], ys[i + 1])
      i = i + 1
    end
    total
  end
end

ステップ2: RBS で型を明示する(任意)

RBS がなくても HM 推論で型は解決されますが、明示すればより強い最適化が効きます。

方法A: インライン RBS(手軽でおすすめ)

rbs-inline コメントで、Ruby ソース内に直接型注釈を書けます:

# physics.rb
# rbs_inline: enabled

module Physics
  #: (Float x1, Float y1, Float x2, Float y2) -> Float
  def self.distance(x1, y1, x2, y2)
    dx = x2 - x1
    dy = y2 - y1
    dx * dx + dy * dy
  end

  #: (Array[Float] xs, Array[Float] ys, Integer n) -> Float
  def self.sum_distances(xs, ys, n)
    total = 0.0
    i = 0
    while i < n - 1
      total = total + distance(xs[i], ys[i], xs[i + 1], ys[i + 1])
      i = i + 1
    end
    total
  end
end

方法B: 別ファイルの RBS

# physics.rbs
module Physics
  def self.distance: (Float x1, Float y1, Float x2, Float y2) -> Float
  def self.sum_distances: (Array[Float] xs, Array[Float] ys, Integer n) -> Float
end

ステップ3: コンパイル

# インライン RBS の場合(方法A)
konpeito build --inline physics.rb

# 別ファイル RBS の場合(方法B)
konpeito build physics.rb

-v をつけると、推論された型と動的フォールバック箇所が表示されます:

konpeito build -v physics.rb

ステップ4: Ruby から使う

# app.rb — 通常の Ruby(Konpeito ではコンパイルしない)
require_relative "physics"

xs = Array.new(10000) { rand }
ys = Array.new(10000) { rand }
puts Physics.sum_distances(xs, ys, 10000)
ruby app.rb

ネイティブになる部分: distance は完全にネイティブ — dx * dx + dy * dyfmul double + fadd double 命令に変換。sum_distanceswhile ループもネイティブカウンターループです。

動的フォールバックになる部分: xs[i] は Ruby Array への rb_funcallv 呼び出し(Array は CRuby オブジェクト)。ここもネイティブにしたい場合は NativeArray[Float] を使います:

NativeArray で完全ネイティブ化

NativeArray[Float] は unboxed の double 値を連続メモリに格納します。配列要素アクセスは getelementptr + load に直接変換され、メソッドディスパッチは一切発生しません。

ローカル NativeArray(関数スコープ)

NativeArray は Konpeito 固有の型なので、生成・使用するコードも Konpeito でコンパイルする必要があります。NativeArray の作成・アクセスは同じ関数スコープ内にまとめます:

# physics_native.rb
# rbs_inline: enabled

module Physics
  #: (Float, Float, Float, Float) -> Float
  def self.distance(x1, y1, x2, y2)
    dx = x2 - x1
    dy = y2 - y1
    dx * dx + dy * dy
  end

  def self.run
    n = 10000
    xs = NativeArray.new(n)
    ys = NativeArray.new(n)
    i = 0
    while i < n
      xs[i] = i * 0.0001
      ys[i] = i * 0.0002
      i = i + 1
    end

    total = 0.0
    i = 0
    while i < n - 1
      total = total + distance(xs[i], ys[i], xs[i + 1], ys[i + 1])
      i = i + 1
    end
    puts total
  end
end

Physics.run
konpeito run physics_native.rb

ヒント: konpeito run はコンパイル済みアーティファクトを .konpeito_cache/run/ にキャッシュします。ソースファイルやRBSファイルが変更されていなければ、再コンパイルはスキップされます。--no-cache で強制再コンパイル、--clean-run-cache でキャッシュクリアが可能です。

注意: 同じディレクトリに physics_native.rbphysics_native.bundle の両方が存在する場合、require "./physics_native".rb ソースファイルを先にロードします。konpeito run はロードパスを自動的に処理するため、この問題を回避できます。ビルドと実行を分けたい場合は、出力先を別ディレクトリにしてください:

konpeito build -o build/physics_native.bundle physics_native.rb
ruby -r ./build/physics_native -e ""

重要: ローカル NativeArray はスタック上に確保されるポインタであり、CRuby のメソッドディスパッチ経由で他の関数に引数として渡すことはできません。ローカル NativeArray は必ず同じ関数スコープ内で作成・使用してください。関数をまたいで共有したい場合は、モジュール NativeArray を使ってください。

これで xs[i]ys[i] もネイティブになり、ループ全体が Ruby のメソッドディスパッチを経由せずに実行されます。

モジュール NativeArray(グローバル、関数間共有)

ゲームの状態やシミュレーションデータなど、複数の関数からアクセスする配列は、RBS でモジュールのインスタンス変数として固定サイズの NativeArray を宣言できます。コンパイラが LLVM グローバル配列を直接生成するため、C ラッパーファイルは不要です。

インライン RBS(rbs_inline: enabled)を使えば、モジュール宣言と配列型を同じファイルに書けます:

# physics.rb
# rbs_inline: enabled

# @rbs module PhysicsData
# @rbs   @xs: NativeArray[Float, 10000]
# @rbs   @ys: NativeArray[Float, 10000]
# @rbs end

#: (Float, Float, Float, Float) -> Float
def distance(x1, y1, x2, y2)
  dx = x2 - x1
  dy = y2 - y1
  dx * dx + dy * dy
end

def init_data
  i = 0
  while i < 10000
    PhysicsData.xs[i] = i * 0.0001
    PhysicsData.ys[i] = i * 0.0002
    i = i + 1
  end
end

#: () -> Float
def compute_total
  total = 0.0
  i = 0
  while i < 9999
    total = total + distance(PhysicsData.xs[i], PhysicsData.ys[i],
                             PhysicsData.xs[i + 1], PhysicsData.ys[i + 1])
    i = i + 1
  end
  total
end

def run_physics
  init_data
  compute_total
end
konpeito run --inline physics.rb

または別ファイルの RBS で宣言:

# physics.rbs
module PhysicsData
  @xs: NativeArray[Float, 10000]
  @ys: NativeArray[Float, 10000]
end

構文は NativeArray[T, N] で、T は要素型(Integer または Float)、N は固定サイズです。アクセスは ModuleName.field_name[index]、代入は ModuleName.field_name[index] = value です。

注意: モジュール NativeArray は LLVM(CRuby)と mruby バックエンドで使用できます。JVM バックエンドは未対応です。実際のゲームでの使用例は examples/mruby_space_invaders/ を参照してください。

パターン2: アプリケーション全体のコンパイル

require チェーンを辿り、ロードパス上のすべてのファイルを単一の拡張に一括コンパイルします。

例: kumiki GUI アプリ

kumiki はクロスプラットフォームのデスクトップ UI フレームワークです。

gem install kumiki
# counter.rb
require "kumiki"
include Kumiki

class CounterComponent < Component
  def initialize
    super
    @count = state(0)
  end

  def view
    column(padding: 16.0, spacing: 8.0) {
      text "Count: #{@count}", font_size: 32.0, color: 0xFFC0CAF5, align: :center
      row(spacing: 8.0) {
        button(" - ") { @count -= 1 }
        button(" + ") { @count += 1 }
      }
    }
  end
end

frame = RanmaFrame.new("Kumiki Counter", 400, 300)
app = App.new(frame, CounterComponent.new)
app.run

Option A: 全体コンパイル(kumiki のソースも含む)

konpeito build -I /path/to/kumiki/lib counter.rb

-I で kumiki の lib/ を指定すると、require "kumiki" の先にあるすべてのファイル(59ファイル)が一括コンパイルされます。直接ディスパッチ・単相化・インライン化がコード全体に適用されます。

Option B: 自分のコードだけコンパイル

konpeito build counter.rb

-I なしでは counter.rb だけがコンパイルされ(約50 KB)、kumiki は実行時に CRuby がロードします。

実行:

konpeito run counter.rb

または、.rb / .bundle の名前衝突を避けるために別ディレクトリにビルドします:

konpeito build -o build/counter.bundle counter.rb
ruby -r ./build/counter -e ""
  • -r ./build/counter で拡張をロード。Init 関数がトップレベルコードを実行し、アプリが起動します。
  • -e "" で空スクリプトを渡します(Ruby が stdin を待たないように)。
  • counter.rb と同じディレクトリで ruby -r ./counter -e "" を使わないでください — Ruby は .bundle より .rb を先にロードするため、コンパイルされていないソースが実行されます。

5. JVM バックエンド: 実用例

スタンドアロンプログラム

# physics_jvm.rb
def distance(x1, y1, x2, y2)
  dx = x2 - x1
  dy = y2 - y1
  dx * dx + dy * dy
end

def sum_distances(n)
  total = 0.0
  i = 0
  while i < n
    total = total + distance(i * 1.0, 0.0, 0.0, i * 2.0)
    i = i + 1
  end
  total
end

puts sum_distances(1000)
konpeito build --target jvm --run physics_jvm.rb

JAR を生成して別途実行:

konpeito build --target jvm -o physics.jar physics_jvm.rb
java -jar physics.jar

GUI アプリ(Castella UI)

JVM バックエンドでは Castella UI(Skia ベースのリアクティブ GUI フレームワーク)が使えます。

git clone https://github.com/i2y/konpeito.git
cd konpeito/examples/castella_ui
bash setup.sh    # JWM + Skija JAR をダウンロード(約30 MB、初回のみ)
bash run.sh framework_counter.rb
# framework_counter.rb
class CounterApp < Component
  def initialize
    super
    @count = state(0)
  end

  def view
    label = "Count: " + @count.value.to_s
    Column(
      Text(label).font_size(32.0),
      Row(
        Button("  -  ").on_click { @count -= 1 },
        Button("  +  ").on_click { @count += 1 }
      ).spacing(8.0)
    )
  end
end

$theme = theme_tokyo_night
frame = JWMFrame.new("Counter", 400, 300)
app = App.new(frame, CounterApp.new)
app.run

Castella UI の詳細は Getting Started のウィジェットカタログとテーマ一覧を参照してください。


5.5. mruby バックエンド: スタンドアロン実行ファイル

mruby バックエンドはスタンドアロン実行ファイルを生成します — 実行マシンに Ruby や Java は不要です。アプリケーション配布、ゲーム開発、Ruby がインストールされていない環境へのデプロイに最適です。

スタンドアロン Hello World

# hello.rb
def main
  puts "Hello from Konpeito!"
end

main
konpeito build --target mruby -o hello hello.rb
./hello    # => Hello from Konpeito!

ビルドと実行を一度に:

konpeito run --target mruby hello.rb

raylib stdlib でゲーム開発

Konpeito は mruby バックエンド向けに raylib stdlib を内蔵しています。コード内で module Raylib を参照すると、コンパイラが RBS/C ラッパーを自動検出します — 手動セットアップは不要です。

# catch_game.rb
module Raylib
end

def main
  screen_w = 600
  screen_h = 400

  Raylib.init_window(screen_w, screen_h, "Catch Game")
  Raylib.set_target_fps(60)

  paddle_x = screen_w / 2 - 40
  paddle_y = screen_h - 40
  paddle_speed = 400

  obj_x = Raylib.get_random_value(30, screen_w - 30)
  obj_y = 0
  obj_speed = 150.0
  score = 0

  while Raylib.window_should_close == 0
    dt = Raylib.get_frame_time

    if Raylib.key_down?(Raylib.key_left) != 0
      paddle_x = paddle_x - (paddle_speed * dt).to_i
    end
    if Raylib.key_down?(Raylib.key_right) != 0
      paddle_x = paddle_x + (paddle_speed * dt).to_i
    end

    obj_y = obj_y + (obj_speed * dt).to_i
    if obj_y > screen_h
      obj_x = Raylib.get_random_value(30, screen_w - 30)
      obj_y = 0
    end

    Raylib.begin_drawing
    Raylib.clear_background(Raylib.color_black)
    Raylib.draw_rectangle(paddle_x, paddle_y, 80, 14, Raylib.color_skyblue)
    Raylib.draw_rectangle(obj_x, obj_y, 16, 16, Raylib.color_gold)
    Raylib.draw_text("Score: #{score}", 10, 10, 20, Raylib.color_white)
    Raylib.end_drawing
  end

  Raylib.close_window
end

main
konpeito run --target mruby catch_game.rb

Clay stdlib で UI レイアウト

Konpeito は mruby バックエンド向けに Clay UI stdlib を内蔵しています。Clay は Flexbox スタイルのレイアウトエンジンで、コンテナのツリーからレイアウトを計算し、raylib 経由で描画コマンドをレンダリングします。コード内で module Clay を参照すると自動検出されます。

# Clay レイアウト: open/close でコンテナを定義、layout/bg で設定、text でテキスト追加
Clay.begin_layout

Clay.open("root")
Clay.layout(1, 16, 16, 16, 16, 8, 1, 0.0, 1, 0.0, 2, 0)  # 縦方向、GROW、中央揃え
Clay.bg(40.0, 40.0, 60.0, 255.0, 0.0)

  Clay.open("card")
  Clay.layout(1, 12, 12, 12, 12, 4, 1, 0.0, 0, 0.0, 0, 0)  # 縦方向、幅GROW、高さFIT
  Clay.bg(255.0, 255.0, 255.0, 255.0, 8.0)                  # 白、角丸
  Clay.border(200.0, 200.0, 200.0, 255.0, 1, 1, 1, 1, 8.0)  # グレーのボーダー
    Clay.text("Hello!", font, 24, 40.0, 40.0, 40.0, 255.0, 0)
  Clay.close

Clay.close

Clay.end_layout
Clay.render_raylib  # raylib で全コマンドをレンダリング

主要概念:

  • Clay.open(id) / Clay.close — ネストされたコンテナの定義
  • Clay.layout(dir, pl, pr, pt, pb, gap, sw_type, sw_val, sh_type, sh_val, ax, ay) — Flexbox レイアウト
  • Clay.bg(r, g, b, a, corner_radius) — 背景色と角丸
  • Clay.border(r, g, b, a, top, right, bottom, left, corner_radius) — ボーダー
  • Clay.text(str, font_id, size, r, g, b, a, wrap) — テキスト要素
  • Clay.pointer_over(id) / Clay.pointer_over_i(id, index) — ヒットテスト

examples/mruby_clay_ui/ にサイドバーレイアウトのデモと Memory Match カードゲームがあります。

ゲームフレームワーク

Konpeito には 2D ゲーム構築用のフレームワーク(game_framework.rb)が含まれています:

  • タイルマップ描画、スプライトアニメーション、シーン管理、NPC システム、テキストボックス
  • Tween/イージング(linear, quad, cubic, bounce, elastic)、画面シェイク、シーン遷移
  • 簡易物理演算(AABB、重力、摩擦)、パーティクルシステム、オブジェクトプール
  • FSM(有限状態マシン)、タイマーシステム、パララックススクロール
  • グリッド/タイルユーティリティ、デバッグオーバーレイ(FPS、衝突矩形)、ゲームパッド抽象化、セーブ/ロード
  • Clay UI ヘルパー: fw_clay_rpg_window, fw_clay_bar, fw_clay_num, fw_clay_menu_item
  • module G + NativeArray グローバルによるゼロアロケーションのゲーム状態管理

examples/mruby_dq_rpg/ に JRPG デモ、examples/game_showcase/ に物理・パーティクル・Tween・FSM・パララックスを活用したプラットフォーマーデモがあります。

KUI — 宣言的 UI フレームワーク

KUI(Konpeito UI)は、Clay + Raylib(GUI)または ClayTUI + termbox2(TUI)を統一的な宣言 API でラップする Pure Ruby DSL です。同じコードで GUI/TUI 両方のビルドが可能です。

カウンターアプリ(GUI)

# counter_gui.rb
# rbs_inline: enabled

require "kui_gui"

# @rbs module AppState
# @rbs   @s: NativeArray[Integer, 4]
# @rbs end

#: () -> Integer
def draw
  vpanel pad: 24, gap: 16 do
    header pad: 12 do
      label "Counter App", size: 28, r: 255, g: 255, b: 255
    end

    spacer

    cpanel gap: 8 do
      label "Current Count:", size: 20
      hpanel gap: 4 do
        spacer
        label_num AppState.s[0], size: 36, r: 100, g: 200, b: 255
        spacer
      end
    end

    spacer

    hpanel gap: 12 do
      spacer
      button "  -  ", size: 20 do
        AppState.s[0] = AppState.s[0] - 1
      end
      button " Reset ", size: 20 do
        AppState.s[0] = 0
      end
      button "  +  ", size: 20 do
        AppState.s[0] = AppState.s[0] + 1
      end
      spacer
    end

    spacer
    divider

    footer do
      label "KUI Framework Demo", size: 14, r: 120, g: 120, b: 140
    end
  end
  return 0
end

#: () -> Integer
def main
  kui_init("KUI Counter", 450, 350)
  kui_theme_dark
  AppState.s[0] = 0

  while kui_running == 1
    kui_begin_frame
    draw
    kui_end_frame
  end

  kui_destroy
  return 0
end

main
konpeito build --target mruby -o counter_gui counter_gui.rb
./counter_gui

TUI 版への切り替え

require 行を変えるだけで同じアプリをターミナル向けにビルドできます:

# counter_tui.rb
require "kui_tui"
# ... draw/main は同じコード ...
# フレーム末尾に _kui_update_focus を追加してキーボードナビゲーションを有効化
konpeito build --target mruby -o counter_tui counter_tui.rb
./counter_tui

KUI ウィジェット一覧

ウィジェット 説明
vpanel(pad:, gap:) { } 縦方向コンテナ(幅/高さ GROW)
hpanel(pad:, gap:) { } 横方向コンテナ(幅 GROW、高さ FIT)
cpanel(pad:, gap:) { } 中央寄せコンテナ
fixed_panel(w, h, pad:) { } 固定サイズコンテナ
scroll_panel(pad:, gap:) { } スクロール対応の縦方向コンテナ
card(pad:, gap:) { } ボーダー付きサーフェスパネル
header(pad:) { } プライマリカラーのトップバー
footer(pad:) { } 控えめなボトムバー
sidebar(w, pad:, gap:) { } 固定幅の縦方向サイドバー
label(text, size:, r:, g:, b:) テキストラベル
label_num(value, size:, r:, g:, b:) 整数表示(文字列割り当てなし)
button(text, size:) { } クリック可能なボタン(ブロックがクリック時に実行)
menu_item(text, index, cursor, size:) 選択可能なメニュー項目
spacer 余白を埋める
divider(r:, g:, b:) 水平区切り線
progress_bar(value, max, w, h, r:, g:, b:) プログレスバー

ライフサイクルとテーマ

kui_init("タイトル", width, height)   # ウィンドウ/ターミナルを初期化
kui_theme_dark                        # ダークテーマ(インディゴ背景、明るいテキスト)
kui_theme_light                       # ライトテーマ(白背景、暗いテキスト)

while kui_running == 1
  kui_begin_frame
  # ... UI を描画 ...
  kui_end_frame
end

kui_destroy                           # 後片付け

入力

key = kui_key_pressed
# 戻り値: KUI_KEY_UP, KUI_KEY_DOWN, KUI_KEY_LEFT, KUI_KEY_RIGHT,
#         KUI_KEY_ENTER, KUI_KEY_ESC, KUI_KEY_SPACE, KUI_KEY_TAB,
#         KUI_KEY_BACKSPACE, または KUI_KEY_NONE

状態管理

KUI アプリはモジュール NativeArray で GC フリーな状態管理を行います:

# @rbs module AppState
# @rbs   @s: NativeArray[Integer, 4]
# @rbs end

AppState.s[0] = 42         # 書き込み
x = AppState.s[0]          # 読み出し

examples/kui_counter/ にカウンターデモ、examples/kui_dashboard/ にサイドバーナビゲーション付きマルチページダッシュボードがあります。

シェル実行 & ファイル I/O — KonpeitoShell

シェルコマンドの実行やファイルの読み書き:

# KonpeitoShell を参照すると自動検出されます
output = KonpeitoShell.exec("ls -la")
status = KonpeitoShell.exec_status   # 0 = 成功

home = KonpeitoShell.getenv("HOME")
KonpeitoShell.setenv("MY_VAR", "value")

content = KonpeitoShell.read_file("data.txt")
KonpeitoShell.write_file("out.txt", "hello")
KonpeitoShell.append_file("log.txt", "new line\n")

if KonpeitoShell.file_exists("config.json") == 1
  # ...
end

JSON — KonpeitoJSON

yyjson を使った JSON パース・生成:

obj = KonpeitoJSON.parse('{"name": "Alice", "age": 30}')
json = KonpeitoJSON.generate(obj)

HTTP — KonpeitoHTTP

libcurl を使った HTTP クライアント:

body = KonpeitoHTTP.get("https://example.com")

暗号 — KonpeitoCrypto

OpenSSL を使ったハッシュ・暗号化:

hash = KonpeitoCrypto.sha256("hello")

圧縮 — KonpeitoCompression

zlib を使ったデータ圧縮:

compressed = KonpeitoCompression.gzip("Hello, World!")
decompressed = KonpeitoCompression.gunzip(compressed)

上記の stdlib モジュールはすべて自動検出されます。ソースコードでモジュール名を参照するだけで、コンパイラが適切な RBS と C ラッパーを自動注入します。

クロスコンパイル

zig cc を使って他のプラットフォーム向けにクロスコンパイルできます:

konpeito build --target mruby \
  --cross aarch64-linux-musl \
  --cross-mruby ~/mruby-aarch64 \
  -o game game.rb
オプション 説明
--cross TARGET ターゲットトリプル(例: x86_64-linux-gnu
--cross-mruby DIR クロスコンパイル済み mruby のインストールパス
--cross-libs DIR 追加ライブラリ検索パス

mruby vs CRuby バックエンド比較

観点 CRuby バックエンド mruby バックエンド
出力 .so/.bundle(拡張ライブラリ) スタンドアロン実行ファイル
実行時依存 CRuby 4.0+ なし
用途 ライブラリ/アプリの高速化 配布、ゲーム
raylib stdlib 非対応 自動検出
Clay UI stdlib 非対応 自動検出
KUI(宣言的 UI) 非対応 自動検出(GUI/TUI)
Thread/Mutex 対応 非対応
キーワード引数 対応 対応
コンパイルキャッシュ .konpeito_cache/run/ .konpeito_cache/run/

6. 型システム

HM 型推論(注釈不要)

Konpeito は Hindley-Milner 型推論でほとんどの型を自動解決します:

def double(x)
  x * 2          # 2 が Integer → x は Integer → 戻り値も Integer
end

def greet(name)
  "Hello, " + name   # String + String → String
end

推論された型はそのまま unboxed 最適化に使われます。RBS は不要です。

RBS でより正確に

RBS を追加すると、コンパイラにより正確な情報を伝えられます:

別ファイル方式:

# sig/math.rbs
module TopLevel
  def add: (Integer a, Integer b) -> Integer
end
konpeito build --rbs sig/math.rbs math.rb

インライン方式(rbs-inline):

# rbs_inline: enabled

#: (Integer, Integer) -> Integer
def add(a, b)
  a + b
end
konpeito build --inline math.rb

ネイティブデータ構造

型付き高速データ構造が使えます(CRuby・mruby バックエンド):

用途 特徴
NativeArray[T] 数値配列 unboxed、連続メモリ、5-15x 高速
NativeClass 構造体 unboxed フィールド、10-20x 高速
StaticArray[T, N] 固定長配列 スタック割り当て、GC なし
NativeHash[K, V] ハッシュマップ 線形探査、4x 高速
Slice[T] メモリビュー ゼロコピー、バウンドチェック付き
# NativeArray の例
def sum_array(n)
  arr = NativeArray.new(n)
  i = 0
  while i < n
    arr[i] = i * 1.5   # unboxed store
    i = i + 1
  end

  total = 0.0
  i = 0
  while i < n
    total = total + arr[i]   # unboxed load
    i = i + 1
  end
  total
end

これらの型を使うには RBS 定義が必要です。詳細は API Reference を参照してください。


7. プロジェクト構成

konpeito init でプロジェクトを初期化できます:

konpeito init --target jvm my_app
cd my_app
my_app/
  konpeito.toml       # ビルド設定
  src/
    main.rb           # エントリポイント
  test/
    main_test.rb      # テストスタブ
  lib/                # JVM 依存(JAR)
  .gitignore
konpeito run src/main.rb    # コンパイル & 実行
konpeito test               # テスト実行

8. 便利なコマンド

konpeito build -v source.rb          # 推論結果と動的フォールバック箇所を表示
konpeito build -g source.rb          # DWARF デバッグ情報付きでビルド(lldb/gdb 対応)
konpeito check source.rb             # 型チェックのみ(コード生成なし)
konpeito build --profile source.rb   # プロファイリング情報付きでビルド
konpeito run --no-cache source.rb    # キャッシュを無視して強制再コンパイル
konpeito run --clean-run-cache source.rb  # runキャッシュクリア後にビルド&実行
konpeito fmt                         # コードフォーマット(RuboCop)
konpeito deps source.rb              # 依存関係の解析・表示

# mruby バックエンド
konpeito build --target mruby -o app app.rb    # スタンドアロン実行ファイル
konpeito run --target mruby app.rb             # ビルド&実行(キャッシュあり)
konpeito doctor --target mruby                 # mruby 環境チェック

次のステップ