〜2001年12月下旬〜
予報通りの雪。うっすら雪化粧という感じ。非常に寒い。
makeをRubyで書く話がruby-talkで続いているが、 たぶんbootstrapに関しては何も考えてないんだろう。 というわけでbarerubyだ。 microとかtinyだと別なのもを想像するのでbareにした。
まずは1.6.6のCVS版で一個一個gcc -cしてみる。
% gcc -c array.c In file included from array.c:15: ruby.h:21:20: config.h: No such file or directory
config.hが必要だ。面倒だから全部まとめてコンパイルだ。
% touch config.h % gcc -c *.c エラーがいっぱい % ls *.o array.o dmyext.o hash.o math.o range.o st.o version.o bignum.o enum.o inits.o numeric.o re.o string.o class.o error.o main.o object.o regex.o struct.o compar.o gc.o marshal.o prec.o sprintf.o variable.o % ls *.c array.c dmyext.c hash.c math.c random.c sprintf.c variable.c bignum.c enum.c inits.c numeric.c range.c st.c version.c class.c error.c io.c object.c re.c string.c compar.c eval.c lex.c pack.c regex.c struct.c dir.c file.c main.c prec.c ruby.c time.c dln.c gc.c marshal.c process.c signal.c util.c
ふむ。半分以上はコンパイル可能。順番に見てこう。
dir.c:232: parse error before "DIR"
がすべてを物語っているわけだが、なんかいきなり難関にぶちあたった気もする。 barerubyは少くともextmk.rbやmkmf.rbが動かないと意味がないわけでdir.cは必須だ。 簡単なconfigureみたいなものが必要かな。 gcc *.c -o barerubyってわけにもいかないので *1、 どっちにしてもshell scriptは必要だろう。 dirent.h, direct.h, sys/ndir.h, sys/dir.h, ndir.hをcheckしよう。
dln.c:1675: `X_OK' undeclared (first use in this function)
unistd.hをcheck。
eval.c:81: redefinition of `struct timeval'
sys/time.hをcheck。
eval.c:5336: `DLEXT' undeclared here (not in a function)
これってdlが使えないなら参照しないようにしたほうがよさそうだな。 とりあえず、ソースを直すのは後にして、
#define DLEXT ".so"
をconfig.hに追加しよう。
eval.c:6614: `free' undeclared (first use in this function)
stdlib.hをcheck。他にstring関係でwarningが出てるのでstring.hもcheck。
file.c:124: `free' undeclared (first use in this function)
これはeval.cと同じでstdlib.h。
file.c:396: parse error before "GETGROUPS_T"
group_memberの為にある。
#define GETGROUPS_T int
でごまかしとこう。
io.c:1281: `O_RDONLY' undeclared (first use in this function)
fcntl.hをcheck。
を忘れてた。が、今までのheaderのcheckでいけてる。
pack.c:82: `TOKEN_PASTE' declared as function returning a function
これは##だね。ANSI Cを前提にしちゃおうかな。
#define TOKEN_PASTE(x,y) x##y
##をcheckしてだめなら/**/にするか。
process.c:594: `hfunc' undeclared (first use in this function) process.c:594: `qfunc' undeclared (first use in this function) process.c:594: `ifunc' undeclared (first use in this function)
RETSIGTYPEか。 barerubyとしてはforkしないでsystemですませたいので、 rb_syswaitもなくてもいい感じだ。とりあえず
#define RETSIGTYPE void
して先に進める。
random.c:158: `RAND_MAX' undeclared (first use in this function)
extmk.rb的には必要ないのが、stdlib.hをcheckすればいいだろう。
ruby.c:266: `RUBY_SITE_LIB2' undeclared (first use in this function) ruby.c:270: `RUBY_SITE_ARCHLIB' undeclared (first use in this function) ruby.c:271: `RUBY_SITE_LIB' undeclared (first use in this function) ruby.c:273: `RUBY_LIB' undeclared (first use in this function) ruby.c:277: `RUBY_ARCHLIB' undeclared (first use in this function)
全部""にしておく。
signal.c:348: parse error before "sighandle" signal.c:378: parse error before "sigbus" signal.c:465: `func' undeclared (first use in this function)
全部RETSIGTYPE。
time.c:22: redefinition of `struct timeval' time.c:60: `free' undeclared (first use in this function)
これもすでに対応済み。
util.c:90: `W_OK' undeclared (first use in this function)
対応済み。
これだけでうまくいけば簡単なんだけどね。
file.o(.text+0x1ae6): the `getwd' function is dangerous and should not be used.
これは警告なので、とりあえず無視。
array.o(.text+0x483): undefined reference to `RSHIFT'
そうか。RSHIFTはconfigure.inからひっぱってこよう。
bignum.o(.text+0x2e62): undefined reference to `pow'
あ-lmが必要だ。
pack.o(.text+0xd47): undefined reference to `NUM2U32'
そうかSIZEOF_HOGEをなんとかしないといけないんだな。 bareならpackもunpackも要らないか。bareinits.cを用意してpackは外そう。
re.o(.text+0x2e6): undefined reference to `ruby_re_mbcinit' re.o(.text+0xc07): undefined reference to `ruby_re_compile_pattern' re.o(.text+0xdcb): undefined reference to `ruby_re_copy_registers' re.o(.text+0x13ef): undefined reference to `ruby_re_search' re.o(.text+0x1ba0): undefined reference to `ruby_re_free_pattern' re.o(.text+0x2caa): undefined reference to `ruby_re_set_casetable' regex.o(.text+0x198f): undefined reference to `xrealloc' regex.o(.text+0x3680): undefined reference to `scan_hex' regex.o(.text+0x36bb): undefined reference to `scan_oct'
RUBY_PLATFORMを"unknown-unknown"と定義する。
string.o(.text+0x60bc): undefined reference to `crypt'
-lcryptか。LIBSを用意しとこ。
% LIBS='-lm -lcrypt' sh bareruby.sh % ./bareruby -v ruby 1.6.6 (2001-12-21) [unknown-unknown]
できたね。packのテストを外してsample/test.rbを実行してみる。
% ln -s bareruby miniruby % ./bareruby sample/test.rb (snip) marshal not ok marshal 1 -- sample/test.rb:1063 (snip) test: 314 failed 1
というわけでmarshalだけだ。これもたぶんSIZEOFだな。 marshalは外そう。
% CC=gcc LIBS=-lcrypt bash ./bareruby.sh
compileは問題なく進む。MAXPATHLENのredefined警告がうるさい。 Cygwinはunistd.hをincludeすると定義されるらしい。 とりあえずsys/param.hもcheckしよう。
file.o(.text+0x250b):file.c: undefined reference to `flock'
__CHECKER__を定義しよう。って__CHECKER__ってなんだ?
io.o(.text+0x1ca):io.c: undefined reference to `ReadDataPending'
これは苦しいね。常に0を返すか?bareinits.cに入れてみよう。
signal.o(.text+0xb9a):signal.c: undefined reference to `sigmask' signal.o(.text+0xbd0):signal.c: undefined reference to `sigsetmask' signal.o(.text+0xbfc):signal.c: undefined reference to `sigsetmask' signal.o(.text+0xcc3):signal.c: undefined reference to `sigblock'
面倒だなあ。いっそsignal.oも外すか。ってそれは無理だ。 bareinits.cにdummyを用意しよう。
% CC='gcc -mno-cygwin' ./bareruby.sh (snip) gcc -mno-cygwin -I. -c dir.c dir.c: In function `dir_s_mkdir': dir.c:484: too many arguments to function `mkdir'
そりゃそうだ。不本意ながらmingw32のcheckを入れよう。
warning: `va_start' redefined
がうるさいが、コンパイルはok。が、リンクでundefinedがいっぱい。 win32/win32.cを無視してるからだ。 crypt.cも対応して、LIBSに-lwsock32を入れてみると
bignum.o(.text+0x1276):bignum.c: undefined reference to `isinf' bignum.o(.text+0x12bd):bignum.c: undefined reference to `isnan' file.o(.text+0x3054):file.c: undefined reference to `getwd'
てな感じ。やっぱ関数をcheckしないのは無理があるか? getwdに関してはdir.cではifdefなしでgetcwdを使っているので、 getcwdにしても問題なさそう。 missing/{isinf,isnan}.cをコピーするか。
これでtestも通った。
問題なし。比較的新しいOSなら通るでしょう。
とりあえずここまでできたから、思う存分makeを作ってくれ。 が、その前にconfigure.rbが必要だと気づいた。
bignum.cで思い切りエラー。世の中そんなに甘くないのである。 明日へつづく(たぶん)。
ftp://ftp1.sf.net/pub/sourceforge/プロジェクト名という感じでftpでアクセスできる。 たとえばmingwなら こう だ。 P4W からの情報。
結局SIZEOFを解決させないとbignum.cはコンパイルできない。これも外すか? それは絶対無理だな。 逆にSIZEOF対応すればmarshalもpack.cもいけるわけだよね。 そっちの線でいったほうがいいか。 小さいものを作ろうとしてるわけでもないし、外さない方向のほうがいいか。
configureを見るとsizeof(foo)をfprintfしてcatするだけ。 autoconf-2.5xだとクロスの場合にも対応してて、 なんだかよくわからない方法でsizeを計算してる。 そこまでやらなくてもという気がするので、 barerubyをクロス対応させるときは環境変数だな。
調べるのはint, short, long, long long, __int64, void *, float, doubleだ。 とりあえずできた( bareruby.sh )。
ふむ。1.7ではすでにgetwdは駆逐されてたのか。 じゃ、HAVE_GETCWDを無条件でdefineしとこう。
testしたらSEGVってしまった。普通に作れば問題ないので何かが足りないようだ。 gc.cの
# define STACK_LEVEL_MAX 655300
が大きすぎるからか。gc.cにパッチをあてよう。
こっちはsystemと表示したっきり返ってこない。
% ./bareruby -e 'system "echo foo"' foo
でpromptに戻らない。systemがなんかまずいって、あ、RETSIGTYPEか? もちろん普通に作れば問題ない。こっちも何かが足りないようだ。
同じ名前で*.oを作ると共存できないので、barray.oのように名前を変えよう。
HAVE_WAITPIDだった。 win32/win32.cを見るとwait()はreturn 0;だから無限ループになるのも無理はない。
出たね。クリスマスにはちょっと早いが。
広末がCMに出てるとこを久し振りに見る。
shにelifがないのが痛い。 {}を使って
{ test -e foo.c && src=foo.c; } || { test -e bar.c && src=bar.c; } || { src=hoge.c; }
という手を捻り出してみた。 {}はconfigureでも使ってるので、まあ、いいかな。 ;を忘れるとエラーになる。zshだと;はなくてもいい。
てゆか、なぜおいらはelifがないと思ったんだろう? あるに決まってるじゃん。
bareruby.shはsrcdir対応にした。
更新。
FreeBSD 3.3でRuby 1.6.6をbareruby.shすると
bpack.o: In function `pack_pack': bpack.o(.text+0xf6d): undefined reference to `NUM2U32'
となる。どうも
#if SIZEOF_SHORT != 2 || SIZEOF_LONG != 4 # define NATINT_PACK #endif
が真になってしまうのが原因のようだ。でもconfig.hはちゃんと
#define SIZEOF_INT 4 #define SIZEOF_SHORT 2 #define SIZEOF_LONG_LONG 8 #define SIZEOF_LONG 4 #define SIZEOF___INT64 0 #define SIZEOF_VOIDP 4 #define SIZEOF_FLOAT 4 #define SIZEOF_DOUBLE 8
となっているんだけどなあ。不思議だ。
なお1.7だと問題ない。そのあたりに違いはないのに。
あ、SIZEOF対応前のconfig.hがsource directoryにあったからか。 -I.を後に置いたほうがいいな。
25分も遅れるなよー。明日からは2時間で予約しとこ。
isinf, snprintf, vsnprintfがundefined。 missingは全部リンクしちゃうか?
更新。
GNU makeを作るにはmakeがないことも考えられていて、 build.shというのがついてくる。いやbuild.sh.inがついてくる。 build.shはconfigureすると作られる。 なるほど。そういう手もあるのか。
mswin32に関しては特に何も考えてない。 調べる必要がないから、最初から決めうちでいいわけだし。
nmake -n
した結果をそのままbareruby.batにするぐらいでいいんじゃないかな。
bareruby.batで思い出した。というかすっかり存在を忘れてた。 今クロスしか環境ないから試せないんだよねえ。 ちなみに
% ../bareruby.sh \ --srcdir=../ruby16 \ --CC=i586-pc-msdosdjgpp-gcc \ --RSHIFT_SIGN=yes \ --SIZEOF_INT=4 \ --SIZEOF_SHORT=2 \ --SIZEOF_LONG=4 \ --SIZEOF_LONG_LONG=8 \ --SIZEOF___INT64=0 \ --SIZEOF_VOIDP=4 \ --SIZEOF_FLOAT=4 \ --SIZEOF_DOUBLE=8 \ --yacc='bison -y'
ぐらいは通ってたりする。作ってみてこれほど意味のないものはないと思うが。 barerubyはminirubyと同じで、その場で実行できないと意味がない。
missing/strftime.cはLinuxではコンパイルできない。 djgppでもtimezoneがundefinedになったりで、あまりportableではないらしい。 結局missingからやばそうなmkdir.c, os2.c, strftime.c, x68.cを除いて足すことにした。 つまりOS/2とX68kは別に対応しないといけないわけか?
rm b*.oだとbignum.oも消えてしまうので、_をprefixすることにした。
今日は10分遅れだ。やはり定刻通りには始まらない。 鬼界カルデラってなんか怖そうな名前だ。
Yendot で知る。
今回は別のPCで
% ./configure \ --enable-languages=c,c++ \ --with-system-zlib \ --enable-sjlj-exceptions \ --enable-threads \ i586-pc-linux-gnu % make bootstrap % make prefix=$HOME/gcc-3.0.3/usr/local install % cd ~/gcc-3.0.3 % tar cfvz gcc-3.0.3-bin.tar.gz usr
してtarballを作ってみた。
そんなクリスマスプレゼントはいらない、ocnのsomebody。
Ruby 1.7になって空白はファイル名の一部とみなすようになった。でも
Dir["foo/*", "bar/*"]
はどうなったんだっけ? どっちにしても1.6と共存を考えた場合、 実装されてもしばらくは使わないほうがいいだろう。 Cygwin用に setup.ini を作るスクリプトを考えてたんだけど、
Dir["ruby-*-i386-cygwin.tar.gz ext/*.tar.gz"]
が出てきてしまった。しかたないので空白を使わない方法を考えよう。
Dir::[]はArrayを返すので2つに分けて足せばいい。
Dir["ruby-*-i386-cygwin.tar.gz"] + Dir["ext/*.tar.gz"]
でもなんかださい。
Dir["ruby-*-i386-cygwin.tar.gz", "ext/*.tar.gz"]
互換性の点から実装されてもあまり使いたくない。
Dir::[]では{,}が使用可能。 実は空白はすべて{,}で置き換えることが可能なのだ。
Dir["{ruby-*-i386-cygwin.tar.gz,ext/*.tar.gz}"]
というわけで、結論としては
dir.cはいじる必要なし 複数パターンを指定したいときは{,}を使え
ということになる。
今日は出ないか。
JST的には間に合わなかったが、ruby-talk的には十分Merry Christmasか。
そのundefined具合から想像するに相当な移植作業が必要です。 socket関係は<winsock.h>あたりをincludeして-lwsock32をlinkすればよさそうだけど、 大きなところではtermiosの代わりを書くとかselectとか。
いちいちuploadして試さないといけないのかと思ったら、setup.exeで
Install from Local Directory
を選べばlocalでtestできることに、今頃気づいた。 というわけで、これから充実させようと思う。
更新。
1.6.6のnet/smtpの仕様変更で動かなくなっていたらしい。 失敗しても何のエラー表示もないようなので要確認。
で、何が変更されたんでしょう?
これ を見ると、 元の記事はruby-talk MLへ流れてない。 ここ2日ほどcomp.lang.rubyへ投稿された記事は、 このままruby-talk MLへは来ないのかもしれない。
Makefileはこのままだと
2.4.18pre1
になってしまうけどいいのか?
EXTRAVERSION = -pre1-preempt
とした。preempt patchもなんかつけて欲しいなあ。
今月のspam率は21/153だ。
最初はよくあるspamだと思ったんだけど、 よく見るとNextへのリンクが切れてるという内容で *1、 このモニタリングサービスを受けたければclickしろとかあって、 結局spamなのか? そのページへアクセスするのも負けた気がするし、放っておくことにする。
それはそれとして、Nextへのリンクを来年一年分用意しとこう。
流量が元に戻ってきた。
[test]があるとメニューに出てこない。困ったな。
CVS限定でいいのならcvsの終了ステータスを見るのが一番軽いかも。
% cvs diff -u1 version.h % echo $? 0 % echo "" >>version.h % cvs diff -u1 version.h >/dev/null % echo $? 1
今気づいたんだけどPostedを見ると12/25の記事が来てる。 ということは徐々に流れて来てたのか。
違った。単にoutboxに残っていたらしい。いわゆる 送信箱問題 か。
やっぱり、SEGVってしまうなあ。0.24で試してみよう。
じゃなくて これ を解決してなかったんだ。 gdbで実行してみると、src/rbgtk.cのrbgtk_poll()で起きてる。 あれ?ここは使わないはずなんだけどなあ。 わかった。 _WIN32 は今のCygwinでは定義されてない。 素直に-DNATIVE_WIN32しよう。というわけで こう してみた。
0.26からはgtkじゃなくてruby-gtkになってる。 gtk-0.25は消したほうがいいか?
だからBadtrans.Bを送ってこないように。
結局Net::SMTP.{new,start}の最初の引数であるSMTP serverが省略不可になったんだけど、 Daveさんのスクリプトの例外処理に不備があり捕らえることができなかったというのが原因のようだ。 仕様変更とはそういうことか。 1.6.5では省略した場合'localhost'とみなしている。
なるほど。-lmはRuby/GDだけの問題じゃないはずなので、 extmk.rb.in,mkmf.rbのhave_libraryを書き換えて、 "m"だったらmswin32では無条件でappend_libraryしないで成功させてしまってもよさそうですね。mingw32も同じか。
if /mswin32|mingw/ =~ RUBY_PLATFORM + return true if lib == 'm' r = try_link(<<"SRC", libs)
てな感じで。commitしとこう。ぐは。yesを表示しなきゃだめだ。
また間違えた。ext/extmk.rb.inはyesを表示しちゃだめ。
Re: [ruby-list:27433] Re: Cygwin + Oracle...
というSubjectでBadtrans.Bが来た。 Badtrans.Bってそんな小細工もするのか。
急にBadtrans.Bが増えたのはなぜ?
更新。
サービスで動かしたときはuserが自分ではないので、 mount tableがない状態になってます。mount -sで設定すればいけます。
あとntsecとnteaは元々同時には使えません。 nteaでは使い物にならないので、ntsecができたようなもんなので。
autoconf.rbもあることだし、そろそろconfigure.rb.inに手を出すか。 大晦日はことのほか暇だったりする。 最初はそのまま1.7のconfigure.inを一行一行変換していくことにする。 最近Rubyのスクリプトもあまり書いてないので、丁度いい練習にもなるかな。
いまのところCVSだけ。configure.rb.inはmod_ruby, erubyに付属のものが参考になる。
% cvs -d :pserver:anonymous@www.modruby.net:/var/cvs login Logging in to :pserver:anonymous@www.modruby.net:2401/var/cvs CVS password: そのままReturn % cvs -d :pserver:anonymous@www.modruby.net:/var/cvs co autoconf_ruby
まずはversion.hからMAJOR, MINOR, TEENYを取り出すとこから。 configure.inではgrepでRUBY_VERSIONのある行を選び、 さらにexprでMAJOR, MINOR, TEENYを得ている。 Ruby的にはいい例題かもしれない。
Rubyで一行一行を見ていく方法はいくつかある。
やっぱFile.foreachが簡単か。最初はこんな感じになる。
File.foreach File.join $srcdir, "version.h" do |line| if /RUBY_VERSION "(\d+)\.(\d+)\.(\d+)"/ =~ line $MAJOR, $MINOR, $TEENY = $1, $2, $3 break end end AC_SUBST("MAJOR") AC_SUBST("MINOR") AC_SUBST("TEENY")
これはversion.hのRUBY_VERSIONが変更されたら、 configureし直さなければならないことを意味している。 CVSで追っかけてる人は要注意。
erubyではこういう感じ。
$MAJOR, $MINOR, $TEENY = open(File.join($srcdir, "eruby.h")). grep(/ERUBY_VERSION/)[0]. scan(/(\d+).(\d+).(\d+)/)[0]
長くなったので改行を入れたが実質one linerだ。 FileはIOのサブクラスでIOはEnumerableをincludeしてるのでgrepがいきなり使える。
3個ぐらいなら並べたほうが早いが、いっぱいあるときは
$~.to_a.indexes(1, 2, 3)
とかしたくなるかもしれない。 が、Array#indexes, Array#indicesは1.7.2では
warning: Array#indexes is deprecated; use Array#select warning: Array#indices is deprecated; use Array#select
を喰らってしまう。 かといって1.6.6にはArray#selectはないので、selectを積極的に使いたくない。 都合が悪いことにselectはEnumerableのメソッドなので、 respond_to?の結果を使ったaliasもできない。
ここでちょっとrespond_to?の利用法を。 以前のRubyではArray#collect!はArray#filterという名前だった。 その過渡期にはcollect!を直接使うのも互換性の問題があるので、
unless [].respond_to? :collect! class Array alias collect! filter end end
という方法が使われていた。 Arrayにcollect!がなければaliasしてしまうわけだ。
続いて--without-gcc対応であるが、こんな感じかな。
AC_ARG_WITH('gcc', '--without-gcc never use gcc') do |withval| case withval when /^no$/ $CC ||= 'cc' when /^yes$/ $CC ||= 'gcc' else $CC = withval end end
autoconf.rbは--without, --disableには対応してないようだ。 たぶん前田さんはもうautoconf.rbをいじらないようが気がするので、 やはりおれがいじるべきか?
それはそれとして$CCはこの前で設定されてるので、||=しても意味ないなあ。 うーむ。
このままだと、
% CC=foo-cc ruby configure.rb
としても$CCに伝わらないので、
require 'importenv'
も入れとこう。
importenvは環境変数を$FOOといったグローバル変数へマッピングしてくれるlibraryだ。
% CC=gcc ruby -e 'p $CC' nil % CC=gcc ruby -rimportenv -e 'p $CC' "gcc"
autoconf.rbしてみると、いきなりrequire "mkmf"があった。 mkmf.rbはrbconfig.rbをrequireしてる。 でもこれはminirubyが作るもので、 今考えているのはrubyを作るためのconfigure.rb.inを書いてるわけだから、 mkmf.rbをrequireしてはいけない。 やはりautoconf.rbを相当いじらないとだめか。
というより、autoconf.rbはembedded rubyのためにあるんだよね、やっぱ。
来年につづく(のか?)。
更新。