ap_getword()の動作

Apachehttpd.hに定義があるap_getword()は、第二引数で渡したポインタの位置から読んでいって最初に第三引数が発見されるまでの文字列のポインタを返す。

const char *uri = "/foo/bar/baz.jpg";
const char *dir;
uri++;                                // uri = foo/bar/baz.jpg
dir = ap_getword(r->pool, &uri, '/'); // uri = bar/baz.jpg, dir = foo
uri--;                                // uri = /bar/baz.jpg

XSをモジュールなしでロードするには?

よくわかってないんだけど、とりあえず動いたので忘れないようにメモ。
(ただしこれはOSX上でのことなので他のOSだとところどこパスなどで違う部分があると思う)

1. hoge.xsを作る

今回は単純にパッケージ名をPACKAGENAMEで、メソッド名methodnameというのが1つあるだけのhoge.xsだとする。

2. xsubppというコマンドでhoge.xsをhoge.cに変換する

typemapが必要なのでExtUtilsのパッケージの中のを使う。

% xsubpp -typemap /System/Library/Perl/5.8.8/ExtUtils/typemap hoge.xs > hoge.c

3. hoge.cをコンパイルする前にppport.hというのを生成しておく

% perl -MDevel::PPPort -e 'Devel::PPPort::WriteFile()'

4. hoge.cをコンパイルする

コンパイルにはEXTERN.hとかが必要なので、下記のような適当な場所をコンパイルオプションに追加する。これでhoge.oができる。

% gcc -I/System/Library/Perl/5.8.8/darwin-thread-multi-2level/CORE -c hoge.c

5. hoge.oをhoge.bundleにする

gcc -bundle -undefined dynamic_lookup -L/usr/local/lib -bundle hoge.o -o hoge.bundle

6. Perlからhoge.bundleをロードする

以下のようにDynaLoaderの関数を使ってxsで書いたパッケージのメソッドを呼び出すことができる。

#!/usr/local/bin/perl

use strict;
use warnings;
use DynaLoader;

my $libref = DynaLoader::dl_load_file( '/path/to/hoge.bundle' );
my $symref = DynaLoader::dl_find_symbol($libref, 'XS_PACKAGENAME_methodname');
DynaLoader::dl_install_xsub('methodname', $symref);
methodname();

まぁ、こんな感じで動くのは確認したんだけど、そもそものxsubppでなにやってるのかとかDynaLoaderでこうやるとメソッドが呼べるとかの原理は詳しく調べてないので、その辺はあとで調べる。

とりあえず今日はここまで。

ソフトウェアのライセンスは難しくてわからないなー

LGPLライセンスのCのライブラリ(libなんちゃら)を自分のCPANモジュール(Perl and GPLライセンス)に同梱したいんだけど問題があるのかないのかわからん。

Cのライブラリの作者にメールとかするのはいいとして、ライセンス的に問題ないかがよくわかりません。


今のところ大きく分けて2つ疑問があります。

1つは

http://ja.wikipedia.org/wiki/GNU_Lesser_General_Public_License

↑この辺を見る限り、CPANモジュールならソースはすべて公開になっているわけだから、LGPLを同梱するのは問題なさそうな気もするけどどうなのか?


もう1つは、LGPLだとそのライブラリを使用するソフトウェアをGPLに準拠させなきゃいけないんだけど、今回のケースの場合、そのライブラリを使用するCPANモジュールがPerl and GPLっていうライセンスになっててこれでGPLに準拠していると言えるのか?(Perlライセンスにもなってるのが気になる)

この辺詳しい人いませんか!

memcachedのコードリーディング

Cの勉強がてmemcachedのコードリーディングでも始めてみようかと思ったり。

続くかわからんけど、どこかでコードリーディング記事を書こうと思った。

思っただけで終らないようにしないとな…。

スレーブのレプリケーションが遅れてたら

DBがマスタ-スレーブ構成になってる場合で、定期的(例えば1日1回とか)にテーブルを作成するようなアプリがあったとします。

それで、普通にWRITEはマスタでREADはスレーブとかやってると、スレーブへのレプリケーションが遅れたりしてスレーブがSELECTしたときにスレーブにテーブルがないという可能性が0ではないと思うのですが、SELECTするプログラム部分をevalしてテーブルがないとエラったらマスタにつなぐのが普通かなぁと思うんだけど、他にいい方法があるんでしょうかねぇ。

ちなみに言語はPerlです。

↓こんな感じにする以外でいい方法あるのかな

my $dbh = DBI->connect( @slave_datasource );
my $sth = $dbh->prepare("SELECT * FROM foo");
eval { $sth->execute() };
if ( $@ ) {
    my $dbh = DBI->connect( @master_datasource );
    my $sth = $dbh->prepare("SELECT * FROM foo");
    $sth->execute();
}
# do something...

r->headers_inなどのapr_table_tのデータの扱い方

r->headers_in は apr_table_t 型で、apr_table_elts() という関数を使うと apr_array_header_t 型の値が取得できる。
これが先頭のデータになる。

const apr_array_header_t *arr = apr_table_elts(r->headers_in);

で、apr_array_header_t は下記のような構造体になってる。

struct apr_array_header_t {
    apr_pool_t *pool;
    int elt_size;
    int nelts;
    int nalloc;
    char *elts;
};

この elts は char * なんだけど、apr_table_entry_t になっているっぽい。
なので、

apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts;

こうやって apr_table_entry_t * として受けとると最終的には、

for (i = 0; i < arr->nelts; i++) {
    printf("%s: %s", elts[i].key, elts[i].val);
}       

とやるとkeyとvalが出力できる。
ちなみに、arr->elts はもともと char * なので (apr_table_entry_t *) でキャストしてやらないとwarningが出ます。