Linuxにlibuvをインストールした時にハマった所

最近は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を使って非同期通信を色々やってみたいと思います。