Haikuports 野良レシピ

Haikuports 自作のレシピです。Haiku で利用できます。オフィシャルレポジトリに投げる予定はありません。

HaikuPorts の使い方を参考にビルドしてください。

Haikuports からリリースされている mozc パッケージに Mozc UT 辞書が組み込まれました。HaikuDepot から mozc をインストールするとすでに UT 辞書が含まれています。以下のパッケージは不要です。

mozcdic-ut-20210725 でビルドしたパッケージ

既存の mozc と共存できません。 インプットメソッドのパッケージをインストールするときは、インストール済みの mozc を削除してから一度システムを再起動してください。でないとインプットメソッドがクラッシュします。

Mozc UT2 と Mozc NEologd UT は廃止されて Mozc UT に統合されたようです。

Haiku OS のインプットメソッド

インプットメソッド関連の環境は OS ごとに異なるため、一つでも対応するのは大変な作業です。大抵、詳しいドキュメントが見つからずに苦労します。

ここでは Haiku OS のインプットメソッドを実装するにあたって必要ことをすべて説明します。Haiku OS rev52698 頃の仕様にしたがっています。

クラスと配置

インプットメソッドはインプットサーバーが呼び出せるように BInputServerMethod クラスを継承したクラスとします。

#include <add-ons/input_server/InputServerMethod.h>

class CustomuInputMethod : public BInputServerMethod
{
public:
    CustomuInputMethod();
    virtual ~CustomuInputMethod();

    // BInputServerFilter
    // キーの押し下げインベントを受け取る
    virtual filter_result Filter(BMessage *msg, BList *_list);

    // 初期化
    virtual status_t InitCheck();

    // BInputServerMethod
    // メソッドが選択・非選択されると呼ばれる
    virtual status_t      MethodActivated(bool active);
};

extern "C" _EXPORT
BInputServerMethod *instantiate_input_method()
{
    return new CustomInputMethod();
}

インプットメソッドのインスタンスを取得するためのエントリーポイントが instantiate_input_method 関数です。

このコードをダイナミックリンクライブラリにコンパイルします。以下のライブラリにリンクしなければいけません。

-lbe -lroot /boot/system/servers/input_server

インプットメソッドを実装したライブラリを以下のどこかに配置すると、インプットサーバーが自動的に認識して、インプットメソッドが使用できるようになります。

# システム
/boot/system/add-ons/input_server/methods
# ユーザー
/boot/home/config/non-packaged/add-ons/input_server/methods

インプットメソッドのテスト時にはユーザー用の配置場所が便利です。パッケージとしてインストールするときはシステム用の配置場所に入れるようにしてください。

初期化

コンストラクタで親クラス BInputServerMethod にインプットメソッド名とアイコンのデータを渡します。これらは、デスクバーアイコンとして使用されます。

CustomuInputMethod::CustomuInputMethod()
    : BInputServerMethod("IM_NAME", kICON_DATA)
{
}

アイコンは一度設定すると、後で変更するために SetIcon メソッドを呼び出しても表示が変わりません (再描写されないバグ?)。

アイコンデータは 16x16 ピクセルの B_CMAP8 形式です。画像ファイルからアイコンデータを生成する方法は後述します。

インプットメソッドのクラスが最初に利用される前に InitCheck メソッドが呼ばれます。ここでインスタンス変数などを初期化できます。別スレッドの Looper などをインスタンス化するのが一般的です。

void CustomuInputMethod::InitCheck()
{
    // ...
}

キーの押し下げイベント

ユーザーがキーボードのキーを押し下げると、インプットサーバーからインプットメソッドへイベントが送られてきます。

filter_result CustomInputMethod::Filter(BMessage *msg, BList *_list)
{
    if (msg->what == B_KEY_DOWN) {
        fLooper.SendMessage(msg);
        return B_SKIP_MESSAGE;
    }
    return B_DISPATCH_MESSAGE;
}

BInputServerMethod の基底クラス BInputServerFilter のメソッドを実装してイベントを受け取ります。B_KEY_DOWN イベントを消費する場合、B_SKIP_MESSAGE を返します。 ここで消費しないイベントは B_DISPATCH_MESSAGE を返すことで、インプットサーバーが次のフィルタへ渡すように指示します。

このコードではイベントのメッセージをそのまま別の Looper (別スレッド) へ丸投げしています。キー入力から変換と表示までの処理に時間がかかるともたつくので、別スレッドで処理させます。

キー押し下げ B_KEY_DOWN メッセージは以下のデータを含みます。

int32 key = msg->GetInt32("key", 0); // raw keycode
uint8 byte = (uint8)msg->GetInt8("byte", 0); // ascii code
uint32 modifiers = (uint32)msg->GetInt32("modifiers", 0); // 修飾キー

キーコードは Preference -> Keymap で選択しているマッピングファイルを参照してください。コンパイル前のファイルがhaiku/src/data/keymapsにあります。

特殊キーや修飾キーは /boot/system/develop/headers/os/interface/InterfaceDefs.h に定義されています。

メソッドの選択・非選択

インプットサーバーがメソッドの切り替えを検出し、該当するメソッドの場合にイベントが送られてきます。

status_t CustomuInputMethod::MethodActivated(bool active)
{
    BMessage msg(active ? IM_METHOD_ACTIVATED : IM_METHOD_DEACTIVATED);
    fLooper.SendMessage(msg);
    return BInputServerMethod::MethodActivated(active);
}

インプットメソッドのエンジンの状態の切り替えなどに利用できます。また、不意にメソッドが非選択状態になった場合を検出できます。候補ウィンドウの非表示にするなどの処理を行いましょう。

ウィンドウサイズ

ウィンドウのサイズを取得するメソッド GetScreenRegion が基底クラスの BInputServerFilter に用意されています。

BRegion region;
if (GetScreenRegion(&region) == B_OK) {
    BRect rect = region.Frame();
}

候補ウィンドウの配置調整に利用できます。

変換イベントの種類

変換の開始と終了を送信するためのイベントがあります。

開始イベントは以下のものです。

要素 説明
be:reply_to BMessenger 返信受取相手

返信を受け取るのは大抵、メソッドや内部の実装で、BHandler や BLooper を BMessenger でラップして指定します。

BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
msg->AddInt32("be:opcode", B_INPUT_METHOD_STARTED);
msg->AddMessenger("be:reply_to", BMessenger(NULL, this));
EnqueueMessage(msg);

変換の終了送信には他のオプションはありません。

BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
msg->AddInt32("be:opcode", B_INPUT_METHOD_STOPPED);
EnqueueMessage(msg);

B_INPUT_METHOD_STOPPED が外部からメソッドへ送られてくることがあります。これは、以下のような場合に送られます。 このとき、メソッドは適当に変換を終了させてください。

  • デスクバーなどで入力メソッドが変更されたとき
  • 変換中のウィンドウがフォーカスを失った時
  • その他

変換中テキストの送信

変換中で確定前のプレエディットとして表示する文字列を送信します。

要素 説明
be:clause_start int32 効果を付ける範囲開始位置
be:clause_end int32 効果を付ける範囲終了位置
be:selection int32 選択効果を付ける位置、二つでそれぞれ開始位置と終了位置を指定
be:string const char* 文字列

be:clause_xxxx の指定で背景色などが設定されます。テキスト全体を含めてしまってかまいません。 be:selection は一つ目で開始位置を、二つ目で終了位置を指定します。

be:confirmed が含まれていても構いませんが、false を指定してください。be:confirmed が true のときは、入力確定とみなされます。

BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
msg->AddInt32("be:opcode", B_INPUT_METHOD_CHANGED);
msg->AddInt32("be:clause_start", 0);
msg->AddInt32("be:clause_end", str.length()-1);
msg->AddInt32("be:selection", 0);
msg->AddInt32("be:selection", str.length()-1);
msg->AddString("be:string", str.c_str());
EnqueueMessage(msg);

入力テキストの送信

入力テキストが確定されたときに、文字列の挿入を要求します。

要素 説明
be:confirmed bool 確定状態
be:string const char* 文字列
BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
msg->AddInt32("be:opcode", B_INPUT_METHOD_CHANGED);
msg->AddBool("be:confirmed", true);
msg->AddString("be:string", str.c_str());
EnqueueMessage(msg);

入力位置の取得

テキスト入力中のカーソル位置を取得するには、B_INPUT_METHOD_EVENT のうち B_INPUT_METHOD_LOCATION_REQUEST を送ります。

要素 説明
be:location_reply BPoint キャレット位置
be:height_reply float キャレット高さ
BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
msg->AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
EnqueueMessage(msg);

返答は以下のように be:location_reply および be:height_reply です。

case B_INPUT_METHOD_EVENT:
{
    uint32 opcode = msg->GetInt32("be:opcode", 0);
    if (opcode == B_INPUT_METHOD_LOCATION_REQUEST) {
        // move window position to the start of selected char
        // be:height_reply: float, be:location_reply: BPoint
        BPoint point;
        float height;
        if (msg->FindPoint("be:location_reply", fCursorIndex, &point) == B_OK &&
            msg->FindFloat("be:height_reply", fCursorIndex, &height) == B_OK) {
            point.y += height + 1.;
            fLastLocation = point;
        }
        float x = fLastLocation.x - fCandidateView->GetValueLeft();
        MoveTo(x >= 0 ? x : 0,
               fLastLocation.y);
    }
    break;
}

現在の実装ではプレエディットに文字が含まれていない場合、返答の要素数はゼロのため、位置が取得できません。

Looper

BInputServerMethod クラスを継承してメソッドクラスを作成した場合、変換などを担当する Looper (別スレッド) を利用します。

このとき、Looper の初期化を忘れないようにしましょう。

#include <Application.h>

// in constructor
if (be_app) {
    if (be_app->Lock()) {
        be_app->AddHandler(this);
        be_app->Unlock();
    }
}

Run();

メソッドから Looper へイベントが送信されてこない場合、Looper の初期化を忘れています。

トレイ

インプットメソッドが一つでも追加されるとトレイに板状のアイコンが表示されます。ここからマウスでインプットメソッドの切り替えやメニューが利用できます。

このメニューに表示されるメソッド名やアイコン、サブメニューを設定できます。 名前とアイコンはインスタンス化時に設定できます。

status_t  SetName(const char* name);
status_t  SetIcon(const uchar* icon);
status_t  SetMenu(const BMenu* menu,
            const BMessenger target);
// target はメニューの項目が選択されたときにイベントを受け取る相手

後からアイコンを変更しようとすると動作しません (hrev52698)。バグかどうか不明です。

メニューはシリアライズされて渡されるため、チェックマークの状態などを更新するには、メニューをまるごと設定しなおしてください。

メニューは一度開くと、二度目にクリックしても反応しません。バグ(#14860)のようです。

候補ウィンドウ

変換候補を表示する候補ウィンドウは以下のような属性を指定して作成します。

CandidateWindow::CandidateWindow()
    : BWindow(
        BRect(100, 100, 200, 250),
        "CandidateWindow",
        B_NO_BORDER_WINDOW_LOOK,
        B_FLOATING_ALL_WINDOW_FEEL,
        B_NOT_RESIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE |
        B_NOT_MINIMIZABLE | B_NOT_MOVABLE |
        B_AVOID_FOCUS |
        B_NOT_ANCHORED_ON_ACTIVATE)
{

}
  • 枠線なし
  • サイズ変更なし、閉じる不可、ズーム不可、最小化不可、移動不可、フォーカスなし

アイコンデータ

2019/1 頃に新しい API が導入されてベクターアイコンがトレイアイコンとして利用できるようになりました。インプットメソッド関連は API の変更が必要なため、後回しのようですが、じきにベクターアイコンが利用できるようになるはずです。

トレイアイコンのデータは B_CMAP8 形式です。16 x 16 ピクセルPNG ファイルを用意しておき、以下のプログラムで変換できます。

// tocmap8.cc

#include <Application.h>
#include <Bitmap.h>
#include <BitmapStream.h>
#include <IconUtils.h>
#include <TranslationUtils.h>

#include <stdio.h>

// g++ -o tocmap8 tocmap8.cc -lroot -ltranslation -lbe

class App : public BApplication
{
public:
    App(const char* path);
};

App::App(const char* path)
    : BApplication("application/x-vnd.icon.conv")
{
    const char *var_name = "kIcon";
    BBitmap *b = BTranslationUtils::GetBitmapFile(path);
    if (b == NULL) {
        return;
    }
    //printf("len: %d, row_len: %d, type: 0x%04x\n", b->BitsLength(), b->BytesPerRow(), (int)b->ColorSpace());
    BBitmap *r = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
    if (BIconUtils::ConvertToCMAP8((const uint8 *)b->Bits(), 16, 16, 64, r) == B_OK) {
        uchar *d = (uchar *)r->Bits();
        //printf("len: %d, row_len: %d\n", r->BitsLength(), r->BytesPerRow());
        int len = r->BitsLength();
        printf("const uchar %s[] = {\n", var_name);
        int i = 0;
        while (i < len) {
            for (int j = 0; j < 16; ++j) {
                printf("0x%02x,", d[i++]);
            }
            printf("\n");
        }
        printf("};\n");
    }
    
    delete r;
    delete b;
}

int main(int argc, char *argv[])
{
    if (argc == 2) {
        App *app = new App(argv[1]);
        delete app;
    } else {
        printf("tocmap8 path_to_16x16.png\n");
    }
    return 0;
}

以下のようにコンパイルしてください。

g++ -o tocmap8 tocmap8.cc -lroot -ltranslation -lbe

ターミナルから次のように変換するファイルを指定して実行します。

tocmap8 hoge.png

標準出力に変換結果が表示されるので、コピーして利用してください。

ディレクトリパス取得

インプットメソッドの設定ファイルは /boot/home/config/settings/method_name 以下に入れるのが一般的です。このパスを取得する API が提供されています。

#include <FindDirectory.h>
#include <Path.h>
#include <stdio.h>

BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
    path.Append("method_name");
    printf("%s\n", path.Path());
}

インストール済みのインプットメソッドのデータファイルは /boot/system/data/method_name など、パッケージ化されていないものは /boot/home/config/non-packaged/data/method_name 辺りに配置しますが、これらのパスも B_USER_NONPACKAGED_DATA_DIRECTORY や B_SYSTEM_DATA_DIRECTORY を指定すると取得できます。

Haiku OS アプリケーションのローカライズ

Haiku OS アプリケーションを C++ で実装したときにローカライズを提供する方法について説明します。

公式で提供する方法以外にも po ファイルを使った方法などがあります。ここでは、標準 API による方法について述べます。

シグネチャ

プログラムなどにシグネチャを割り当てます。他のプログラムと衝突しないように選んでください。

BApplication クラスのインスタンス化時に渡すものと同じです。以下に例を示します。

#include <Application.h>

#define APP_SIGNATURE "application/x-vnd.AquaSKK-Preference"

class SKKPreferenceApp : public BApplication
{
public:
    SKKPreferenceApp();
    virtual ~SKKPreferenceApp() {};
};

SKKPreferenceApp::SKKPreferenceApp()
    : BApplication(APP_SIGNATURE)
{
}

この例でのシグネチャは x-vnd.AquaSKK-Preference です。application/ の部分はシグネチャには含めません。

このシグネチャを使用してプログラムとローカライズリソースを結びつけます。

ファイルの種類

以下のような種類のファイルを取り扱います。

種類 説明
C++ ローカライズする文字列を含むソースコード
pre ソースコードをまとめたファイル
catkeys 候補とチェックサムを含むタブ区切りテキストファイル
catalog ローカライズ用変換済みバイナリ
rdef リソース定義テキストファイル
rsrc 変換済みバイナリリソースファイル

プログラム

以下のようなプログラムでローカライズ用リソースを作成します。

プログラム 説明
collectcatkeys pre ファイルから候補を抽出して catkeys ファイル出力
linkcatkeys catkeys ファイルから catalog ファイルを生成
rc rdef を rsrc ファイルへ変換
xres rsrc を実行フィルなどに結合

ソースコードでの候補マーキング

C++ ソースコード中でローカライズする文字列を指定します。

// 必要なヘッダのインクルード
#include <Catalog.h>

// コンテキストの定義
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "App-Preference"

printf(B_TRANSLATE("Hello"));

Catalog.h をインクルードしてコンテキストなどを定義しておきます。その後、B_TRANSLATE などのマクロでローカライズ候補を指定します。

B_TRANSLATE などのマクロは B_COLLECTING_CATKEYS が定義されていると定義内容が変更され、pre ファイルを生成するときのマーキングが有効になります。普通にコンパイルするときには B_COLLECTING_CATKEYS を定義してはいけません。

マーキングの種類

以下のようなマクロが定義されています。用途に応じて使い分けてください。

マクロ 説明
B_TRANSLATE(string) 翻訳させる。現在のコンテキスト
B_TRANSLATE_CONTEXT(string, context) 指定のコンテキストで翻訳
B_TRANSLATE_COMMENT コメント付き
B_TRANSLATE_ALL(string, context, comment) コンテキストとコメントの両方を指定
B_TRANSLATE_ID(id) リソース ID 参照?
B_TRANSLATE_SYSTEM_NAME(string) システムリソースから翻訳
B_TRANSLATE_MARK(string) 翻訳マーキングのみ
その他 Catalog.h参照

B_TRANSLATE_MARK は Catalog.h に説明のあるとおり、翻訳候補としてマークされますが、実行時には翻訳されません。B_TRANSLATE などに渡して自分で翻訳後の文字列を取得してください。静的文字列配列の要素を翻訳用の catkeys に含めたいときに利用します。

候補の抽出用ファイル生成

候補抽出用にまとめた pre ファイルを生成します。これはヘッダファイルの内容もまとめて一つのファイルにしたものです。

ファイルを一つにまとめるには以下のようにコンパイラプリプロセッサを利用します。

gcc -E -x c++ -DB_COLLECTING_CATKEYS -I./ app.cpp

-E オプションでプリプロセッサのみ実行します。-x c++C++ を指定しています。 -DB_COLLECTING_CATKEYS を指定して候補抽出ようマクロに切り替えます。

処理時にエラーが出た場合、大抵はインクルードパスが不足しています。

これで生成されたファイルに含まれる # から始まる行が悪さをすることがあるため、以下のようなスクリプトでそのような行を削除してしまうとよいでしょう。

# gen_pre.py
import sys
import argparse
import subprocess

def gen_pre(parser, includes, outpath, input_paths):
    inc = ["-I" + i for i in includes]
    data = []
    args = [parser, '-E', '-x', 'c++', 
            '-DB_COLLECTING_CATKEYS', '-DOS_LINUX', '-DOS_HAIKU']
    args.extend(inc)
    args.extend(input_paths)
    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if p.poll() is None:
        out = p.stdout.read()
        data.extend([line for line in out.split("\n") 
                        if not line.startswith("#")])
    else:
        print(p.stderr.read())
        return -1
    with open(outpath, "w") as f:
        f.write("\n".join(data))
    return 0

def main():
    parser = argparse.ArgumentParser(
                description='Generates pre file from B_TRANSLATE.')
    parser.add_argument('--parser',
                help='C compiler')
    parser.add_argument('--outpath', 
                help='pre file')
    parser.add_argument('--includes', nargs='+',
                help='Include dirs')
    parser.add_argument('--inputpath', nargs='+',
                help='C++ files to be extracted')
    args = parser.parse_args()
    return gen_pre(args.parser, args.includes, args.outpath, args.inputpath)

if __name__ == '__main__':
    sys.exit(main())

この Python スクリプトは以下のように実行します。

python gen_pre.py --parser gcc --outpath out.pre --includes ../ --inputpath foo.cpp

catkeys ファイル生成

pre ファイルから候補を抜き出した catkeys ファイルを生成します。

collectcatkeys -s SIGNATURE -o en.catkeys out.pre

catkeys ファイルには元の文字列から生成されたチェックサムが含まれているため、元の文字列を変更するとファイルが壊れてしまいます。ソースコードローカライズする文字列を変更したときは、pre ファイルを経由して catkeys ファイルを生成しなおしてください。

翻訳

en.catkeys ファイルを ja.catkeys としてコピーします。このファイルを翻訳します。

catkeys ファイルは以下のような構造をしています。

バージョン 言語 シグネチャ チェックサム
1   English x-vnd.AquaSKK-Preference    948131552
Select location...  Preference      Select location...
Enable  Preference      Enable
元文字列 コンテキスト コメント 翻訳後文字列

各項目はタブで区切られています。言語名は変更しなくても問題ありません。

タブ区切りテキストのため、テキストエディタで編集できます。日本語が表示できてタブが可視化できるエディタをおすすめします。

CatKeysEditor で翻訳できますが、保存されないバグなどがあるようです。

catalog ファイル生成

catkeys ファイルを翻訳した後、catalog ファイルへ変換します。

linkcatkeys -o ja.catalog -s SIGNATURE -l ja ja.catkeys

-l オプションで言語名を指定します。ファイル名は言語名.catalog としておきます。

catalog ファイル配置

catalog ファイルは指定の場所に配置してシステムが読み込めるようにします。

システムまたは非パッケージ用の配置場所があります。

# システム
/boot/system/data/locale/catalogs/SIGNATURE/ja.catalog
# 非パッケージ
/boot/home/config/non-packaged/data/locale/catalogs/SIGNATURE/ja.catalog

テストやパッケージ化セずに配布するアプリケーションでは非パッケージ用の場所に配置すると良いでしょう。

rdef ファイル定義

アプリケーションの実行ファイルにリソースに関する情報を追加しますが、その内容を定義するのが rdef ファイルです。

resource app_signature "application/x-vnd.App-Preference";
resource app_name_catalog_entry "x-vnd.App-Preference:System name:apppref";

ここで必要となるのはシグネチャです。アプリケーション、ローカライズ用 catkeys ファイルとシグネチャを合わせてください。

app.rdef などとして保存しておきます。

rdef ファイルではファイルアイコンなども指定できますが、ここでは説明を割愛します。

rdef ファイルを rsrc に変換

rdef ファイルをバイナリの rsrc ファイルに変換します。

rc -o app.rsrc app.rdef

rsrc を埋め込み

rsrc ファイルをアプリケーションの実行ファイルに埋め込みます。

xres -o app app.rsrc

ここでは、すでに存在する実行ファイル app に app.rsrc ファイルを埋め込んでいます。app ファイルが上書きされるので注意してください。リソースを埋め込んだ後のファイルを別ファイルにしたい場合、事前に実行ファイルをコピーしてください。


ロケールを合わせてアプリケーションを実行すると文字列がローカライズされた状態でプログラムが起動します。

pkgman の使い方

pkgman コマンドで Haiku OS のソフトなどを含むパッケージを管理できます。 GUI でパッケージ管理を行う HaikuDepot もあります。 HaikuPorts でソフトをビルドしてテストしていると、HaikuDepot を使って行うのが面倒になってきます。そこでコマンドラインでパッケージを管理できる pkgman を利用します。

パッケージのインストールやアンインストールは簡単です。

pkgman install package_name
pkgman uninstall package_name

などとします。複数のパッケージを同時にインストール、アンインストール指定できます。

package_name に HaikuPorts での名称やローカルにあるパッケージのファイル名を指定できます。

レポジトリでパッケージを検索するには search コマンドを使用します。

pkgman search mozc

以下にオプション一覧を示します。

> pkgman --help
Usage: pkgman <command> <command args>
Manages packages and package repositories.

Package management commands:
  full-sync
    Synchronizes the installed packages with the repositories.

  install <package> ...
    Installs one or more packages.

  search ( <search-string> | --all | -a )
    Searches for packages matching <search-string>.

  uninstall <package> ...
    Uninstalls one or more packages.

  update [ <package> ... ]
    Updates the specified or all packages.

Repository management commands:
  add-repo <repo-base-url>
    Adds the repository with the given <repo-base-URL>.

  drop-repo <repo-name>
    Drops the repository with the given <repo-name>.

  list-repos
    Lists all repositories.

  refresh [<repo-name> ...]
    Refreshes all or just the given repositories.

Other commands:
  resolve-dependencies <package> ... <repository> [ <priority> ] ...
    Resolves all packages the given packages depend on.

Common options:
  -h, --help   - Print usage info for a specific command.

install コマンド向けオプション

Options:
  --debug <level>
    Print debug output. <level> should be between 0 (no debug output,
    the default) and 10 (most debug output).
  -H, --home
    Install the packages in the user's home directory. Default is to
    install in the system directory.
  -y
    Non-interactive mode. Automatically confirm changes, but fail when
    encountering problems.

uninstall コマンド向けオプション

Options:
  --debug <level>
    Print debug output. <level> should be between 0 (no debug output,
    the default) and 10 (most debug output).
  -H, --home
    Uninstall the packages from the user's home directory. Default is to
    uninstall from the system directory.
  -y
    Non-interactive mode. Automatically confirm changes, but fail when
    encountering problems.

HaikuPorts のレシピを書くときの注意点

HaikuPorts のレシピを書いて haikuports に取り込んでもらいましょう。

レシピのガイドラインに従っていないレシピは容赦なく修正指示がくるので、最初からガイドラインに沿ってレシピを書きましょう。 レシピの各項目の説明も参照してください。レシピ中で利用できる環境変数は便利なので確認しておいてください。 レシピファイルの表記定義ファイルもあります。

以下はレシピのガイドラインにしたがって説明していますが、分かりにくい所は独自に説明を追加してあります。

環境変数

ビルド時によく使用される環境変数とインストール時によく使用される環境変数があります。また、インストール時によく使用される環境変数でも、インストール場所の指定に使われることがあります。

よく使われる一部を紹介します。

以下はインストール先の指定でよく使われるもの。

  • $appsDir: アプリケーションのリンク先
  • $binDir: コマンドを入れる場所
  • $dataDir: データファイル配置場所
  • $includeDir:
  • $fontsDir: フォントのインストール先。$fontsDir/otfonts や $fontsDir/ttfonts 以下に
  • $prefix: $binDir などすべてのディレクトリのトップ、secondary ビルドの時に $binDir と $prefix/bin では結果が異なるので注意

レシピの配置

haikuports でのレシピは Gentoo Linux のパッケージと同じ場所に配置しましょう。見つからなければそれらしいサブディレクトリに入れます。

レシピ名

レシピ名は以下のようにバージョン名などを含みます。

package_name-major.minor.bugfix.recipe

- (ダッシュ) はパッケージ名とバージョンの区切りに使用されるため、名前に使ってはいけません。_ (アンダースコア) を使用できます。 バージョンは . (ドット) で区切ってください。よくみられるメジャー、マイナー、バグフィックスの三つの番号以外も利用できます。

インデントと改行、行の長さ

インデント一段はタブ一つです。コマンド行などを複数行に分けるときに \ 記号で終端した次の行はインデントを一つ深くします。

改行は LF です。また、レシピの最後は空の行(LF 一つだけの行)で終わります。

行末のスペース記号は削除しておいてください。テキストエディタなどに機能があります。

一行は 70 文字以内にしてください。DESCRIPTION などの項目は長くなりがちですので、行末の \ で改行を無効にして次の行に進めましょう。

項目の順番

レシピ中の項目の順番はレシピのガイドラインの Orderingにしたがってください。

また、項目間の空行もガイドライン中の空行から変更してはいけません。空行位置が違うと修正させられます。

SUMMARY

SUMMARY は . で終わってはいけません。

DESCRIPTION

DESCRIPTION の一行は 70 文字以内とし、改行を \ で無効にして次の行に続けられます。ダブルクォートは \" としてエスケープしてください。

HOMEPAGE

HOMEPAGE に指定する URL はドメインのみの場合、最後に / を付けます。

ドメインより下位のディレクトリ名で終わっている場合、最後に / は不要です。

URL がプロジェクトの管理サイトなどの場合、プロジェクトトップをホームページとみなし、最後に / を付けます。

以上の説明を参考にしてガイドラインのHOMEPAGEの例を参照してください。

COPYRIGHT

年号と名前の間に , (コンマ) は不要です。

LICENSE

改行を入れて複数のライセンスを指定できます。ライセンス名は /boot/system/data/licenses ディレクトリにあるファイルの名前とします。

LICENSE="BSD (2-clause)"

LICENSE="BSD (3-clause)
    GNU GPL v2
"

REVISION

ソースのバージョンが同じで生成されるパッケージの内容が変化したときに番号を増やします。ちょっとしたレシピの変更でパッケージ内のファイルに変化がなければ番号はそのまま。

ソースのバージョンが変わったときに番号を 1 に戻します。

SOURCE_URI

ソースが一つしかないときは SOURCE_URI を使います。二つ以上のときは SOURCE_URI、SOURCE_URI_1 などと数字を追加します。対応する CHECKSUM_SHA256 などにも同じように数字を追加してください。

$portVersion などを活用してバージョンごとに変更せずに済むようにしましょう。

80 文字を超えても問題ありません。

CHECKSUM_SHA256

ソースファイルに対して sha256sum を実行して表示されるチェックサムだけを記載します。

sha256sum foo.tar.gz

SOURCE_FILENAME

ソースファイル名が分かりにくい場合に指定します。

SOURCE_DIR

ソースアーカイブを解凍したときにディレクトリ名が変化する場合に指定します。

レシピをビルドしてみたときにディレクトリが見つからないエラーが出た時、ダウンロードされたファイルを解凍して作成されるディレクトリ名をココに指定すると解決します。

PATCHES

パッチファイルを patches ディレクトリに入れておき、レシピファイル名と同じような名前を付けておきます。ファイルの拡張子は .patch または .patchset とします。

最近は patchset が好まれるようです。git format-patch などのコマンドで patchset ファイルを作成できます。コミットが複数に分かれている場合、git rebase などでコミットをまとめる必要があるかもしれません。git の説明を参照してください。

haikuporter でレシピをビルドするときに -G (--no-git-repo) を指定しない場合、ソースファイルを git レポジトリとして初期化します。 ビルド時に変更が必要であれば、git にコミットしてパッチファイルを作成できます。

詳細は git の説明を参照してください。

ADDITIONAL_FILES

ディレクトリ additional-files 以下に入れたファイル名を指定します。 $portDir/additional-files/file_name などとして利用できます。

ARCHITECTURES と SECONDARY_ARCHITECTURES

ARCHITECTURES は最低でも x86_gcc2 x86 x86_64 の三つを入れておきます。

ARCHITECTURES="!x86_gcc2 ?x86 x86_64"

ビルドできないものの前に ! をつけます。未確認のものの前に ? を付けましょう。

x86_gcc2 でビルドできない場合、!x86_gcc2 としておき、SECONDARY_ARCHITECTURES の x86 でビルドできるようにがんばりましょう。

if [ "$targetArchitecture" = x86_gcc2 ]; then
SECONDARY_ARCHITECTURES="x86"
fi

SECONDARY_ARCHITECTURES では GCC7 などの比較的新しいコンパイラが提供されているため、大抵のソースコードはビルドできます。 未確認の場合は ? を付けておくこともできます。

ARCHITECTURES の一つ前の行は空行です。ガイドラインにしたがってください。

PROVIDES

最初の行はパッケージ名です。

二行目以降はパッケージが提供する項目を指定します。lib、cmd、app、addon の一つを指定します。

パッケージ名以外はアルファベット順に記載してください。

BUILD_REQUIRES と BUILD_PREREQUIRES

BUILD_REQUIRES にビルド時にリンクされるライブラリなどを記載します。

BUILD_PREREQUIRES にビルド時に利用されるツールなどを記載します。大抵は cmd: で始まるコマンドラインツールです。

ビルドは隔離された環境で実行されるため、ここに記載されていないコマンドやライブラリは利用できないと考えてください。 レシピをテストビルドしたときにエラーが出た場合、これらの項目を見直してください。

依存ライブラリなどの正確な名前が分からない場合、そのパッケージを提供しているレシピを参照してください。PROVIDES で指定されている名前が使用できます。

lua に依存性のある場合、lua から始まっている名称は旧式のようです。liblua の方を使用してください。

PATCH

PATCHES とは違い、コマンドを実行して変更を適用します。この項目はオプションです。 sed などのコマンドでちょっとだけソースコードをいじるようなときに使用します。

BUILD

ビルドに必要なコマンドライン指定を羅列します。make などを呼ぶことが多いでしょう。

ディレクトリの作成は mkdir -p として -p オプションを指定すると、すでにディレクトリが存在したときにエラーになりません。

INSTALL

インストールに必要なコマンドライン指定を羅列します。

TEST

パッケージのテストに必要なコマンドライン指定を羅列します。


初めてレシピを書いたときに指摘されやすい項目のみについて説明しました。あとはレシピのガイドライン読んでみてください。

haikuports にあるレシピにはガイドラインに沿っていないものが結構あります。レシピの参考にするときはコミット日の新しいものを参照してください。

HaikuPorts のレシピを読む

HaikuPorts ではプログラムやフォントなどをパッケージ化するためのプロジェクトです。 Haiku OS 用にソフトを移植したり、フォントをまとめてインストールできるようにしたければ、レシピを書きましょう。

HaikuPorts ではソフトなどをレシピとして管理しており、レシピにはパッケージの情報やビルド情報が記載されています。

自分でレシピを書けるように既存のレシピを見ていきます。

aobook のレシピを題材にレシピの大まかな内容を説明します。aobook は青空文庫のデータのためのビューアーです。

最初の部分にパッケージの説明やビルドに使われるソースコードやファイルの取得方法を記載します。

SUMMARY="Aozora Bunko text viewer"
DESCRIPTION="Aobook is a viewer for Aozora Bunko which is a digital library \
of Japanese-language literature."
HOMEPAGE="https://osdn.net/projects/aobook/"
COPYRIGHT="2014-2018 Azel"
LICENSE="BSD (3-clause)"
REVISION="1"
SOURCE_URI="https://github.com/hanya/aobook-haiku/archive/v${portVersion/_/-}.tar.gz"
CHECKSUM_SHA256="f840a98b0f0c1f3fa31ae19498bc9051106e068b9af95eb4065643693f7f1e07"
SOURCE_FILENAME="aobook-haiku-${portVersion/_/-}.tar.gz"
SOURCE_DIR="aobook-haiku-${portVersion/_/-}"

次に互換性のある環境を指定します。

ARCHITECTURES="!x86_gcc2 x86 x86_64"
SECONDARY_ARCHITECTURES="x86"

x86_gcc2 でビルドできないため、前に ! 記号がついています。 haikuports.conf で二番目のアーキテクチャが有効なら SECONDARY_ARCHITECTURES に指定されているアーキテクチャが利用できるかもしれません。

PROVIDES ではパッケージ名とインストール後に提供される実行ファイルなどを記載します。app 指定は実行ファイルが /boot/system/apps に入ることを示します。

PROVIDES="
    aobook$secondaryArchSuffix = $portVersion
    app:Aobook = $portVersion
"
REQUIRES="
    haiku$secondaryArchSuffix
    lib:libfontconfig$secondaryArchSuffix
    lib:libfreetype$secondaryArchSuffix
    lib:libiconv$secondaryArchSuffix
    lib:libjpeg$secondaryArchSuffix
    lib:libpng16$secondaryArchSuffix
    lib:libz$secondaryArchSuffix
    "

REQUIRES は実行時に必要なファイルを指定します。$secondaryArchSuffix は SECONDARY_ARCHITECTURES 用にビルドしたときに _x86 などが追加されることを示します。

BUILD_REQUIRES はビルド時にリンクされるライブラリです。

BUILD_REQUIRES="
    haiku${secondaryArchSuffix}_devel
    devel:libfontconfig$secondaryArchSuffix
    devel:libfreetype$secondaryArchSuffix
    devel:libiconv$secondaryArchSuffix
    devel:libjpeg$secondaryArchSuffix
    devel:libpng16$secondaryArchSuffix
    devel:libz$secondaryArchSuffix
    "
BUILD_PREREQUIRES="
    makefile_engine
    cmd:g++$secondaryArchSuffix
    cmd:gcc$secondaryArchSuffix
    cmd:make
    cmd:sed
    "

BUILD_PREREQUIRES はビルド時に必要な make やコンパイラなどのツールを指定します。ビルドは隔離された環境で行われるため、ここで指定していないツールは利用できずにエラーになることがあります。リンクするライブラリなども同様です。自作のレシピをビルドするときにエラーが出た場合、必要なファイルを見直して追加してみてください。

BUILD ではビルドするコマンドなどを記載します。

BUILD()
{
    make -C mlib -f Makefile.haiku $jobArgs OBJ_DIR=objects
    make -C src -f Makefile.haiku $jobArgs OBJ_DIR=objects \
        default catalogs bindcatalogs
}

INSTALL ではインストール時に実行するコマンドを指定します。特殊なコマンドもあり、ここでは実行ファイルをデスクバーのメニューから実行できるように addAppDeskbarSymlink で登録しています。

INSTALL()
{
    mkdir -p $appsDir
    cp -af src/objects/aobook $appsDir/Aobook

    mkdir -p $dataDir/aobook/doc
    cp -af doc/manual.html $dataDir/aobook/doc

    addAppDeskbarSymlink $appsDir/Aobook

    mkdir -p $dataDir/locale/catalogs/x-vnd.azsky.aobook
    cp src/objects/x-vnd.azsky.aobook/* \
        $dataDir/locale/catalogs/x-vnd.azsky.aobook
}

このレシピを haikuporter でビルドするとインストール可能なパッケージができます。レシピを haikuports に取り込んでもらえば、いつのまにか HaikuDepot からインストールできるようになります。