プラグイン開発ガイド

はじむでは、C言語(または共有ライブラリを生成できる任意の言語)でネイティブプラグインを開発できます。
統一拡張子 .hjp(Hajimu Plugin)により、Windows・macOS・Linux で共通のファイルが使えます。

概要

はじむのプラグインシステムは2種類の拡張方法を提供します。

🔌

C拡張プラグイン (.hjp)

C/C++/Rust/Go 等で高速なネイティブライブラリを開発。数学関数、暗号処理、画像処理など計算量が多い処理に最適。

📦

はじむパッケージ (.jp)

はじむ言語自体で書かれたライブラリ。ユーティリティ、データ処理、ビジネスロジックなど汎用的な用途に。

クイックスタート:最初のプラグイン

3ステップでプラグインを作成・使用できます。

ステップ 1:プラグインを書く

hello_plugin.c を作成します。

#include "hajimu_plugin.h"

// プラグイン関数: 挨拶を表示
static Value fn_hello(int argc, Value *argv) {
    (void)argc;
    if (argv[0].type == VALUE_STRING) {
        printf("こんにちは、%sさん!\n", argv[0].string.data);
    }
    return hajimu_null();
}

// 関数テーブル
static HajimuPluginFunc functions[] = {
    {"挨拶", fn_hello, 1, 1},
};

// 初期化関数(必須)
HAJIMU_PLUGIN_EXPORT HajimuPluginInfo *hajimu_plugin_init(void) {
    static HajimuPluginInfo info = {
        .name        = "hello_plugin",
        .version     = "1.0.0",
        .author      = "あなたの名前",
        .description = "挨拶プラグイン",
        .functions   = functions,
        .function_count = sizeof(functions) / sizeof(functions[0]),
    };
    return &info;
}

ステップ 2:コンパイル

# macOS / Linux
$ gcc -shared -fPIC -I/path/to/hajimu/include -o hello_plugin.hjp hello_plugin.c

# Windows (MinGW)
$ gcc -shared -I/path/to/hajimu/include -o hello_plugin.hjp hello_plugin.c

ステップ 3:はじむから使う

test.jp を作成して実行します。

取り込む "hello_plugin" として HP
HP["挨拶"]("太郎")
// → こんにちは、太郎さん!
$ nihongo test.jp
こんにちは、太郎さん!

プラグイン API

プラグインの開発には include/hajimu_plugin.h をインクルードします。

必須構造体

HajimuPluginFunc — 関数登録用

typedef struct {
    const char *name;       // はじむ側に公開する関数名(日本語OK)
    Value (*fn)(int, Value*); // 関数ポインタ
    int min_args;           // 最小引数数
    int max_args;           // 最大引数数(-1で可変長)
} HajimuPluginFunc;

HajimuPluginInfo — プラグイン情報

typedef struct {
    const char *name;           // プラグイン名
    const char *version;        // バージョン
    const char *author;         // 作者
    const char *description;    // 説明
    HajimuPluginFunc *functions;// 関数テーブル
    int function_count;         // 関数の数
} HajimuPluginInfo;

初期化関数(必須)

すべてのプラグインは hajimu_plugin_init 関数をエクスポートする必要があります。

HAJIMU_PLUGIN_EXPORT HajimuPluginInfo *hajimu_plugin_init(void) {
    static HajimuPluginInfo info = {
        .name        = "プラグイン名",
        .version     = "1.0.0",
        .author      = "作者",
        .description = "説明",
        .functions   = functions,      // HajimuPluginFunc 配列
        .function_count = 関数の数,
    };
    return &info;
}

関数シグネチャ

すべてのプラグイン関数は同じ型です:

Value 関数名(int argc, Value *argv)

// argc: 引数の数
// argv: 引数の配列(argv[0], argv[1], ...)
// 戻り値: Value 型

ヘルパー関数

値の作成・操作に便利なインライン関数が用意されています。

値の作成

関数説明
hajimu_null() NULL値を作成 return hajimu_null();
hajimu_number(n) 数値を作成 return hajimu_number(3.14);
hajimu_bool(b) 真偽値を作成 return hajimu_bool(true);
hajimu_string(s) 文字列を作成(コピー) return hajimu_string("結果");
hajimu_array() 空の配列を作成 Value arr = hajimu_array();

配列操作

// 配列を作成して要素を追加
Value arr = hajimu_array();
hajimu_array_push(&arr, hajimu_number(1));
hajimu_array_push(&arr, hajimu_number(2));
hajimu_array_push(&arr, hajimu_string("三"));
return arr;

引数の型チェック

static Value fn_example(int argc, Value *argv) {
    // 引数の数チェック
    if (!hajimu_check_argc(argc, 2)) return hajimu_null();
    
    // 引数の型チェック
    if (!hajimu_check_type(&argv[0], VALUE_NUMBER)) {
        fprintf(stderr, "エラー: 第1引数は数値が必要\n");
        return hajimu_null();
    }
    
    double x = argv[0].number;
    double y = argv[1].number;
    return hajimu_number(x + y);
}

Value の型一覧

型定数説明フィールド
VALUE_NULL-
VALUE_NUMBER数値.number (double)
VALUE_BOOL真偽値.boolean (bool)
VALUE_STRING文字列.string.data, .string.length
VALUE_ARRAY配列.array.elements, .array.length
VALUE_DICT辞書.dict.keys, .dict.values

コンパイル方法

すべてのプラットフォームで出力ファイル名を .hjp にします。

macOS

$ gcc -shared -fPIC -I/path/to/hajimu/include -o my_plugin.hjp my_plugin.c

Linux

$ gcc -shared -fPIC -I/path/to/hajimu/include -o my_plugin.hjp my_plugin.c -lm

Windows (MinGW)

$ gcc -shared -I/path/to/hajimu/include -o my_plugin.hjp my_plugin.c

Windows (MSVC)

> cl /LD /I C:\path\to\hajimu\include /Fe:my_plugin.hjp my_plugin.c

Makefile の例

PLUGIN = my_plugin.hjp
SRC    = my_plugin.c
INCLUDE = -I../../include

UNAME := $(shell uname -s)
ifeq ($(UNAME), Darwin)
    SHARED_FLAGS = -shared -dynamiclib
else
    SHARED_FLAGS = -shared
endif

$(PLUGIN): $(SRC)
	gcc $(SHARED_FLAGS) -fPIC $(INCLUDE) -o $@ $< -lm

clean:
	rm -f $(PLUGIN)

はじむから使う

名前空間付きインポート(推奨)

取り込む "math_plugin" として 数学P

// 関数の呼び出し
表示(数学P["二乗"](5))       // → 25
表示(数学P["階乗"](6))       // → 720
表示(数学P["平方根"](144))   // → 12

直接インポート

取り込む "math_plugin"

// 関数が直接使える
表示(二乗(5))     // → 25
表示(階乗(6))     // → 720

メタ情報へのアクセス

取り込む "my_plugin" として P

表示(P["__名前__"])         // → "my_plugin"
表示(P["__バージョン__"])   // → "1.0.0"
表示(P["__作者__"])         // → "作者名"
表示(P["__説明__"])         // → "プラグインの説明"

プラグイン検索パス

拡張子なしで 取り込む "名前" とすると、以下の順序で .hjp ファイルを自動検索します。

優先度検索場所
1 呼び出し元ファイルからの相対パス ./plugins/my_plugin.hjp
2 カレントディレクトリ ./my_plugin.hjp
3 ローカルパッケージ ./hajimu_packages/my_plugin.hjp
4 グローバルプラグインディレクトリ ~/.hajimu/plugins/my_plugin.hjp

グローバルインストール

頻繁に使うプラグインは ~/.hajimu/plugins/ にコピーすると、どのプロジェクトからでも使えます。

# グローバルインストール
$ mkdir -p ~/.hajimu/plugins
$ cp my_plugin.hjp ~/.hajimu/plugins/

# どのディレクトリからでも使用可能
$ nihongo -c '取り込む "my_plugin" として P; 表示(P["__名前__"])'

対応言語

共有ライブラリを生成できる言語であれば、C以外でもプラグインを開発できます。
要件hajimu_plugin_init シンボルをCリンケージ(extern "C")でエクスポートし、HajimuPluginInfo * を返すこと。

言語コンパイル例備考
C gcc -shared -fPIC -o plugin.hjp plugin.c 標準的な方法
C++ g++ -shared -fPIC -o plugin.hjp plugin.cpp extern "C" でラップ
Rust cargo build --release cdylib crate-type、出力を .hjp にリネーム
Go go build -buildmode=c-shared -o plugin.hjp //export コメント付き
Zig zig build-lib -dynamic 出力を .hjp にリネーム

C++ での例

#include "hajimu_plugin.h"
#include <cmath>

static Value fn_sin(int argc, Value *argv) {
    (void)argc;
    return hajimu_number(std::sin(argv[0].number));
}

static HajimuPluginFunc functions[] = {
    {"サイン", fn_sin, 1, 1},
};

extern "C" {
    HAJIMU_PLUGIN_EXPORT HajimuPluginInfo *hajimu_plugin_init(void) {
        static HajimuPluginInfo info = {
            .name        = "trig_plugin",
            .version     = "1.0.0",
            .author      = "作者",
            .description = "三角関数プラグイン",
            .functions   = functions,
            .function_count = 1,
        };
        return &info;
    }
}

はじむパッケージ(.jp)の作成

はじむ言語自体で書かれたライブラリも作成・公開できます。

ステップ 1:プロジェクト初期化

$ mkdir my_package && cd my_package
$ hajimu パッケージ 初期化
✓ hajimu.json を作成しました

ステップ 2:hajimu.json を編集

{
  "名前": "my_package",
  "バージョン": "1.0.0",
  "説明": "便利なユーティリティパッケージ",
  "作者": "あなたの名前",
  "メイン": "main.jp",
  "依存": {}
}

ステップ 3:メインファイルを書く

main.jp(hajimu.json の「メイン」で指定したファイル)を作成します。

// main.jp - パッケージのエントリポイント

// 数学ユーティリティ
関数 円の面積(半径):
    戻す 3.14159 * 半径 * 半径
終わり

関数 円の周長(半径):
    戻す 2 * 3.14159 * 半径
終わり

// 文字列ユーティリティ
関数 挨拶文(名前):
    戻す "こんにちは、" + 名前 + "さん!"
終わり

関数 繰返し文字(文字, 回数):
    変数 結果 = ""
    繰り返す i から 0 まで 回数:
        結果 = 結果 + 文字
    終わり
    戻す 結果
終わり

ステップ 4:使用する側から利用

// 別のプロジェクトでパッケージをインストール
$ hajimu パッケージ 追加 ユーザー名/my_package
// はじむコードから使用
取り込む "my_package" として ユーティリティ

表示(ユーティリティ.円の面積(5))    // → 78.53975
表示(ユーティリティ.挨拶文("太郎")) // → こんにちは、太郎さん!

パッケージ構造の例

my_package/
├── hajimu.json          # マニフェスト
├── main.jp              # エントリポイント
├── lib/
│   ├── math.jp          # サブモジュール
│   └── string.jp        # サブモジュール
├── examples/
│   └── usage.jp         # 使用例
└── README.md            # ドキュメント

サブモジュールを使うパッケージ

// main.jp
取り込む "lib/math" として 数学
取り込む "lib/string" として 文字列

// 他のファイルから公開したい関数を再エクスポート
関数 円の面積(r):
    戻す 数学.円の面積(r)
終わり

パッケージの公開

作成したパッケージは GitHub で公開できます。

公開手順

# 1. GitHub リポジトリを作成
$ git init
$ git add -A
$ git commit -m "v1.0.0: 初回リリース"
$ git remote add origin https://github.com/ユーザー名/my_package.git
$ git push -u origin main

# 2. 他のユーザーがインストール
$ hajimu パッケージ 追加 ユーザー名/my_package

依存パッケージの管理

パッケージが他のパッケージに依存する場合、hajimu.json の「依存」に記述します。

{
  "名前": "my_advanced_package",
  "バージョン": "1.0.0",
  "説明": "高機能パッケージ",
  "作者": "作者名",
  "メイン": "main.jp",
  "依存": {
    "utils": "ユーザー名/utils_package",
    "math_extra": "ユーザー名/math_extra"
  }
}

依存パッケージは hajimu パッケージ インストール で自動的にインストールされます。

パッケージ管理コマンド

コマンド説明
hajimu パッケージ 初期化 プロジェクトを初期化(hajimu.json 作成)
hajimu パッケージ 追加 <URL> パッケージをインストール
hajimu パッケージ 削除 <名前> パッケージを削除
hajimu パッケージ 一覧 インストール済み一覧表示
hajimu パッケージ インストール hajimu.json の全依存をインストール

インストール先

種類パス用途
ローカル ./hajimu_packages/ プロジェクト固有のパッケージ
グローバル ~/.hajimu/packages/ 全プロジェクト共通のパッケージ

Tips & ベストプラクティス

🎯 関数名は日本語で

はじむのユーザーが直感的に使えるよう、関数名には日本語を使いましょう。"square" ではなく "二乗" のように。

🛡️ 引数チェックを忘れずに

hajimu_check_argc()hajimu_check_type() で引数を検証しましょう。不正な引数でクラッシュするプラグインは避けてください。

📝 メタ情報を充実させる

name, version, author, description をしっかり設定しましょう。ユーザーが P["__名前__"] でプラグイン情報を確認できます。

📦 .hjp はどこでも同じ

.hjp ファイルは OS ごとにビルドする必要がありますが、はじむコード側は一切変更不要です。同じ 取り込む 文で動きます。

完全なサンプルプラグイン

リポジトリの examples/plugins/ に数学関数プラグイン(8関数)のサンプルが同梱されています。

// サンプルで提供される関数
二乗(5)       → 25
立方(3)       → 27
階乗(6)       → 720
フィボナッチ(10) → 55
GCD(12, 8)    → 4
平方根(144)   → 12
累乗(2, 10)   → 1024
絶対値(-42)   → 42

サンプルプラグインを見る →

次のステップ