Entry

Expat を使ってみよう(その1)

2005年04月06日

久方ぶりの更新になってしまいました。この頃何かと忙しいもので,なかなか長めの文章が書けないんです。どうもごめんなさい。

さて,ここから本題。Expat というのは,C で実装されたストリーム型の XML parser です。FreeBSD で ports を扱っている向きには,「なんでか知らないけれど入ってしまう port」の1つとしてお馴染みなんじゃないでしょうか。

XML parser 一般で有名なモノというと,Apache XML project の Xerces あたりになるんでしょうけど,XML を使いたい場面というのは,C++ や Java を持ち出さなきゃいけないほど大規模な開発だけじゃないんですよね。例えば,この頃は設定ファイルを XML で書くアプリケーションが増えてきたけれど,こういったモノは規模の大小にかかわらず XML を使えると便利だったりするんです。

まぁ……言いわけのように「C から XML を扱いたい」と言うのは,あたしが C++ や Java に暗いからなんですけどね(←!)。とりあえずぼちぼち使ってみることにします。

さて,Expat の使い方を調べてみたところ,日本語のサイトでは詳しいサイトがあまりなかったりします。そこで,今回はライブラリの使い方(プログラムの書き方)を見る前に,「実際にどうやってビルドして使うのか」というところをみていこうと思います。

今回使う Expat のバージョンは 1.95.8 にしました。また,ここでは,普通にインストールした時の場所に置いてあることにします。つまり,ライブラリ(libexpat.a)が /usr/local/lib に,ヘッダファイル(expat.h)が /usr/local/include にそれぞれ入っているということですね。

インストール

とりあえず,何はともあれライブラリをインストールします。FreeBSD の場合,何かの Ports を入れていたら大抵入っているので,改めてインストールすることもなかったりするわけですが……。一応,以下のようにして

% pkg_info | grep expat
expat-1.95.8        XML 1.0 parser written in C

みたいになってれば Expat が入っています。

入っていない場合はインストールしましょう。Ports(textproc/expat)から導入する場合は,例によって make 一発でお願いします。ソースからインストールしたいという向きは,SourceForge からソースをもらってきて(参照:「SourceForge.net: Expat XML Parser」),以下のようにします。まぁ……いつもの方法なわけですが……。

% ls
expat-1.95.8.tar.gz
% tar xvzf expat-1.95.8.tar.gz
% cd expat-1.95.8
% ./configure
% make
# make install

これで準備完了です。

非常に簡単なサンプル

インストールが終わったら,早速使ってみることにしましょう。簡単なサンプルを用意したのでこれをコンパイルしてみます。今回は,「なんとかビルドできるようになること」が目標なので,中身については細かく話せません……あしからず。

まずは,Expat を使った C のソースをば……。XML の要素(element)を上から順番に表示するだけの単純なプログラムです。長く見えるのはエラーを拾っているからで,中身は薄っぺらです。ここでは xptest.c として保存したことにします。

#include <stdio.h>
#include <stdlib.h>

#include <expat.h>

#define BUFSIZE 1024  

void
element_start(void *userData, const XML_Char *name, const XML_Char *atts[])
{
    printf("[ELEMENT] %s Start!\n", name);
}

void
element_end(void *userData, const XML_Char *name)
{
    printf("[ELEMENT] %s End!\n", name);
}

int
main (int argc, char *argv[])
{
    char buf[BUFSIZE];
    int eofflag;
    size_t len;
    XML_Parser parser;
    /* create XML parser */
    if ((parser = XML_ParserCreate(NULL)) == NULL) {
        fprintf(stderr, "parser creation error\n");
        exit(-1);
    }
    XML_SetElementHandler(parser, element_start, element_end);
    /* read and parse */
    do {
        len = fread(buf, sizeof(char), BUFSIZE, stdin);
        if (ferror(stdin)) {
            fprintf(stderr, "file error\n");
            exit(-1);
        }
        eofflag = feof(stdin);
        /* XML parse */
        if ((XML_Parse(parser, buf, (int)len, eofflag)) == 0) {
            fprintf(stderr, "parser error\n");
            exit(-1);            
        }
    } while (!eofflag);

    fprintf(stderr, "done.\n");

    return 0;
}

次に,XML のソースファイルです。用意できるようなら,お手元の適当な XML ファイルを使ってもらって構いません。ただ,Expat の内部文字コードは Unicode なので,単品では EUC-JP や Shift_JIS の XML を理解できません。ここでのプログラムも特別な日本語対策をしていないので,ASCII の単純なものを用意しましょう。ここでは,適当に作った XML を置いておきます(bsd.xml ということにします)。

<?xml version="1.0"?>
<bsd>
  <entry>
    <name>FreeBSD</name>
    <version>
        <current>6.x</current>
        <release>5.3</release>
    </version>
    <platform>
        <item>alpha</item>
        <item>amd64</item>
        <item>ia32</item>
        <item>ia64</item>
        <item>pc98</item>
        <item>sparc64</item>
    </platform>
  </entry>
</bsd>

コンパイルとリンク

無事保存できたら,コンパイルしてみましょう。普段からライブラリを使っている方には何でもないことなんですけれど,標準ライブラリ以外のライブラリを使うときって,案外難儀するんですよね……。ここではちょっと詳しく説明しておきます。

gcc で C のソースをコンパイルするときには,3段階の手順を踏むことになっています。つまり,

  1. C のソースコード(*.c)からアセンブリファイル(*.s)を作る
  2. アセンブリファイル(*.s)からオブジェクトファイル(*.o)を作る
  3. オブジェクトファイル(*.o)をまとめて実行ファイルを作る

といった段取りです。もっとも,コマンドの上では,アセンブリファイルの出力をすっ飛ばしてオブジェクファイルを出力するので,作業の手間は通常2段階です。アセンブリファイルは gcc の中の人が,内部でせっせこ作っているというわけ。ちなみに,アセンブリを出力したいときは,`-S' オプションを使います。どうでもいいことですが……。

コンパイルしてみる

そんなわけで,今回のソースファイルを見てみましょう。まずは,C のソースコードからオブジェクトファイルを作ります(手順1と2)。

オブジェクトファイルというのは,ライブラリの本体を含まない断片的な機械語のことです。お馴染みの stdio.h から printf() なんかを使うときも,この段階ではまだ printf() の本体が組み込まれていません。オブジェクトファイルにあるのは,「ここに printf() が組み込まれる予定」という印だけです。とはいえ,本体が組み込まれないとしても,印をつける必要はあります。印を付けるのに必要なのが,ライブラリのヘッダファイル(*.h)というわけです(注:ヘッダファイルの役割はそれだけじゃないけれど,ここではそういうことにしてください)。

今回のソースは,標準ライブラリの他に,expat.h を include しているので,コンパイルするには,コンパイラ(gcc)がこのヘッダファイルを探せなくちゃいけません。つまり,ヘッダファイルがあるディレクトリに path が通っていなくちゃいけないんです。

一方,Expat のヘッダファイルはどこにあるかというと,先ほど /usr/local/include にインストールしていたのでした。ただ,あいにく FreeBSD の場合,デフォルトでは /usr/local/include に include path が通っていません。`-I' オプションでコンパイラにヘッダファイルの在処を教えてあげましょう。つまり,C のソースファイルからオブジェクトファイルを作るには `-c' オプションを使って以下のようにします。

% cc -I/usr/local/include -Wall -c xptest.c

カレントディレクトリに xptest.o というオブジェクトファイルができるはずです。ちなみに,`-Wall' は「警告を全部表示しなさい」という意味です。

リンクしてみる

次に,できたオブジェクトファイルとライブラリをリンクします(手順3)。リンクというのは,断片のオブジェクトファイルどうしをくっつけて,1つの実行ファイルにすることです。リンクの仕方はいろいろあるけれど,とりあえずここでは libexpat.a と静的にリンクすることにします。ちなみに,ライブラリファイルは(lib*.a),あらかじめコンパイルしてまとめてあるので,上のようにコンパイルする必要はありません。

リンクするには,`-l' オプションでリンクしたいライブラリファイルを指定します。指定の仕方がちょっと特殊で,ライブラリファイルの名前から `lib' と `.a' を除いた部分を指定します。例えば,libexpat.a とリンクしたい場合は,`-lexpat' と指定するわけですね。追記:lib*.a と静的にリンクする場合は,"-static"オプションも指定しておきます(すっぽ抜けててごめんなさい)。

一方,include path の場合と同じく,ライブラリも gcc が探せるように path を通しておく必要があります。例によって FreeBSD は,デフォルトで /usr/local/lib に path が通っていないので,`-L' オプションでライブラリのある場所を教えてあげましょう。

結局,まとめてコマンドにすると,次のようになります。

% cc -L/usr/local/lib -Wall -o xptest xptest.o -lexpat -static

`-o' オプションは,出力する実行ファイルの名前です。指定しないと `a.out' というファイルができるのは,お馴染みですね。

まとめて実行する

ここでは,ソースコードからオブジェクトファイルを作ってリンクしました。けれど,実は,今回のようにソースファイルが1つしかない場合は,まとめてリンクまで実行ことができます(ご存知の人が大多数でしょうが……)。やり方は,オプションをまとめて指定するだけ……。

% cc -I/usr/local/include -L/usr/local/lib -Wall -o xptest xptest.c -lexpat

オブジェクトファイルは作らないので,`-c' オプションは要りません。

実行してみる

xptest もコンパイルできたことだし,実行することにしてみましょう。このプログラムは,標準入力から XML ファイルを読み込んで,要素(element)の名前を出力するというモノです。

次のように使います。

% ./xptest < bsd.xml
[ELEMENT] bsd Start!
[ELEMENT] entry Start!
[ELEMENT] name Start!
[ELEMENT] name End!
[ELEMENT] version Start!
[ELEMENT] current Start!
[ELEMENT] current End!
[ELEMENT] release Start!
[ELEMENT] release End!
[ELEMENT] version End!
[ELEMENT] platform Start!
[ELEMENT] item Start!
[ELEMENT] item End!
[ELEMENT] item Start!
[ELEMENT] item End!
[ELEMENT] item Start!
[ELEMENT] item End!
[ELEMENT] item Start!
[ELEMENT] item End!
[ELEMENT] item Start!
[ELEMENT] item End!
[ELEMENT] item Start!
[ELEMENT] item End!
[ELEMENT] platform End!
[ELEMENT] entry End!
[ELEMENT] bsd End!
done.

無事結果が出力されたら見事成功。ええ,今回はこれだけです。

まとめ

なんだか,だらだらと長文になってしまいました……。今回は,Expat の説明というよりは,外部ライブラリの使い方が主だったので,致し方ありませんです。もっとも,これで Expat 以外の外部ライブラリも比較的楽に扱えるんじゃないでしょうか。Makefile も自分の頭で考えて作れるようになるはずです。きっと……。

次回は,Expat を使って簡単な設定ファイルを作ってみようと思います。思っているだけ……じゃなくて,作りますです。はい。

追記:次回に続く(qune: Expat を使ってみよう(その2)

Trackback
Trackback URL:
[2015年12月04日 06:09] yajimaandendo_yajima_install_on_cloud_3 from Confluence: APPLIINFRA
Subversionのインストール SQLiteのインストール $ sudo tar xzvf sq [more]
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN