〜2002年5月上旬〜
embeddedなrubyを作る際に、ruby-talk MLでも-DNT -DIMPORTのつけ忘れが目立つ。 ということは逆にしたほうが使い易いと言える。 NTはdefines.hで
#if defined _MSC_VER || defined __MINGW32__ || defined __BORLANDC__ #define NT 1 #endif
とし、 defaultはIMPORTにしてRuby DLLをcompileするときは-DEXPORTにするのはどうだろう? 現在win32/win32.hでは
#undef EXTERN #if defined(IMPORT) #define EXTERN extern __declspec(dllimport) #elif defined(EXPORT) #define EXTERN extern __declspec(dllexport) #endif
となっているが、実際EXPORTは使われていない。 def fileを作っているから必要ないというのもあるけど。 つまり
#undef EXTERN #if defined(RUBY_EXPORT) # define EXTERN extern __declspec(dllexport) #else # define EXTERN extern __declspec(dllimport) #endif
とするわけだ。 単にIMPORTとかEXPORTだとぶつかる可能性が高すぎるので名前を変えた。 で、これをどうやって定義するかがいまいち困るわけだが、 やはり別の変数が必要だな。Makefile.inで
CFLAGS = @CFLAGS@ @RUBY_EXPORT@
みたいな。
実際試してみるとmissing/flock.c, ext/socket/getaddrinfo.cで破綻してしまった。 でも単にdefines.hをincludeすればいいだけか。 どちらもconfig.hはincludeしてるからここでNTを定義したほうが簡単かもしれない。 ext/socket/getnameinfo.cもそうか。 うーむ。ext/Win32API/Win32API.cはruby.hを最初にincludeしないとだめだ。 ということは拡張ライブラリを書き換えてもらう必要が出てくるわけか。 これはちょっと受け入れられないかもしれないな。
更新。
192通。韓国からは45通。今月は200通を越えるのか?昨日だけで既に8通来てるし。
Redo(CTRL-R)です。
更新。
窓使いの憂鬱だと
window PuTTY /putty.*\.exe:/ : Global key C-Slash => C-S-HyphenMinus
という手はあります。 default.mayuのTeraTermProのとこに書いてある通りですが。
sys_nerrはAC_CHECK_DECLSで宣言が必要かどうかを調べるようになった。 でも$ac_includes_defaultには<errno.h>がない。 cygwinだと<errno.h>にsys_nerrの宣言があるのでちょっとまずい。 新しいldならauto-importがdefaultなので問題ない。 おそらく [ruby-talk:39482] は古いldを使ってるんじゃないかと思う。
ま、warningをなくす意味でも
AC_CHECK_DECLS([sys_nerr], [], [], [#include <errno.h>])
としてみた。が、これだと逆に$ac_includes_defaultがなくなるので最終的には
AC_CHECK_DECLS([sys_nerr], [], [], [$ac_includes_default #include <errno.h>])
とした。
あ、たぶんwin32/config.h.inにも
#define HAVE_DECL_SYS_NERR 1
が必要だな。追加しとこ。
/proc/registryとかが使えるようになるらしい。 fhandler_proc.ccを見ると今はまだ/proc/versionと/proc/uptimeだけのようだ。
更新。CHANGESを見ると
our i386 memchr,memcmp were broken for the count=0 case
ということで、 例の件 も直ってるようだ。 てゆかmemcmpもまずかったのか。
というわけで対応してみる。configure時のオプションは
--with-gcc='ccache diet gcc -nostdinc'
を追加。
io.c: In function `pipe_open': io.c:1859: `NOFILE' undeclared (first use in this function) io.c:1859: (Each undeclared identifier is reported only once io.c:1859: for each function it appears in.)
NOFILEがないらしい。
/* EMX has sys/param.h, but.. */ #if defined(HAVE_SYS_PARAM_H) && !(defined(__EMX__) || defined(__HIUX_MPP__)) # include <sys/param.h> #else # define NOFILE 64 #endif
となっているが、<sys/param.h>にない場合が多いのだろう。 HIUXも最近新たに加わったようだ。BeOSとまとめて
#if defined(HAVE_SYS_PARAM_H) # include <sys/param.h> #endif #if !defined NOFILE # if defined OPEN_MAX # define NOFILE OPEN_MAX # else # define NOFILE 64 # endif #endif
ぐらいがいいのかもしれない。
signal.c:291: redefinition of `sighandler_t' /opt/diet/include/signal.h:87: `sighandler_t' previously declared here
これは困るね。configure.inに
AC_CHECK_TYPES([sighandler_t], [], [], [#include <signal.h>])
を入れて、signal.cのほうは
#if !defined HAVE_SIGHANDLER_T typedef RETSIGTYPE (*sighandler_t)_((int)); #endif
としてみよう。
math.o(.text+0x4cc): undefined reference to `frexp' numeric.o(.text+0x90d): undefined reference to `modf' sprintf.o(.text+0xbb1): undefined reference to `frexp' time.o(.text+0x385): undefined reference to `modf'
うーむ。これは結構面倒な気がする。
Operaでfull screenモードにすると 見易いらしい。 とりあえずOpera 5 for Linuxをダウンロードしてみる。 なぜかSlide 30以降へ進めなくなる。しょうがないのでOpera 6のbeta版をダウンロード。 こっちは4.3MBもある。もちろんQTなど入れてないのでstatic版だ。 おお、いい感じ。最初からこっちダウンロードしとけばよかった。 5よりも圧倒的に速いし。
the fastest browser on earth!
と自信満々なメッセージを出すだけのことはある。
最近ダウンロードしようとするとミラーへ飛ばされて、ちと不便。
単にbin/がないだけのようです。
% mkdir bin
でsetupもok。 あとsrc/をlib/にrenameしないとインストールされないとか、 そうしちゃうとpre-setup.rbがまずそうとか、 まだ不完全のよう。
glibcやnewlibcやuClibcやDJGPPを見るとどれもCopyrightは同じで Sun Microsystemsらしい。というかどうもNetBSD経由らしい。 rcsidに$NetBSDの文字が。
更新。
更新。
% touch a b c % ls *(L0) a b c
ほんとzshって何でもありだよね。 誰かが書いてたけど、Rubyで使えるzsh globライブラリは欲しい気がする。
TV Bros.を見るとテレビ埼玉の18:00から「血」一文字だけの番組がある。 かなり不気味だ。見てみると「赤き血のイレブン」だった。懐しすぎ。
更新。
更新。
更新。
manを見ると
#include <math.h> double modf(double x, double *iptr); modf() 関数は、引数 x を整数部分と小数部分に分割する。この と き、ふたつの値はともに x と同じ符号を持っている。整数部 分は iptr に保存される。
ということらしい。 一見
double modf(double x, double *iptr) { *iptr = (int)x; return x - *iptr; }
でよさそうな気がするが、 考えてみるとdoubleってのはintなんかよりかなり範囲が広いのでこれじゃだめなのだ。 たとえばtime.cでは
double f, d; d = modf(RFLOAT(time)->value, &f); t.tv_sec = (time_t)f; if (f != t.tv_sec) { rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT(time)->value);
というようにそれを積極的に利用している。
ちょっと変形して
double modf(double x, double *iptr) { *iptr = x < 0.0 ? ceil(x) : floor(x); return x - *iptr; }
でどう?-100のように負で小数部がないときに-0.0にはならないけど、ま、いっか。
Cygwinのバイナリも用意されてるのか。
またman frexpを見ていろいろ考える。
#include <math.h> double frexp(double x, int *exp); 説明 frexp()関数は浮動小数点実数 x を正規化分数と exp に保存される指数に分解する。 返り値 frexp() 関数は正規化分数を返す。引数 x がゼロでないなら、 この正規化分数は x に2のべき乗を乗じた も の で あ り、 常 に1/2から1の範囲となる(ただし1自体は含まれない)。 x がゼロ の場合、正規化分数はゼロになり exp にはゼロが保存される。
要するにlog2()があれば簡単な話なんだが、 そんな関数はないので、log(x)をlog(2.0)で割ることで代用。 こんな感じか?
#if !defined M_LN2 #define M_LN2 0.69314718055994530942 #endif double frexp(double x, int *exp) { double sign = 1.0; if (x == 0.0) { *exp = 0; return 0.0; } else if (x < 0.0) { sign = -1.0; x = -x; } *exp = log(x) / M_LN2 + 1; return sign * x / (2 << (*exp - 1)); }
うーむ。shiftしちゃだめだ。overflowする。 2のべき乗だからpowかldexpを使えばいいのか。 pow.Sとldexp.Sを比較するとldexpのほうが圧倒的に速そうな気がする。 それと、xがちょうど2のべき乗のときに*expが1.0になってしまうのもまずい。 というわけで
double f; ... f = ldexp(1.0, *exp); if (x == f) { (*exp)++; f *= 2.0; } return sign * x / f;
でどうだろう?
明日にはminirubyができそうだ。
missing/{modf,frexp}.cを作って、 modfとfrexpをconfigure.inのAC_REPLACE_FUNCSに追加。 configureし直して、とりあえずmake minirubyを実行。 link時にsprintfを使うなとかstdioを使うと7KB余分に消費するぞとか例の警告が出るが、 これでminirubyはできた。
ここで一度testしてみよう。
% ln -s miniruby ruby % make test sample/test.rb:1025:\ in `sleep': Invalid argument - "sleep" (Errno::EINVAL) from sample/test.rb:1025 test failed
流石に一度ではうまくいかないようだ。エラーになったのは
sleep 0.1
で、これは 一昨日書いたところ が非常に怪しい。 gdbでbreakして何を返しているか見てみると全然でたらめな値になってる。 なぜ?しばらく考えてmodf(3)の宣言がないからintを返しているのが原因と気づく。 そりゃそうだよね。modfがないから作ったわけだし。 ってことは他にもあるんじゃないかと思ってチェックしてみると、 hypot, acosh(asinh, atanh)がまずい。 なにしろLinuxとか使ってると最初からすべてあるという状態だからなかなか気づかない。 これでmake testも通った。
frexpのほうはMath.frexpでRubyから呼べるので試してみる。
% ./miniruby -e 'p Math.frexp 10' [2.5, 4] % ruby -e 'p Math.frexp 10' [0.625, 4]
だめじゃん。うーむ。そうか、diet libcの<math.h>にはldexp(3)の宣言がない。 不完全だなあ。#ifdef __dietlibc__しないとだめだ。
% ./miniruby -e 'p Math.frexp 10' [0.625, 4]
よさそう。
% ./miniruby -e 'p Math.frexp -10' [-.625, 4]
printf系は0を省略するのか。これは問題にならないよね?
% ruby -e 'p -.1' -0.1
なので、evalもできるから大丈夫だろう。
明日は拡張ライブラリだ。
なんかよさそうなので、とりあえず1年間で契約してみた。 さっそくCVSでRuby 1.7.2を取ってきてmake all testした。 その前にautoconf 2.53をインストールしたり。
動き始めた。
missing.hにプロトタイプ宣言を入れることになった。 でもvsnprintfとか結構面倒だね。 <stdarg.h>をincludeしなきゃいけないとか。
msvcrt.dllでは_snprintf, _vsnprintfというシンボルだということに、 今更ながら気づく。 win32/win32.hで
#define vsnprintf _vsnprintf #define snprintf _snprintf
としているのでMinGWでは無駄にvsnprintf.oがリンクされてしまう。 MinGWのときはそれを削除したいが、 LIBOBJSなのでconfigure.inの中では手を出すことはできない。 しかたないのでcygwin/GNUmakefile.inで対処しよう。
ARCH=@arch@ ifeq ($(ARCH),i386-mingw32) MISSING := $(filter-out vsnprintf.o,$(MISSING)) endif