株式会社クリアコード > ククログ

ククログ


GTK-Docの使い方

GNOME Advent Calendar 2013 2日目の記事です。1日目はmyokoymさんの「Ruby/GTK3で作るカレンダーアプリ」でした。

C言語で書かれていて、Autotoolsでビルドシステムを構築しているプロジェクトがあるとします。このプロジェクトのドキュメントツールとしてGTK-Docを使う方法を説明します。

長いです。

GTK-Docについて

GTK-Docはその名の通りGTK+用のドキュメントツールです。GTK-Docは、公式サイトにも書いてある通り、一般的なドキュメントツールではなくGTK+に特化したドキュメントツールです。もう少し細かくいうと、GObjectに特化したドキュメントツールです。

「GObjectに特化している」というのは、次の機能を備えているからです。

  • GObjectのプロパティー専用のドキュメント機能
  • GObjectのシグナル*1専用のドキュメント機能
  • GObjectのクラスの継承関係を表示する機能

これらは通常のドキュメントツールにはない機能です。

GTK-DocはDocBookをバックエンドに使ったドキュメントツールなので他のドキュメントツールと同じくらい表現力があります。そのため、GObjectを使ったプロジェクトなら、他のドキュメントツールではなくGTK-Docを使ったほうがユーザーにとって使いやすいドキュメントを提供できます。

ただし、GObjectを使っていないのであれば、別のドキュメントツールも検討したほうがよいでしょう。例えば、C++も使うなら確実に他のツールの方がよいです。GTK-DocはC++をサポートしていません。

なお、Cutterのリファレンスマニュアルmilter managerのリファレンスマニュアルはGTK-Docを使っています。これらのプロジェクトではGObjectを使っているからです*2

GTK-Docの使い方

それでは、例を出しながらGTK-Docの使い方を説明します。ここで作るライブラリーはGitHubに置いてあります。ライセンスはCC0 (Public Domain)にするので、自由に再利用してください。

ここでは、「libsample」というライブラリーを作ります。このライブラリーの中にあるクラスはSampleGreeterだけです。

次の順に説明します。

  • GObjectを使ったプロジェクトを作成(GTK-Docはまだ使わない)
  • 作ったプロジェクトでGTK-Docを使う
GObjectを使ったプロジェクトを作成

それでは、GObjectを使ったプロジェクトを作成します。このセクションはそれほど大事なことではないので、興味のない人は飛ばしてもかまいません。

まずはこのライブラリーの実装を用意します。.cも.hも「sample/」以下に置きます。クラス定義について、GObjectの使い方を知っている人は「いつもの感じ」と思うかもしれませんが、知らない人は面倒だと思うことでしょう。

sample/greeter.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

#ifndef SAMPLE_GREETER_H
#define SAMPLE_GREETER_H

#include <glib-object.h>

G_BEGIN_DECLS

#define SAMPLE_TYPE_GREETER \
  (sample_greeter_get_type())
#define SAMPLE_GREETER(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj), SAMPLE_TYPE_GREETER, SampleGreeter))
#define SAMPLE_GREETER_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass), SAMPLE_TYPE_GREETER, SampleGreeterClass))
#define SAMPLE_IS_GREETER(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj), SAMPLE_TYPE_GREETER))
#define SAMPLE_IS_GREETER_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_TYPE((klass), SAMPLE_TYPE_GREETER))
#define SAMPLE_GREETER_GET_CLASS(obj) \
  (G_TYPE_INSTANCE_GET_CLASS((obj), SAMPLE_TYPE_GREETER, SampleGreeterClass))

typedef struct _SampleGreeter         SampleGreeter;
typedef struct _SampleGreeterClass    SampleGreeterClass;

/**
 * SampleGreeter:
 *
 * A SampleGreeter greets.
 */
struct _SampleGreeter
{
    /*< private >*/
    GObject parent_instance;
};

struct _SampleGreeterClass
{
    GObjectClass parent_class;
};

GType          sample_greeter_get_type (void) G_GNUC_CONST;
SampleGreeter *sample_greeter_new      (void);
const gchar   *sample_greeter_greet    (SampleGreeter *greeter);

G_END_DECLS

#endif

sample/greeter.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "greeter.h"

/**
* SECTION: greeter
* @short_description: A greeter.
*
* The #SampleGreeter is a class to greet.
*/
G_DEFINE_TYPE(SampleGreeter, sample_greeter, G_TYPE_OBJECT)

static void
sample_greeter_init(SampleGreeter *object)
{
}

static void
sample_greeter_class_init(SampleGreeterClass *klass)
{
}

/**
 * sample_greeter_new:
 *
 * Allocates a new #SampleGreeter.
 *
 * Returns: a new #SampleGreeter.
 */
SampleGreeter *
sample_greeter_new(void)
{
    SampleGreeter *greeter;
    greeter = g_object_new(SAMPLE_TYPE_GREETER, NULL);
    return greeter;
}

/**
 * sample_greeter_greet:
 * @greeter: A #SampleGreeter.
 *
 * Greets.
 *
 * Returns: Message from a greeter.
 */
const gchar *
sample_greeter_greet(SampleGreeter *greeter)
{
    return "Hello!";
}

コード中の次のようなコメントの中に書かれているドキュメントがGTK-Doc用のドキュメントです。ドキュメントを.cに書くドキュメントツールと.hに書くドキュメントツールがありますが、GTK-Docは主に.cです。ざっくり言うと、実装のそばにドキュメントを書くスタイルということです。

1
2
3
/**
 ...
 */

次に、これらのソースをビルドする部分を作ります。次のようなディレクトリー構成にします。

.
|-- Makefile.am
|-- autogen.sh
|-- configure.ac
`-- sample
    |-- Makefile.am
    |-- greeter.c
    `-- greeter.h

まず、configure.acを作ります。コメントを入れておいたのでなんとなくわかるでしょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Autoconf 2.65以上を必須にする
# これは、Automake 1.13がAutoconf 2.65以上が必須だから
AC_PREREQ(2.65)

# Autoconfを初期化
AC_INIT([gtk-doc-sample], [1.0.0], [kou@clear-code.com])
# 補助スクリプトをconfig/以下に置く
AC_CONFIG_AUX_DIR([config])
# M4マクロをm4/以下に置く
AC_CONFIG_MACRO_DIR([m4])

# ソースディレクトリーを検出するために、
# ソースディレクトリーに必ずあるファイルを指定
AC_CONFIG_SRCDIR([sample/greeter.h])
# AC_DEFINEで定義した変数を出力するヘッダーファイルを指定
AC_CONFIG_HEADERS([config.h])

# 1.13:    Automake 1.13以降必須
# foreign: NEWSなどのファイルを必須としない
AM_INIT_AUTOMAKE([1.13 foreign])
# ビルドする時にコマンドラインではなく
# どんな役割のコマンドを実行しているかを出力するだけにする
AM_SILENT_RULES([yes])

# Cコンパイラーを検出
AC_PROG_CC
# Libtoolsを初期化
LT_INIT

# GLib 2.32.4以降必須
# GLibの中のgobjectモジュールを使う
AM_PATH_GLIB_2_0([2.32.4], [], [], [gobject])

# .inから生成するファイルを指定
AC_CONFIG_FILES([
  Makefile
  sample/Makefile
])

# AC_CONFIG_FILESで指定したファイルなどを生成
AC_OUTPUT

続いてMakefile.amです。「aclocal」用の設定ぐらいのものです。

Makefile.am:

1
2
3
4
5
6
7
8
9
# configure.acでm4/以下にM4マクロを置くようにしたので
# m4/以下もパスに加える。
# また、ユーザーがACLOCAL_FLAGS環境変数でオプションを
# 渡せるようにしている。
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}

# 再帰的にsample/以下もmakeする。
SUBDIRS =                                        \
        sample

最後にsample/Makefile.amです。

sample/Makefile.am:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# top_builddirはconfig.hを探すため
# top_srcdirはプロジェクトのヘッダーファイルを探すため
AM_CPPFLAGS =                                        \
         -I$(top_builddir)                        \
         -I$(top_srcdir)

# .cからGLibを使うためのコンパイラーオプションを指定
AM_CFLAGS =                                        \
        $(GLIB_CFLAGS)

# 作成する共有ライブラリー(libsample)を指定
lib_LTLIBRARIES =                                \
        libsample.la

# libsampleで使うライブラリー(GLib)を指定
libsample_la_LIBADD =                                \
        $(GLIB_LIBS)

# libsampleのソースファイルを指定
libsample_la_SOURCES =                                \
        greeter.c                                \
        greeter.h

autogen.shを用意すればビルドできます。

autogen.sh:

1
2
3
4
5
6
7
#!/bin/sh

set -u
set -e

mkdir -p m4
autoreconf --install

それではビルドしてみましょう。

% ./autogen.sh
% ./configure --prefix=/tmp/local
% make
% make install

これで/tmp/local/lib/libsample.soができます。

GTK-Docを使う

このプロジェクト用のドキュメントをGTK-Docで生成する仕組みを作ります。

ポイントは次の4つです。

  • autogen.shでgtkdocizeを使う
  • configure.acでGTK-Docを検出する
  • GTK-Doc用のファイルを作る

ファイルを作る前に、GTK-Docを使うようになった後のディレクトリー構造を示します。

.
|-- Makefile.am                 変更!
|-- autogen.sh                  変更!
|-- configure.ac                変更!
|-- doc                         新規!
|   |-- Makefile.am             新規!
|   `-- reference               新規!
|       |-- Makefile.am         新規!
|       |-- sample-docs.sgml    新規!
|       `-- version.xml.in      新規!
`-- sample
    |-- Makefile.am
    |-- greeter.c
    `-- greeter.h

doc/以下を新しく作り、それに伴いトップディレクトリーにある次のファイルを変更します。

  • Makefile.am
  • autogen.sh
  • configure.ac

それでは、autogen.shからいきましょう。

GTK-Docを使うための補助的なファイルを生成するgtkdocizeというコマンドがあります。これは、autoreconfを実行するために必要なファイルも生成するので、autoreconfの前に実行します。gtkdocizeもautoreconfのようにm4/ディレクトリー以下にファイルをコピーするのでmkdirよりは後にします。

autogen.sh:

1
2
3
4
5
6
7
8
9
10
11
diff --git a/autogen.sh b/autogen.sh
index 41bf970..2275409 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -4,4 +4,6 @@ set -u
 set -e

 mkdir -p m4
+
+gtkdocize --copy --docdir doc/reference
 autoreconf --install

configure.acでは、GTK-Docを検出するようにします。

configure.ac:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
diff --git a/configure.ac b/configure.ac
index 3df3497..1164668 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,6 +31,9 @@ LT_INIT
 # GLibの中のgobjectモジュールを使う
 AM_PATH_GLIB_2_0([2.32.4], [], [], [gobject])

+# GTK-Docを検出
+GTK_DOC_CHECK([1.18-2])
+
 # .inから生成するファイルを指定
 AC_CONFIG_FILES([
   Makefile

これでGTK-Docを下準備はできました。それでは、GTK-Docの設定にいきます。

GTK-Docの設定はdoc/reference/以下で行います。まずは、トップディレクトリーでmakeしてもdoc/reference/まで再帰的に降りていってくれるようにしましょう。次のファイルを編集します。

  • Makefile.am
  • doc/Makefile.am
  • configure.ac

Makefile.am:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
diff --git a/Makefile.am b/Makefile.am
index 870d996..73ee162 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,7 @@
 # 渡せるようにしている。
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}

-# 再帰的にsample/以下もmakeする。
+# 再帰的にsample/、doc/以下もmakeする。
 SUBDIRS =                                        \
-        sample
+        sample                                        \
+        doc

doc/Makefile.am:

1
2
3
# 再帰的にreference/以下もmakeする。
SUBDIRS =                                        \
        reference

configure.ac:

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/configure.ac b/configure.ac
index 1164668..abb481c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,8 @@ GTK_DOC_CHECK([1.18-2])
 AC_CONFIG_FILES([
   Makefile
   sample/Makefile
+  doc/Makefile
+  doc/reference/Makefile
 ])

 # AC_CONFIG_FILESで指定したファイルなどを生成

これでdoc/reference/までの道ができました。doc/reference/Makefile.amがGTK-Docの設定をする場所です。意外とパラメーターが多いなぁと思うことでしょう。

doc/reference/Makefile.am

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# モジュール名
DOC_MODULE = sample

# エントリーポイントになるファイル名
# 「${モジュール名}-docs.sgml」という名前付け規則が広く使われている
# のでそのまま従うのがよい。
DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.sgml

# ソースコードがあるディレクトリー
DOC_SOURCE_DIR =                                \
        $(top_srcdir)/sample

# 非推奨になったAPIを検出するためのオプションを指定
# 今回は使っていないが開発を続けていくライブラリーなら
# きっと必要になる
SCAN_OPTIONS =                                                \
        --deprecated-guards="SAMPLE_DISABLE_DEPRECATED"

# ライブラリー内で関数名の最初に使う名前空間用プレフィックスを指定
MKDB_OPTIONS =                                        \
        --name-space=sample

# ヘッダーファイルを指定するグロブパターン
HFILE_GLOB =                                        \
        $(top_srcdir)/sample/*.h

# ソースファイルを指定するグロブパターン
CFILE_GLOB =                                        \
        $(top_srcdir)/sample/*.c

# ソースコードをビルドするために必要なCプリプロセッサー用のオプション
# $(top_srcdir)/sample/Makefile.amで指定したものと同じものを指定すればよい。
# ただし、ビルドするディレクトリーが違うのでそこは考慮する必要がある。
AM_CPPFLAGS =                                        \
        -I$(top_builddir)                        \
        -I$(top_srcdir)

# ソースコードをビルドするために必要なCコンパイラー用のオプション
# $(top_srcdir)/sample/Makefile.amで指定したものと同じものを指定すればよい。
# ただし、ビルドするディレクトリーが違うのでそこは考慮する必要がある。
AM_CFLAGS =                                        \
        $(GLIB_CFLAGS)

# ライブラリーをリンクするためのオプション
GTKDOC_LIBS =                                        \
        $(top_builddir)/sample/libsample.la        \
        $(GLIB_LIBS)

# GTK-Docが用意したMakefileを読み込む
include $(srcdir)/gtk-doc.make

# make cleanでsample-sections.txtとsample.typesを削除する。
# (詳細は本文で。)
CLEANFILES +=                                        \
        $(DOC_MODULE)-sections.txt                \
        $(DOC_MODULE).types

どのパラメーターも悩まずに設定できるはずです。新しく決めることはなく、事実を埋めていくだけです。

次の2点を補足します。

  • ドキュメントを生成するのにどうしてビルドオプションを指定するのか
  • CLEANFILESに指定しているものはなにか

まず、ビルドオプションについてです。GTK-Docはドキュメントを生成するために、ドキュメント対象のライブラリーを組み込んだ実行ファイルを作成します。その実行ファイルを実行してライブラリーのメタデータを動的に取得します。メタデータとはクラス階層やどんなプロパティーを持っているかなどです。GTK-DocがGObjectに特化したドキュメントツールなのでここまでやっているのです。

次に、CLEANFILESに指定している次のファイルについてです。

  • sample-sections.txt
  • sample.types

GLibやGTK+での使い方をみると、どちらもリポジトリーに入れて管理することを期待しているファイルのようにみえます。しかし、ここではリポジトリーに入れずに自動で生成するようにします。理由は、どちらも手動で管理することが面倒だからです。

sections.txtはドキュメント対象とする関数や構造体を列挙するファイルで、.typesは自分で作ったオブジェクト*3を列挙するファイルです。開発が進むにつれ、ここに列挙しなければいけないことが増えますが、それをいちいちやっていられません。これらのファイルはなければ前述したメタデータなどから自動的に作成されます。多少ゴミもまじりますが、手動で管理する手間を考えれば割にあいます。そのため、CLEANFILESに入れています。

最後にドキュメントのエントリーポイントとなるXMLファイルとそこで使うファイルを作成して仕組みは完成です。ポイントは<xi:include>のところです。他は一度作ったら後はほとんど使いまわせます。

doc/reference/sample-docs.sgml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY version SYSTEM "version.xml">
]>
<book xmlns:xi="http://www.w3.org/2003/XInclude" id="index" lang="en">
  <bookinfo>
    <title>Sample Reference Manual</title>
    <releaseinfo>for Sample &version;</releaseinfo>
  </bookinfo>

  <part id="reference">
    <title>Reference</title>
    <chapter id="libsample">
      <title>libsample</title>
      <xi:include href="xml/greeter.xml"/>
    </chapter>
  </part>

  <index id="index-all">
    <title>Index of all symbols</title>
  </index>
  <index id="index-deprecated" role="deprecated">
    <title>Index of deprecated symbols</title>
  </index>
  <index id="index-1-0-0" role="1.0.0">
    <title>Index of new symbols in 1.0.0</title>
  </index>
</book>

新しいクラスができたら対応する<xi:include>を増やしていきます。そうするとドキュメントに組み込まれます。

version.xmlを参照しているので作ります。ここにはバージョン番号だけが入るので、.inからconfigureで作ります。

sample/doc/reference/version.xml.in:

1
@VERSION@

.inを作ったのでconfigure.acも変更します。

1
2
3
4
5
6
7
8
9
10
11
12
diff --git a/configure.ac b/configure.ac
index abb481c..9a925d1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,7 @@ AC_CONFIG_FILES([
   sample/Makefile
   doc/Makefile
   doc/reference/Makefile
+  doc/reference/version.xml
 ])

 # AC_CONFIG_FILESで指定したファイルなどを生成

これで仕組みができました。GTK-Docを使ったドキュメントを作ってみましょう。configureで--enable-gtk-docを指定することがポイントです。

% ./autogen.sh
% ./configure --prefix=/tmp/local --enable-gtk-doc
% make
% make install

これで/tmp/local/share/gtk-doc/html/sample/index.htmlにHTMLができているはずです。

まとめ

実例を用いてプロジェクトのビルドシステムにGTK-Docを組み込む方法を説明しました。GTK+などGObjectベースのライブラリーを作っている場合はドキュメントはGTK-Docで提供することをオススメします。GObjectに特化した情報のドキュメントの作成が容易ですし、わりと小ぎれいなドキュメントができます。ぜひ、GTK-Docを使ってみてください。

ここで作った例はGitHubに置いてあります。ライセンスはCC0 (Public Domain)なので自由に再利用してください。

*1 kill(1)で送るシグナルとは違う。

*2 CutterではGTK+を少し使っていますが、milter managerではGTK+を使っていません。GTK+がベースとしているライブラリーであるGLibやGObjectの機能だけを使っています。

*3 もう少し言うとGType

2013-12-02

全文検索エンジンGroongaを囲む夕べ 4での発表資料

2013年11月29日(いい肉の日)に全文検索エンジンGroongaを囲む夕べ 4が開催されました。会場の提供から運営、懇親会の飲み物や肉メインのおいしい食べ物の提供まで、DeNAさんが全面的にバックアップしてくれました。とても感謝しています。

平日の17時と早い時間からのスタートにも関わらず、130名くらいも参加*1してくれました。4時間という長い時間のイベントだったので、みなさんだいぶ疲れたのではないでしょうか。DeNAさんが用意してくれた懇親会の飲み物と食べ物をよりおいしく感じたかもしれませんね。

今年もUstream配信すずきさんが協力してくれました。ありがとうございます。遠方で参加できない人などの役に立っていたようでよかったです。録画してあり、今でも観れるので当日参加できなかった方はご利用ください。

イベントの内容はTwitter上にも流していました。Togetterまとめで当日のTwitter上での情報を確認できるのでこちらも合わせてご利用ください。Twitterでの情報提供は@hyoshihara04さんが手伝ってくれました。

軽妙な語り口でスムーズな進行をしてくれたのは今年も坂井さんです。坂井さんの司会はUstreamの録画でお楽しみください。

さて、今回のイベントではクリアコードのメンバー3人の発表がありました。参加できなかった人でもわかるように、それぞれの発表について説明します。発表内容は次のとおりです。

  • Groonga族2013:Groonga関連プロダクトの概要と最新情報の紹介
  • Groongaビジネスパートナー募集:Groongaでのビジネスを一緒に盛り上げようというお誘い
  • Groongaを支える取り組みの紹介:Groongaをもっと便利に使えるようにするための取り組みを紹介

Groonga族2013

まず、Groonga関連プロダクトの概要と最新情報の紹介した「Groonga族2013」について説明します。発表資料は次の場所にあります。どちらも同じものです。

概要

この発表では次の3つについて話しました。

  • Groonga関連プロダクトの公式表記が先頭大文字で「Groonga」や「Mroonga」になったこと。
  • Groongaそれ自体と他の関連プロダクトの関係。
  • Groonga関連プロダクトのここ1年での改良点を紹介。
公式表記の変更について

公式表記について補足します。これまでは、主に「groonga」(すべて小文字)、たまに*2「Groonga」(先頭大文字)という表記を使っていましたが、今後は「Groonga」(先頭大文字)という表記のみを使っていきます。

このように表記を統一する理由は、世界進出を視野にいれているからです。これまで英語圏の人とやりとりしていた経験から、英語圏では先頭大文字表記の方がなじみがあることがわかりました。今後、世界でGroongaについて話題にするときによりなじみやすくするために先頭大文字で統一することにしました。今後は、ユーザーのみなさんもGroongaの世界進出を後押しするためにこの表記を使ってくださいとお願いしました。

表記の変更についてはGroonga公式サイトでのアナウンスも参考にしてください。

プロダクトの関係について

Groongaそれ自体と他の関連プロダクトの関係については、図入りで説明しました。図があったほうがわかりやすいので、発表資料を参照してください。

ここ1年の改良点について

現在、Groonga関連のイベントは年に1回いい肉の日に開催されている「全文検索エンジンGroongaを囲む夕べ」のみです。そのため、前回のイベントからこの1年でGroonga関連プロダクトが成長しているかの概要を紹介しました。紹介した内容は次のとおりです。

  • Groonga
    • Fedora公式パッケージになった。CentOS 7くらいではCentOS 7にも入るだろう。
    • mrubyの組み込みを始めた。ただし、まだ実験的な機能。
  • Mroonga
    • Windowsサポートを始めた。
    • MariaDBバンドル作業が進行中。
  • Rroonga

もう少し粒度を小さくするともっとたくさんありますが、時間の関係でこのくらいにとどめました。詳細はGroongaの更新履歴ページMroongaの更新履歴ページを確認してください。

まとめ

「Groonga族2013」では次の3点について話しました。

  • Groonga関連プロダクトの公式表記が先頭大文字で「Groonga」や「Mroonga」になったこと。
  • Groongaそれ自体と他の関連プロダクトの関係。
  • Groonga関連プロダクトのここ1年での改良点を紹介。

Groongaビジネスパートナー募集

次に、Groongaでのビジネスを一緒に盛り上げようという「Groongaでビジネスしませんか? -Groongaビジネスパートナー構想のご紹介」発表について説明します。

概要

Groongaの普及にともなって、Groongaを使ってみたい、Groongaをとことん使いこなしたいという企業からの問い合わせが増えてきました。また、Groongaを使ったサービスのアイデアももらうようになりました。しかし、現在の体制ではこのような要望に十分に応えられていません。Groongaの更なる普及には、Groongaを使ったシステム開発やGroongaのサポートに対応する体制を強化する必要があります。

その方法としてGroongaに関連したサービスを提供する企業が共同でPR活動を行ったり、一緒にサービスを開発する体制を構築する予定です。サポートを提供する企業が多く存在することによってユーザの選択肢が増加し、さらにそれぞれの企業が連携してより大きなサービスを提供することが可能となることを期待しています。

これはクリアコードでのいくつかの経験を参考にしています。ひとつは、Mozilla Japanのサポートパートナーに参加して、Mozilla Firefox、Thunderbirdの企業導入を行ってきた経験です。サポートパートナーが連携して1つの案件を獲得することもありますし、サポートパートナーが1つの案件で競合することもあります。いずれも複数のサポート企業が存在することによってできることです。Groongaに関しても複数のサポート企業がユーザから見やすいかたちで存在することが重要です。

もうひとつはクリアコードで案件を請けられない時に信頼できる企業を紹介してきた経験です。MozillaのサポートやRubyによる開発などクリアコードに仕事の依頼をもらっても、リソースがないことが理由で請けられないケースがあります。このような時に、せっかく問い合わせしてもらったので、なにかお役に立てないか他の企業を紹介することがあります。具体的には一緒に仕事をした経験があり、また一緒に仕事をしたいと思う企業を優先して紹介します。そして、紹介したことによってビジネスが生まれれば、問い合わせした企業、クリアコード、紹介した企業の3社の間に信頼関係ができます。Groongaをキーワードにこのような信頼の連鎖を作っていきたい考えです。

Groongaビジネスパートナー構想を検討するにあたって、クリアコードの経験だけでなく、参加を検討される方々の経験やアイデアを参考にしていきます。そのため、12月からGroongaでのビジネスに興味のある方からお話を伺っていきます。興味のある方はぜひminami@clear-code.comまでご連絡ください。

発表者の感想

素敵な会場での発表で、非常に緊張してしまい、伝えきれなかったところが多々ありました。しかし、発表の後、何人かから声をかけていただき、Groongaビジネスパートナー構想への参加を検討していただけることになりました。うれしい限りです。来年2月9日の発足に向けてしっかり進めて行きたいと思います。ありがとうございました。

Groongaを支える取り組みの紹介

最後に、Groongaをもっと便利に使えるようにするための取り組みを紹介をした「Groongaを支える取り組みの紹介」について説明します。

概要

この発表では次のことについて話しました。

  • この1年でやってきたGroongaの利用事例やノウハウを共有する取り組み
  • Groongaを使っていて困った時の助けの求め方
  • Groongaプロジェクトへの貢献のお誘い
利用事例やノウハウを共有する取り組み

利用事例やノウハウを共有するために、今年は次の2つに取り組みました。

週刊Groongaは毎週木曜日にQiitaにGroonga、Mroonga、Rroonga関連のちょっとした便利情報をまとめているものです。Mroonga関連の記事が人気です。

記事を公開したら@groongaで告知しています。フォローして最新記事を確認してみてください。

隔週連載Groongaはgihyo.jpさんで4月から9月まで約半年(ほぼ)隔週で続けた連載です。Groonga関連プロダクトの事例紹介とその事例紹介に関連する技術情報を提供しています。今でもすべての記事を読めるのでチェックしてみてください。なお、今回のイベントレポートもgihyo.jpさんに載る予定です。楽しみですね。

困った時の助けの求め方

Groongaはこつこつと開発を続けてだいぶよいソフトウェアになってきました。しかし、困ることもあるでしょう。そんなときは、Twitterにつぶやいたりgroonga-devメーリングリストで質問したりしてみてください。

Groonga開発者は「Groonga」や「Mroonga」などのキーワードで困っている人がいないかをチェックしています。Twitterでつぶやくと開発者の人から助けてもらえるかもしれません。

Twitterでは確実に返事をもらえるわけではありませんが、メーリングリストでは確実に返事をもらえます。バグ報告や機能要望だけではなく、どうやったらうまく使えるか、といった質問も受けつけています。

メーリングリストというと敷居が高いかもしれませんが、groonga-devメーリングリストは技術系メーリングリストで質問するときのパターン・ランゲージ真・技術系メーリングリスト FAQから想起されるような殺伐とした場所ではありません。過去のメールを見ればわかるはずです。「メーリングリストに投稿したらすぐに直してもらえた」という利用者の声もあります。お気軽にご利用ください。

Groongaプロジェクトへの貢献のお誘い

Groongaをよりよくしていくために、ユーザーのみなさんの協力を待っています。次のようなことにピンときたら、ぜひ協力してください。

  • 週刊Groongaの翻訳
    • Groongaの世界進出を推進するために、英語圏へもGroongaの有用な情報を届けたい。週刊Groongaという日本語のコンテンツがあるので、それを翻訳して、Groongaの世界進出を後押しして欲しい。
    • 難易度:元の文章はあるので英語の読み書きができれば簡単
  • コマンドのドキュメントのフォーマットを統一
    • 現在は、Groongaのコマンドのドキュメントの表記が統一されていない。統一するとユーザーがドキュメントを読みやすくなるため、Groongaを使いやすくなる。
    • 難易度:簡単(テキストの整形だけ)
  • 「groonga」表記を「Groonga」表記へ統一
    • 公式表記は「Groonga」と表明しているのにドキュメント中には小文字表記が多く残っていて、公式表記の普及に悪影響がある。
    • 難易度:簡単(テキストの修正だけ)
  • Groonga Advent Calendar 2013
    • 参照できるGroonga関連情報が増えるので、Groonga普及に役立つ。
    • 難易度:Groonga関連プロダクトをすでに使っていれば簡単

Groongaに貢献したいと思っているけど何をすればいいかわからなかった、という方はぜひ参考にしてください。

まとめ

毎年いい肉の日に開催しているGroongaイベントでの発表内容を紹介しました。

冒頭にも書いたとおり、DeNAさんには本当にお世話になりました。きっかけを作ってくれた@sunaotさん@ryopekoさん、ありがとうございました。パーフェクトRubyが縁でした。

*1 参加登録者が約160名なのでの約8割。ATNDでイベントにしては参加率が高い方ではないでしょうか。

*2 例えば英語の文章で先頭にくるときだけ。

2013-12-04

スクリプト言語の拡張機能の作り方とGObject Introspectionの紹介

GNOME Advent Calendar 2013 9日目の記事です。

多くのスクリプト言語では、スクリプトからCで書かれたライブラリーを使うための機能を提供しています。ここでは便宜的に「拡張機能」と呼びます。「拡張機能」はスクリプト言語毎に違う名前がついています。例えば、Rubyでは「拡張ライブラリ」と呼んでいて、Pythonでは「拡張モジュール」と呼んでいます*1

Cで書かれたライブラリーを使えるとできることが一気に増えます。既存の機能を利用できるからです。

例えば、NroongaGroongaというCで書かれた全文検索エンジンライブラリーを使う機能を200行くらいのC++で実装しています。これでNode.jsから全文検索機能を使うことができるようになります。いくらJavaScriptの方がCよりも簡潔に記述できるといっても、200行でGroongaと同じ機能・同じ性能の全文検索エンジンを実現することはできません。

このように、Cで書かれたライブラリーをスクリプト言語から使えるようにする機能は便利な機能です。今回は、その機能をより簡単に使うためのソフトウェアGObject Introspectionを紹介します。あわせて、拡張機能の書き方もいろいろ紹介します。

拡張機能の書き方

GObject Introspectionの紹介をする前に、拡張機能の書き方について説明します。これは、どうしてGObject Introspectionが必要とされているのかということを説明するために必要となるからです。

拡張機能の仕事はスクリプト言語とCで書かれたライブラリーの隙間を埋めることです。例えば、スクリプト言語での「文字列」とCの「文字列」は違う表現になっています。拡張機能はそれらの相互変換をします。隙間を埋めるという役割が「糊」の役割と似ていることから、拡張機能を実現するためのコードをグルー(糊の英語)コードと呼んだりします。

それでは、グルーコードの書き方を紹介します。

手書き

最初の書き方は手動で書いていく書き方です。

グルーコードはスクリプト言語の値とCでの値を相互変換する処理がほとんどなので、定型的な記述が多くなります。そのため、慣れてしまえば簡単に書くことができます。最も基本的な書き方です。

ただし、簡単というのは「技術的に」簡単なだけであって、「時間的に」は簡単ではありません。スクリプト言語に提供したいCのAPIが多いと、「技術的に」簡単でも、手間のかかる作業です。

自動生成

そんな手間のかかるけど定型的な作業を軽減するための書き方が、グルーコードを自動生成する方法です。

Cのヘッダーファイルから自動生成したり、手動で自動生成するための情報(グルーコードを書くよりは少ない記述で済む)を作成し、それを使って自動生成したりします。

この方法を使っているのが、PerlのXSや、Gaucheのgauche-packageと.stubの組み合わせなどです。言語に依存しないSWIGというソフトウェアもあります。

この方法では、一度C/C++のソースコードを生成し、それをコンパイルすると使えるようになります。そのため、この方法で作られた拡張機能を使うためにはコンパイラーが必要になります。

動的呼び出し

コンパイラーが必要になるとインストールの敷居がグッとあがります。そのため、コンパイラーがなくても動くようにしたくなります。また、コンパイラーから脱却するならグルーコードをスクリプト言語自身で書きたくなります。

そこで、FFI(Foreign Function Interface)です。FFIを使えば、事前にコンパイルしなくても、実行時にCで書かれたライブラリーの関数を呼び出すことができます。

FFIの実装はlibffiが有名ですが、RubyのDL*2のように自前でlibffiと同じような機能を実装しているライブラリーもあります。

libffi(Cで書かれたライブラリー)を使うための拡張機能を標準で提供しているスクリプト言語も増えています。Pythonはctypesというモジュールを提供していますし、RubyはFiddleを提供しています。Mozillaが搭載しているJavaScriptではjs-ctypes*3を使えます。

FFIを使うことにより、コンパイラーは必要なくなり、スクリプト言語でグルーコードを書けるようになります。しかし、libffiでは関数のシグネチャーの情報を取得する機能は提供していないので、スクリプト言語側から返り値の情報を与えなければ適切に動きません。グルーコードを作る手間はだいぶ減りましたが、使いたいAPIが多い場合はまだ手間がかかります。

メタ情報を動的に取得

Cで書かれたライブラリーがどのようなシグネチャーの関数を提供しているかを実行時に知ることができれば、その情報を使って動的に自動でグルーコードを動的に生成できます。ほぼ全自動です。

この方法を実現しているのがGObject Introspectionです。GObject IntrospectionはGTK+*4が使っているオブジェクトシステムの仕組みを使って動的にメタ情報を取得する機能を提供しています。また、libffiを使って動的に関数を呼び出す機能も提供しています。これらの機能を使うことによりほぼ全自動で動的にグルーコード相当のことをする機能を実現できます。

GTK+と同じくクロスプラットフォーム対応のGUIツールキットであるQtも同様の機能を提供しています。それはSMOKEと呼ばれています。

これらの仕組みを使えば、Cで書かれたライブラリーのバージョンが変わり、APIが増えても、グルーコード用の処理をなにも変更せずに対応できます。拡張機能のメンテナンスがほぼ0で常に最新の機能を使えるということです。

まとめ

Cで書かれたライブラリーの機能をスクリプト言語から使うための仕組みの実現方法を4つ紹介しました。

  • 手動でグルーコード(C/C++)を書いてビルドする
  • 自動でグルーコード(C/C++)を生成してビルドする
  • FFIを使ってスクリプト言語から動的に関数を呼び出す(関数のシグネチャーは手動で設定)
  • Cで書かれたライブラリーのメタ情報を取得し、それを基にFFIで動的に関数を呼び出す(ほぼ全自動)

ここで紹介した方法はすべて今でも使われているものです。後になるほどより便利になっているので先に紹介した方法はすでに過去のものと感じたかもしれませんが、そんなことはありません。

例えば、手動でグルーコードを書くことは面倒でイヤだと思うかもしれませんが、FFIのオーバーヘッドがない分、高速に動作するというメリットがあります。また、自動生成するAPIに比べてより使いやすいAPIを提供しやすく*5なります。適材適所です。

拡張機能を実現する仕組みを紹介したうちの最後の仕組み「ほぼ全自動で動的に拡張機能を使う仕組み」を実現したライブラリーとしてGObject Introspectionがあることを紹介しました。

GObject Introspectionの使い方は別の機会に紹介します。

*1 Cで書かれたライブラリーを呼び出さない「拡張ライブラリ」や「拡張モジュール」もあります。その場合は、それら自身が「Cで書かれたライブラリー」と考えることもできます。しかし、ここではあまり厳密に考えなくてもよいです。

*2 Ruby 2.0からはdeprecatedになっています。

*3 名前からわかる通り、Pythonのctypesを参考にしています。

*4 C言語で実装されているクロスプラットフォーム対応のGUIツールキット。ようやくGNOMEっぽい単語がでてきました。

*5 もちろん、開発者がどれだけがんばるか次第です。手動で作ったからよいAPIになるわけではありません。

2013-12-09

パーフェクトRubyのおかげでYARDがよくなってGroongaイベントも開催できた話

パーフェクトRuby Advent Calendar 2013の10日目の記事です。

9日目の記事はパーフェクトなCRubyを目指して - 1行のバグ修正に潜む苦労 - - I am Cruby!です。

パーフェクトRubyとの関わり

それは札幌Ruby会議2012に「クリアなコードの作り方」という話をしに行ったときのことです。会場に向かう途中でパーフェクトRubyの著者の1人の@ryopekoさんとばったり会いました。そのとき、「Rubyの本を書いているんですよー。YARDのことも書いているんですけど、バグを見つけちゃったんですよねぇ。直し方はわかったんですけど、テストが書けなくて…どうしたらいいですかねぇ。」みたいな話を聞きました。それに対してなんと言ったのか具体的には覚えていませんが、「それでもPull Requestすればいいと思うよ!」みたいなことを言った気がします。

その後、@ryopekoさんはYARDにPull Requestを送り*1、YARDの問題が1つ直りました。

さらにその後、同じくパーフェクトRubyの著者の1人の@takkanmさんから、「自分が書いたところとかYARDのところとかいくつかの章だけでもレビューしてくれないか」という打診があったのでレビューアーとして参加しました。

これが、パーフェクトRubyとの関わりです。パーフェクトRubyが出版されたときは紹介記事を書きました。

Groongaイベント

パーフェクトRubyが出版されたあと、レビューアーに誘ってもらえなかったかくたにさんから「パーフェクトRubyのちょっとした打ち上げをやるのでいかがですか」というお誘いをもらいました。もちろん、喜んで参加しました。

その会で、「毎年いい肉の日にやっているGroongaイベントの場所をどうするか悩んでいるんですよねー」と漏らしたところ、@ryopekoさんと@sunaotさんのDeNAコンビが「うちでやりなよ!」と言ってくれました。そのおかげで、2013年のGroongaイベントを成功させることができました*2

まとめ

パーフェクトRubyはRubyの最新情報を網羅的に提供しているだけでなく、YARDもよくして、Groongaイベントの開催も支援して、すばらしいですね!

*1 コミットメッセージでtypoしているのがかわいらしいですね。

*2 DeNAさんのイベント支援力、ものすごいですよ!これは何度でも強調するべきことです!ものすごいです!

タグ: Ruby
2013-12-10

GObject Introspection対応ライブラリーの作り方

GNOME Advent Calendar 2013 16日目の記事です。

スクリプト言語の拡張機能をほぼ全自動で作ることができるGObject Introspectionに対応したライブラリーの作り方を紹介します。ライブラリーはCで実装します。

GObject Introspectionに対応するとうれしいこと

最初に、GObject Introspectionに対応するとうれしいことを説明します。

Cで書かれたライブラリーがGObject Introspectionに対応していると、各種スクリプト言語の拡張機能を1つずつ作る必要がありません。実際にどのようになるかみてみましょう。

この記事では次のAPIを提供するCのライブラリー「Sample」を作ります。このライブラリーはGTK-Docの使い方を説明したときに作ったものです。詳細はリンク先を参照してください。

1
2
3
4
5
6
7
struct _SampleGreeter
{
    GObject parent_instance;
};

SampleGreeter *sample_greeter_new      (void);
const gchar   *sample_greeter_greet    (SampleGreeter *greeter);

GObject Introspectionに対応すると、次のPythonスクリプトでこのAPIを使うことができます。

1
2
3
4
from gi.repository import Sample

greeter = Sample.Greeter()
print(greeter.greet()) # -> Hello!

Rubyスクリプトから使う場合はこうなります。

1
2
3
4
5
6
7
8
9
require "gobject-introspection"

module Sample
  loader = GObjectIntrospection::Loader.new(self)
  loader.load("Sample")
end

greeter = Sample::Greeter.new
puts(greeter.greet) # -> Hello!

どちらの場合も、「Greeterクラスを定義、Greeterクラスにはgreetメソッドを定義」ということを指定していません。「Sampleライブラリーを使う」と指定しているだけです。

SampleライブラリーのAPIは2つの関数しか提供していませんが、通常、ライブラリーのAPIはもっと多くの関数を提供しています。ライブラリーがGObject Introspectionに対応していると、それらの関数をどのように使うかを1つずつ定義しなくてもスクリプトから使えます。便利ですね。

GObject Introspection対応の仕方

それでは、GObject Introspectionに対応する方法を説明します。ビルドシステムにはAutotoolsを使用していることを前提としています。

GObject Introspectionに対応するためには次の2つのファイルを編集します。

  • configure.ac
  • 共有ライブラリーを生成するディレクトリーのMakefile.am

configure.acの変更点は1行です。

1
2
3
4
5
6
7
8
9
10
11
12
diff --git a/configure.ac b/configure.ac
index a75fcbb..d7cb118 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,6 +15,7 @@ LT_INIT

 AM_PATH_GLIB_2_0([2.32.4], [], [], [gobject])

+GOBJECT_INTROSPECTION_REQUIRE([1.32.1])
 GTK_DOC_CHECK([1.18-2])

 AC_CONFIG_FILES([

GOBJECT_INTROSPECTION_REQUIRE()を追加しているだけです。引数で指定している1.32.1は「少なくとも1.32.1以降のGObject Introspectionが必須」という意味です。最低でもこの環境はサポートしたいと考えている環境に合わせればよいです。なお、1.32.1はDebian wheezyのgobject-introspectionのバージョンです。つまり、この指定はDebian wheezyは最低でもサポートしたいという意味になります。

もし、AM_INIT_AUTOMAKE()foreignを指定していない場合は-Wno-portabilityを指定してください。

diff --git a/configure.ac b/configure.ac
index a75fcbb..8214d6c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR([sample/greeter.h])
 AC_CONFIG_HEADERS([config.h])

-AM_INIT_AUTOMAKE([1.13 foreign])
+AM_INIT_AUTOMAKE([1.13 -Wno-portability])
 AM_SILENT_RULES([yes])

 AC_PROG_CC

-Wno-portabilityはポータブルではないことに対する警告を抑制します。どうしてこのオプションが必要かというと、GObject Introspectionが提供するMakefile(後述)がGNU make独自の機能を使っているからです。

共有ライブラリーを生成するディレクトリーのMakefile.amの変更点はそこそこあります。

まず、該当するMakefile.amを確認しましょう。今回は次のようなディレクトリー構成になります。

.
|-- Makefile.am
|-- autogen.sh
|-- configure.ac
|-- doc
|   |...
|   `-- ...
`-- sample
    |-- Makefile.am          変更!
    |-- Sample-1.0.gir       GOject Introspectionが生成!
    |-- Sample-1.0.typelib   GOject Introspectionが生成!
    |-- libsample.la         ビルドして生成!
    |-- greeter.c
    `-- greeter.h

共有ライブラリーlibsample.soの元になるlibsample.laをsample/以下に生成するので、該当するMakefile.amはsample/Makefile.amになります。sample/Makefile.amを編集して次のファイルを生成するようにします。

  • sample/Sample-1.0.gir
  • sample/Sample-1.0.typelib

この2つのうち、スクリプトから読み込んでいるのが.typelibの方です。.typelibは.girから生成します。.girはライブラリーから生成します。

Makefile.amはこのようになります。コメントをつけているところがGObject Introspection固有の記述です。GObject Introspectionが提供するMakefileがルールを提供するので、Makefile.amではマクロを定義するだけです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# 自動生成する.girと.typelibをmake cleanで削除するため。
CLEANFILES =

AM_CPPFLAGS =                                        \
         -I$(top_builddir)                        \
         -I$(top_srcdir)

AM_CFLAGS =                                        \
        $(GLIB_CFLAGS)

lib_LTLIBRARIES =                                \
        libsample.la

libsample_la_LIBADD =                                \
        $(GLIB_LIBS)

libsample_la_SOURCES =                                \
        greeter.c                                \
        greeter.h

# GObject Introspectionが提供するMakefileを取り込む。
# マクロ(変数みたいなもの)を定義しておくと
# それを使って.girと.typelibを生成するルールが
# 定義されている。
# (GNU make依存の書き方をふんだんに使っている。)
-include $(INTROSPECTION_MAKEFILE)

# 生成する.girのリスト。
# 後の方でこのマクロに.girを追加していく。
INTROSPECTION_GIRS =
# .girを生成するg-ir-scannerに渡すコマンドライン引数。
# 同じMakefile.amで複数の.girを作成する場合は
# ここで指定した引数がすべての.gir生成で使われる。
INTROSPECTION_SCANNER_ARGS =
# .typelibを生成するg-ir-compilerに渡すコマンドライン引数。
# 同じMakefile.amで複数の.typelibを作成する場合は
# ここで指定した引数がすべての.typelib生成で使われる。
INTROSPECTION_COMPILER_ARGS =

# GObject Introspectionが見つかったときだけ実行されるブロック。
if HAVE_INTROSPECTION
# Sample-1.0.girの依存関係を指定。
Sample-1.0.gir: libsample.la
# 以降、Sample-1.0.girの「-」と「.」を「_」に変換した
# 「Sample_1_0_gir」をプレフィックスとしてパラメーターを指定する。

# Sample-1.0.girが依存するpkg-configのパッケージ名を指定。
# gobject-2.0は指定しなくてもよい。
# 省略可。
Sample_1_0_gir_PACKAGES =
# Sample-1.0.girが提供するpkg-configのパッケージ名を指定。
# 省略可。
Sample_1_0_gir_EXPORT_PACKAGES = sample
# Sample-1.0.girが依存するGObject Introspectionのパッケージ名を指定。
# GObject-2.0でも指定する。
# 省略可。
Sample_1_0_gir_INCLUDES = GObject-2.0
# ライブラリー(libsample.so)を使ったコードをビルドするために必要な
# フラグを指定。このライブラリーは依存ライブラリーがないので必要ないが
# 他のライブラリーに依存している場合は次のように指定すればだいたい大丈夫。
#   Sample_1_0_gir_CFLAGS = $(AM_CPPFLAGS) $(AM_CFLAGS)
# 省略可。
Sample_1_0_gir_CFLAGS =
# .girが対象とするライブラリーを指定。
# 必須。
# (「_LIBS」の代わりに「_PROGRAM」を指定することが可。)
Sample_1_0_gir_LIBS = libsample.la
# Sample-1.0.girに依存するファイルを指定。
# 必須。
Sample_1_0_gir_FILES = $(libsample_la_SOURCES)
# Sample-1.0.girを作るときにg-ir-scannerに渡すコマンドラインを指定。
# 省略可だが、--identifier-prefixと--symbol-prefixは
# 明示的に指定しておいたほうがよい。省略すると自動で推測するが、
# 推測が外れるとどのAPIも.girに含まれなくなる。
Sample_1_0_gir_SCANNERFLAGS =                        \
        --identifier-prefix=Sample                \
        --symbol-prefix=sample
# Sample-1.0.girを生成する.girのリストに追加。
INTROSPECTION_GIRS += Sample-1.0.gir

# .girをインストールするディレクトリーを指定。
# ここは変更する必要はない。
girdir = $(datadir)/gir-1.0
# .girをインストールするという指定。
# ここは変更する必要はない。
gir_DATA = $(INTROSPECTION_GIRS)

# .typelibをインストールするディレクトリーを指定。
# ここは変更する必要はない。
typelibdir = $(libdir)/girepository-1.0
# .typelibをインストールするという指定。GNU make依存の書き方。
# ここは変更する必要はない。
typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)

# make cleanで.girと.typelibを削除。
CLEANFILES +=                                        \
        $(gir_DATA)                                \
        $(typelib_DATA)
endif

これでGObject Introspection対応になりました。使ってみましょう。

ここで作ったライブラリーはGitHubで公開しているのでそれを使います。

% git clone https://github.com/kou/gobject-introspection-sample.git

ビルドしてインストールします。

% cd gobject-introspection-sample
% ./autogen.sh
% ./configure --prefix=/tmp/local
% make
% make install

Pythonから使ってみます。スクリプトはこれです。

1
2
3
4
from gi.repository import Sample

greeter = Sample.Greeter()
print(greeter.greet())

実行するときはGI_TYPELIB_PATHで/tmp/local/lib/girepository-1.0を指定して、インストールしたばかりのSample-1.0.typelibを見つけられるようにします。LD_LIBRARY_PATHを指定しているのはlibsample.soを見つけるためです。

% GI_TYPELIB_PATH=/tmp/local/lib/girepository-1.0:/usr/lib/girepository-1.0 \
    LD_LIBRARY_PATH=/tmp/local/lib \
    python /tmp/sample.py
Hello!

呼び出せましたね。

まとめ

Cで実装したライブラリーをGObject Introspectionに対応させるとスクリプトから簡単に使えることを説明し、対応方法を説明しました。ここで実装したライブラリーはGitHubで公開しています。ライセンスはCC0 (Public Domain)です。

ここでは、複雑な引数(たとえば出力引数)の場合はどのようにすればよいかについては省略しました。複雑な引数のことについて説明するときにGTK-Docの使い方の説明が活きてくるはずでした。また別の機会ですね。

2013-12-16

Mac OS X版GTK+の日本語入力対応 その後

これまでの記事で、数回に渡ってMac OS X版GTK+の日本語入力対応状況について紹介してきました。

今回はMac OS X版GTK+の日本語入力関連最後の記事として、その後の状況について紹介します。

GTK+本体での対応状況

GTK+2系、GTK+3系いずれについても、山本博之氏およびek.kato氏によるimquartzが取り込まれており、最新版では追加パッチ無しで日本語が入力できるようになっています。

GTK+2系

GTK+2系はGTK+ 2.24.19でek.kato氏によるimquartzが投入されました。GTK+ 2.24は安定系のブランチですので本来はこのような大きな変更が入ることは無いのですが、GTK+2系は既に新規の開発が終了しているため、いきなりこのブランチへの投入となったようです。

このためGTK+ 2.24.19 〜 GTK+ 2.24.20ではIM絡みの問題が噴出していましたが、ek.kato氏をはじめとする方々のご尽力により、gtk+-2.24.21では安定して使えるようになっています。クリアコードでもInkscapeで文字入力ができなくなる問題について調査を行い、修正パッチが取り込まれました。

GTK+3系

GTK+3系については、9月にリリースされたGTK+ 3.10.0でimquartzが投入されました。GTK+3系は現在のメインの系統ですので、いきなり安定板にimquartzが投入されるようなことはなく、GTK+ 2.24やGTK+ 3.9(GTK+-3.10の開発バージョン)での安定化の成果が取り込まれた形でのリリースとなりました。このため、GTK+ 3.10以降ではGTK+ 2.24.21と同様に安定して日本語を入力することができます。

既知の不具合の対応状況

7月の記事で紹介した不具合のうち、主なものについてその後の状況を確認してみました。

英数キーやかなキーでのモード切り替え時の挙動不具合

パッチを投稿したものの開発者からのレスポンスが無く、前回の記事から進展は無いようです。アプリケーションによって問題が発生するものと発生しないものがありますが、発生した場合は、日本語キーボードを使う人にとって実用に耐えない問題であるため、引き続き取り込んでもらえるよう呼びかけていきます。アプリケーションによっては、独自に本パッチを当てて配布しているものもあるようです。

変換中のカーソルキーの動作不具合

ek.kato氏が対応して下さったので、最新版のGTK+では解決しています。

かなテーブルや文字ビューアでの入力不具合

これもek.kato氏が対応して下さったので、最新版のGTK+では解決しています。imquartzの設計ではキーイベント以外のイベントを受け取ることができないのが大きな問題でしたが、マウスでの確定時はダミーのキーイベントを送出する方法で解決したようです。

新たに見つかった不具合

GtkTreeViewでのクイックサーチ

GtkTreeViewでのクイックサーチが機能しないという問題が発生しています。

Windows版GTK+でも同様の問題はありますが、Mac版ではショートカットキーでもクイックサーチを開始することができないなど、より深刻な状況のようです。

アプリケーションでの対応状況

Xamarin Studio

Xamarin Studioの最新版である4.2.2を確認したところ、GTK+ 2.24.20をベースにいくつかのパッチを当てたバージョンが同梱されているようです。そのため追加パッチ無しで日本語入力できるようになっていますが、候補ウィンドウから候補を選んで確定しようとした場合に

  • マウスのダブルクリックでは候補文字列が更新されない
  • Enterキーでは候補文字列ではなく改行が挿入される

という問題があります。GTK+ 2.24.21ではこのような問題は無いため、GTK+の更新で修正できるものと思われます。確認の上、Xamarinに報告します。なお、英数キーやかなキーの問題については、上記のパッチが適用されているため、Xamarin Studioでは問題無く動作します。

GIMP

最新版であるGIMP 2.8.10 for OSXで日本語入力できるようになっています。ただし、肝心のText Toolで未確定文字列が表示されない問題があるようなので、今後原因を調査します。

GtkIMCocoaについて

GTK+本体のみで日本語入力が可能となったため、GtkIMCocoaについては開発を一旦停止しています。今後の修正については、なるべくGTK+本体に対して行っていく予定です。ただし新たなコンセプトでの開発が必要になった場合には、GtkIMCocoaでの作業を再開します。

まとめ

多くの方々のご尽力により、Mac OS X版GTK+でも追加パッチ無しで日本語を入力できるようになりました。クリアコードでは業務でもWindows版GTK+やDirectFB版GTK+を活用していますが、今後はMac版GTK+も同様に活用していくことができそうです。

ただし、まだ細かな問題は残されていますし、アプリケーションによっては未だ実用に耐えない物もありますので、今後も地道に改善していきたいと思います。

2013-12-26

«前月 最新記事 翌月»
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|