最近はnode.jsに興味を持ち出しています。
そうなると、やっぱり内部のアーキテクチャが気になってしまって、jsを弄るのと並行してlibuvを使ってCでコード書いたりしています。例えば、Apache2.4系のmpmはLoadableなので、libuvでmpm書いちゃったらApacheも高速だろうなーとかも考えてます。
しかし、Windowsはいっぱいあるんだけど、意外とLinuxにlibuvをインストールする記事やドキュメントが無くて、微妙にハマったのでlibuvをLinuxにインストールする方法をまとめておきます。Makefileやconfig-unix.mkをチラチラ見ながらなんとかしました。
Linuxにlibuvをインストール
OSはCentOS5系でわけあって32bitのPAEカーネルの環境にインストールしました。
[program lang=’bash’ escaped=’true’]
uname -a Linux example.com 2.6.18-308.11.1.el5PAE #1 SMP Tue Jul 10 09:29:33 EDT 2012 i686 i686 i386 GNU/Linux
[/program]
まずは、libuvをGitHubからとってきます。
[program lang=’bash’ escaped=’true’]
git clone git://github.com/joyent/libuv.git
[/program]
そして、libuvディレクトリに移動しmakeします。
すると、上記の32bit環境では下記のようなエラーがでました。64bit環境ではふつうに通ります。
[program lang=’c’ escaped=’true’]
cc --std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter -D_GNU_SOURCE -Iinclude -Iinclude/uv-private -Isrc -Isrc/unix/ev -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -g -c src/unix/async.c -o src/unix/async.o In file included from src/unix/internal.h:40, from src/unix/async.c:22: src/unix/linux/syscalls.h:74: error: expected specifier-qualifier-list before ‘__u64’ make: *** [src/unix/async.o] Error 1
[/program]
おや、__u64がなんか怪しいんでは?と言われている様子。ということで、/usr/include/linux/types.hをみてみると、以下のようになっていました。
[program lang=’c’ escaped=’true’]
95 #if defined(__GNUC__) && !defined(__STRICT_ANSI__) 96 typedef __u64 uint64_t; 97 typedef __u64 u_int64_t; 98 typedef __s64 int64_t; 99 #endif
[/program]
ここで安直に、-U__STRIC_ANSI__したらいいんじゃないの?と思い、MakefileのCPPFLAGSに追加するも、以下のようにうまくいきませんでした。
[program lang=’c’ escaped=’true’]
src/unix/signal.c:119: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘static’ src/unix/signal.c: In function ‘uv__signal_handler’: src/unix/signal.c:144: warning: implicit declaration of function ‘uv__signal_first_handle’ src/unix/signal.c:144: warning: assignment makes pointer from integer without a cast src/unix/signal.c: In function ‘uv_signal_start’: src/unix/signal.c:310: warning: comparison between pointer and integer src/unix/signal.c: In function ‘uv__signal_stop’: src/unix/signal.c:446: warning: comparison between pointer and integer make: *** [src/unix/signal.o] Error 1
[/program]
うーん、これはなんかいつもの良くない方向にハマっていってるなぁと思ったので、とりあえず__u64をunsigned long longに変える以下のようなpatchを作って当てました。これだとansi、c89の環境なのでもちろんWarningが発生しますが一応コンパイルは通ります。もっと良い案があれば教えて欲しいです。というか__u64と書かれていたのは一か所だけでした。
[program lang=’c’ escaped=’true’]
--- src/unix/linux/syscalls.h.orig 2012-11-10 00:24:57.000000000 +0900 +++ src/unix/linux/syscalls.h 2012-11-10 00:44:41.000000000 +0900 @@ -71,7 +71,7 @@ struct uv__epoll_event { __u32 events; - __u64 data; + unsigned long long data; } __attribute__((packed)); struct uv__inotify_event {
[/program]
そして、再度makeするとうまく通って、libuv.aがカレントディレクトリに生成されました。そして、ヘッダファイルとライブラリを以下のようにコピーしました。
[program lang=’bash’ escaped=’true’]
sudo cp -r include/{uv.h,uv-private} /usr/include/. sudo cp livuv.a /usr/lib/.
[/program]
そこで、以下のようなlibuvのサンプルコードを書いて、
[program lang=’c’ escaped=’true’]
#include <stdio.h> #include <uv.h> int main() { uv_loop_t *loop = uv_loop_new(); printf("Now quitting.¥n"); uv_run(loop); return 0; }
[/program]
以下のようにコンパイルしました。
[program lang=’c’ escaped=’true’]
gcc sample.c -O3 -g -fPIC -pthread -ldl -lrt -lm -luv
[/program]
そして、バイナリa.outを実行すると、
[program lang=’c’ escaped=’true’]
./a.out Now quitting.
[/program]
と、無事libuvを使ったコードを実行する事ができました。
めでたしめでたし。
というわけで、今後はlibuvを使って非同期通信を色々やってみたいと思います。