2008-11-08

GNU makeとSolaris makeのシェル置換

Makefileを書くとき、別の場所にある不特定多数の複数のファイルのベースファイル名だけが定義されたマクロを定義したいとする。

GNU makeだと
DIR = xxx/yyy/zzz
FILES = $(shell cd $(DIR); echo *.cc)

Solaris makeだと
DIR = xxx/yyy/zzz
CMD = cd $(DIR); echo *.cc
FILES = $(CMD:sh)

でできるらしい。

でも、できれば同じMakefileを使いたいものだ。いろいろ迷って

DIR = xxx/yyy/zzz
CMD = cd $(DIR); ls *.cc
FILES = $(CMD:sh) $(shell $CMD)

としてみた。一応動くけど… 微妙

サブMakefileを動的に作って、それを読み込ませるべきかな?

Solaris x86のカーネルデバッガの起動方法

デバッガ制御下でカーネルを起動させた場合に(カーネルパニックを起こさずに)デバッガに入る方法がman kdbに載ってた。
F1+A、またはShift+Pauseとのこと。なるほどね。
SPARCシステムでもShift+Pauseは有効らしい。STOPキーが付いてないキーボードもちゃんとサポートされているわけだ。

Xサーバが動いている時にF1+A押したらどうなるのか試したら、画面はフリーズして、見えないところでデバッガが動いた。
::continueでデバッガからカーネルに復帰するので、何事もなかったかのようにXサーバが動作を再開するのがちょっとおかしい。

Solarisの起動画面 #3

ついでに/boot/solaris.xpmの作り方。

基本的には、14色に減色した640x480のxpm画像を用意すれば良い。
GIMPでやるとすると、以下のような手順になる。

  1. 画像>画像拡大縮小で縦か横を480または640に合わせる。
  2. 画像>キャンバスサイズで640x480にする。
  3. 画像>モード>インデックスで、14色パレットを使うインデックスカラーモードに変更する。このときディザを使うほうが良い。
  4. xpmファイルとしてファイル保存。
  5. xpmファイルをテキストエディタで開く。
  6. "640 480 14 1",と書いてある行があるはずなので、"640 480 15 1",に書き換える。
  7. その下に"! c None",という行を追加する。ただし、ファイル中に!という文字が使われていたら、別の文字を選ぶ必要がある。

基本的にはWindows9xと同じような作業なのではないかと。若干面倒くさいけど、Windows2000では起動画面のイメージはカーネルの実行ファイルに埋め込みらしく、再設定には専用のツールが必要らしい。それよりはましかな。

そんなわけで、我が家では制服姿の女子小学生が起動画面に設定されておりますw
こんなSolarisもそうそうないだろうな orz...

Solarisの起動画面 #2

…ということで、Solaris 10/08の起動画面を設定してみたのだけど、GRUBのほうの画面は表示されるものの、カーネルが起動してからの画面は表示されないことが判明。

よく見ると、boot_archive(Linuxでいうinitrd.gzみたいなもの)に/boot/solaris.xpmが入ってない。
そこで、boot_archiveに入れるファイルを決める/boot/solaris/filelist.ramdiskにファイル名を入れてみたのだけど、やはり表示しないようだ。あれー?

ZFS rootなのが影響しているのかな?

2008-11-04

Solarisの起動画面

ブート画面がグラフィカルになったのはGRUBを採用した頃だったかな?
最初はその軟派さがもの珍しくて喜んで設定したものだっけ。

あったあった、「ささの豆知識ブログ」だな。
http://blogs.sun.com/sasanuma/entry/solaris_10_1_06_graphical

だけど、絵柄はたいして代わり映えのするものではないので、最近は微妙にうっとおしかったりしてw
何の情報も出てこないのも無駄な話ではあるし、しばらく何の表示もされないままなのはハングっぽくてたまにギョッとすることがある。それに、コンピュータの起動画面というのは文字がぶわーっと出るものだという刷り込みがあるんだよねw

というわけで、単にテキストモードにするだけでなく、カーネルを冗長モードにし、かつSMFのサービス起動を表示させてみる方法。

GRUBのmenu.lst(/boot/grubや/rpool/grubの下に入ってる)のsplash文をコメントアウト。んでもって、
#---------- ADDED BY BOOTADM - DO NOT EDIT ----------
から
#---------------------END BOOTADM--------------------
で囲まれている部分を、その外側にコピー。コピーしたほうのkernel行に"-v -m verbose"を追加する。

例えば
#---------- ADDED BY BOOTADM - DO NOT EDIT ----------
title Solaris 10 1/06 s10x_u1wos_19a X86
root (hd0,0,a)
kernel /platform/i86pc/multiboot
module /platform/i86pc/boot_archive
#---------------------END BOOTADM--------------------
と書いてあったら、
title Solaris 10 New!
root (hd0,0,a)
kernel /platform/i86pc/multiboot -v -m verbose
module /platform/i86pc/boot_archive
#---------- ADDED BY BOOTADM - DO NOT EDIT ----------
title Solaris 10 1/06 s10x_u1wos_19a X86
root (hd0,0,a)
kernel /platform/i86pc/multiboot
module /platform/i86pc/boot_archive
#---------------------END BOOTADM--------------------
とするだけでよい。

ここらへんはman boot, man kernelに載ってる。ついでに-kオプションもつけておくと、デバッガの制御下でカーネルを起動できる。といっても、パニックを起こすようなことがなければ役には立たないけど…

Solaris 10/08をインストール

Xubuntuで疲れきってしまったので、気を取り直してSolaris 10/08をインストール。
これもかなり独特なインストーラだけど、ドキュメントはかなり揃っているのでGoogle先生に頼ることはあまりないのが良い。

ただ、マシンの構成情報を入力する画面のインターフェースはいいかげん直してもらいたいものだ。青地のスクリーンとか(どうにもMSXを思い出してしかたがないw)、次に進むのがEnterではなくF2とか、かなり異彩を放っている。
まあ、そうそう何度もインストールするものでもないけど…

では遅まきながらZFS RootやVirtual Boxを堪能するとしますか。

ThinkPad 240 / Silicon Motion Lynx EM+でX.org起動せず

タイトルのみ…
疲れたよ、パトラッシュ…

なんかこのビデオカード、X.orgにとってはかなりの地雷らしい orz...
先に言ってくれよ…

Xubuntu 8.10のネットインストール #2

ネットインストールでごちゃごちゃ頑張ってはみたんだけど、どうにも成果あがらず… xubuntu-desktopパッケージをインストールできればXubuntuシステムのインストールが完了するのだけど、どういうわけか失敗してしまう。

そのうち「なんでネットインストールなんかしているんだろう」というところまで気分が萎えてきてしまう始末w ただ、これが結果的には突破口になった。

そもそもネットインストールを試みる理由を考えてみると、

  1. 光学ドライブそのものがない/接続できない/認識しない
  2. 光学ドライブから起動できない

があると思うんだけど、今回は後者のケース。よく考えるとUSB接続のDVDドライブがあるので、いったんカーネルさえ起動してしまえばそこからはインストーラが起動できるはず。

インストーラはPXEから起動した場合とCD-ROMから起動した場合で実は2種類ある。PXEから起動されるインストーラは「ミラーサーバからごっそりダウンロードしてくる」という動作になっており、この動作を行なわせるスクリプトがCD-ROMのinstall/netboot/ubuntu-installer/i386/initrd.gzに入ってTFTP経由で転送される。

それに対し、CD-ROMから起動する場合のインストーラは「ひとまずCD-ROMの内容を使う」という動作になっており、CD-ROMのinstall/initrd.gzに入っている(ファイル名は同じだが、中身は別)。

そんなわけで、「ネットインストール用のinitrd.gz」を「CD-ROMからのインストール用のinitrd.gz」に差し換え、それをTFTPで転送させてみると…
おお、何事もなくUSB-DVDドライブからインストール始めたよ!
そんなわけで、ThinkPadにもXubuntuインストール完了

2008-11-03

日立Flora用のxorg.conf

今回Xubuntuを入れたFloraは、もともとWin98の時代に企業向けに出されていた機種で、VRAMの量が極めて少ない。このため、デフォルトの24bppでは解像度が800x600になってしまう。

そこで、今どき必要な人がいるとも思えないのだけどxorg.confをさらしてみる。
Section "Server Layout"
Identifier "Configured Layout"
Screen 0 "Default Screen" 0 0
InputDevice "Configured Mouse" "CoreMouse"
InputDevice "Configured Keyboard" "CoreKeyboard"
EndSection

Section "Device"
Identifier "Configured Video Device"
EndSection

Section "Monitor"
Identifier "Configured Monitor"
HorizSync 40-50
VertRefresh 50-70
EndSection

Section "Screen"
Identifier "Default Screen"
Monitor "Configured Monitor"
Device "Configured Video Device"
DefaultDepth 16
EndSection

Section "InputDevice"
Identifier "Configured Mouse"
Driver "mouse"
EndSection

Section "InputDevice"
Identifier "Configured Keyboard"
Driver "kbd"
Option "XkbRules" "xorg"
Option "XkbModel" "jp106"
Option "XkbLayout" "jp,jp"
Option "Xkbvariant" "106,"
Option "XkbOptions" "ctrl:swapcaps"
EndSection

DefalutDepthを16にするだけではダメで、HSync/VSyncを明示的に指定することが必要。

Ubuntu 8.10のX.orgはctrl:swapcapsが効かない

ネットインストールに挫折し、日立Floraで普通にインストール。うーん、簡単でいいなあ…

で、困ったことがひとつ。
自分は気持ちは若いつもりなのだけど、CtrlキーはAの横にないとダメなオールドタイプである。特にノートPCでは手の腹でCtrlを押せないので、必ずCapsとCtrlは入れ替え(もしくは両方ともCtrl化)を行なっている。

さっそくxorg.confをいじって
        Option          "XkbOptions" "ctrl:swapcaps"
を追加してみたのだけど… 効かねえ orz...

ログを見ると、途中までは記述を読み込んでいるようなのだけど、途中でevdevとかいうドライバ(?)が再設定しなおしているようだ。余分なことを…

そんなわけでカーネル側のキーマップを変えようと思い、/etc/console-setup/boottime.kmap.gzのkeycode 58のCaps_LockをすべてControlに置換。
ただし、これも仮想端末ではきちんと反映されるものの、XサーバではCapsはやはりCapsのまま。

最終的には
#!/bin/sh
setxkbmap -option ctrl:swapcaps
という内容の/etc/X11/Xsession.d/10setxkbmapを作って回避。やれやれ

Xubuntu 8.10のネットインストール

CG定点観測さんでXubuntuというものがあるのを知り、古いノートPCを再生させようと思い立つ。

で、たまたま思い立った日がUbuntu 8.10とXubuntu 8.10がリリースされた日で、さっそくAlternateのCD-ROMイメージをダウンロード。Think Padは光学ドライブがないので、ネットインストールに挑戦… これが茨の道だった。

分かったこと。

  • DHCP+TFTPでブートさせるのまでは簡単。
  • DOS対策のためか存在しないファイルを要求するとTFTPサーバが少しウェイトするので、ubuntu-installer/i386/boot-screens/以下にamd.cfg gtk.cfg amdgtk.cfg adamd.cfg adgtk.cfg adamdgtk.cfgという名前の空のファイルを置いておくと高速にメニューが出てくる。
  • kickstartという自動インストール機構がある。Solarisで言うところのjumpstart。
  • kickstartの設定ファイルの場所はubuntu-installer/i386/boot-screens/text.cfgで指定する。
  • ただし、Xubuntuのインストーラがkickstartの書式を直接理解するというわけではない。実際にはインストール時にkickseedというプログラムがpreseedという別の形式(?)のファイルに変換しているだけらしい。凝ってるなあ…
  • で、このkickseedのスクリプトがバグってる。getoptが-lオプションを認識出来ないので、kickstartの設定がほとんど反映されない。


最後のが影響が大きく、ミラーサーバの指定ができずに必ず公式サーバに接続しにいこうとしてしまう。まあ、時間のある時だったらいいけど、できればローカルなミラーサーバを探しにいって欲しいわけだ。

一応カーネルの起動オプションで生の(すなわちkickseedが動的に生成したものではない)preseedを指定することもできるのだが、これが反映されるのがkickseedが動いてミラーサーバを決めた後らしく、解決策にならない。

そんなわけで、こんな方法で逃げてみた。

  1. mkdir /tftpboot/ubuntu-installer/i386/initrd
  2. cd /tftpboot/ubuntu-installer/i386/initrd
  3. gzip -dc ../initrd.gz | cpio -idv
  4. lib/kickseed/handlers/url.shのurl_handler()の先頭に以下を追加。超強引wwww

    ks_preseed d-i log/url string ''
    ks_preseed d-i mirror/country string 'enter information manually'
    ks_preseed d-i mirror/protocol select http
    ks_preseed d-i mirror/http/hostname string 192.168.1.xx
    ks_preseed d-i mirror/http/directory string /xubuntu

  5. 同じくlib/kickseed/handlers/user.shのuser_handler()の先頭に以下を追加。これでパスワードなしのユーザを追加する。

    ks_preseed passwd passwd/make-user boolean true
    ks_preseed passwd passwd/username string xxxx
    ks_preseed passwd passwd/user-fullname string xxxx
    ks_preseed passwd passwd/user-password-crypted password

  6. find . | cpio -oc | gzip > ../initrd.gz

(作業はSolaris上でやったので、cpioのオプションがLinuxと違うかもしれない)

要するに、kickseedがやるはずだった処理を、getoptに差し掛かる前に自前で実行してしまおうというものだ。kickstartの設定ファイルには

install
url --url http://192.168.1.xx/xubuntu/
user xxxx --fullname xxxx --passwd xxx

%packages
xubuntu-desktop
と書いてあるが、実際にはオプションはまったく解析されない。

で、大体これでうまくいくんだけど、パッケージの選択がまだうまくいかないのでベースシステムだけになってしまう。あと、sources.listもおかしいかな。うーん…

2008-10-13

DECOチョコ

オリジナルの画像でラッピングされたチロルチョコを作ってくれるサービスがあるらしい。
DECOチョコ

45個入り(画像3種類x15個)で2362円+送料なので結構お手頃。なんかのネタによさそうなのでメモ。

2008-09-25

バビリムナマコ

デイリーポータルZで干しナマコの醤油煮の記事が載ってた。
これがもうキモいのなんのって!
外面もキモいし、内臓もキモい。
実はこれは地球外生物です、と言われても信じてしまいそう。
なんかエイリアン9を思い出してしまう。

で、たまたまドルアーガの塔の小説を読み返したばかりで、「バビロニアンキャッスルサーガ」と「バビリムナマコ」のを連想したところにバビローンとか吹き出しがあって、一瞬そういうネタなのかなと思ったのだけど、別に関係なかったかな…

2008-09-02

型の最大最小値

長かった…
これがしたかっただけなんだけど、ずいぶん大げさになってしまった。

// 型の最大値
template <typename X> struct max_of {
typedef typename SelectNegativePresentation
<X, limits_of_u<X>, limits_of_s2<X>, limits_of_s1<X>, limits_of_sa<X>
>::Result Selected;
static X value() { return Selected::max(); }
};

// 型の最小値
template <typename X> struct min_of {
typedef typename SelectNegativePresentation
<X, limits_of_u<X>, limits_of_s2<X>, limits_of_s1<X>, limits_of_sa<X>
>::Result Selected;
static X value() { return Selected::min(); }
};


ちなみに、シフトによる桁あふれがあるのでg++でコンパイルするとご丁寧に警告を出してくれるのだけど、これが3000行近かったりするw

型の選択

これはLoki(というかModern C++ Design)からのパクリ。

// 型選択
// flagが真ならResultがT1、偽ならResultがT2となるクラステンプレート
template <bool flag, typename T1, typename T2> struct Select {
typedef T1 Result;
};
template <typename T1, typename T2> struct Select<false, T1, T2> {
typedef T2 Result;
};

// 整数の表現形式を選択する
template <typename X, typename U, typename S2, typename S1, typename SA>
struct SelectNegativePresentation {
typedef typename Select<
is_unsigned<X>::value, U,
typename Select<has_sign_and_abs_part_unsafe<X>::value, SA,
typename Select<
is_1s_complement_unsafe<X>::value, S1, S2
>::Result
>::Result
>::Result Result;
};


こいつを使うと、型の最大最小がわかるはず…

整数の表現形式ごとの最大最小

これはWikipediaを参考にしつつ。
1の補数表現と2の補数表現が同じになってしまってあれっと思ったけど、そういえば+1されてるかどうかの違いだった… 忘れてるなあ。

// 2の補数表現での最大最小
template <typename X> struct limits_of_s2 {
static X max() { return msb<X>::value() ^ ~X(0) ; }
static X min() { return msb<X>::value(); }
};

// 1の補数表現での最大最小
template <typename X> struct limits_of_s1 {
static X max() { return msb<X>::value() ^ ~X(0) ; }
static X min() { return msb<X>::value(); }
};

// 符号ビット+絶対値表現での最大最小
template <typename X> struct limits_of_sa {
static X max() { return msb<X>::value() ^ ~X(0); }
static X min() { return ~X(0); }
};

// 符号なし整数の最大最小
template <typename X> struct limits_of_u {
static X max() { return ~X(0); }
static X min() { return X(0); }
};

整数型のビット数

// Xの範囲で1 << Nが算術的に桁あふれするならvalue==1
template <typename X, unsigned N> struct arith_overflow {
// 1<<0は算術的に桁あふれしないと定義する。
// N>0に対しては、1<<(N-1)が算術的に桁あふれしておらず、
// かつ(1<<N)/2 == 1<<(N-1)が成立する場合、
// 1<<Nは算術的に桁あふれしないと定義する。
// なお、Nビット幅の整数Xに対して(X(1)<<N)==0は必ずしも成立しない。
enum { value = arith_overflow<X, N-1>::value
|| X(X(1) << N) / 2 != X(1) << (N - 1) };
};
template <typename X> struct arith_overflow<X, 0> {
enum { value = 0 }; // 定義より、1<<0は算術的に桁あふれしない

};


// 整数型の有効桁のビット数を得る
template <typename X, unsigned N = 0, bool flag = false> struct valid_bits_of {
// X(1)<<Nが桁あふれする場合(flag != false)の定義
enum { value = N };
};
template <typename X, unsigned N> struct valid_bits_of<X, N, false>
{
// X(1)<<Nが桁あふれしない場合(flag == false)の定義
enum {
// N+1〜N+3で桁あふれするか調べ、分からなければN+4で調べる
value = arith_overflow<X, N + 1>::value ? N + 1
: arith_overflow<X, N + 2>::value ? N + 2
: arith_overflow<X, N + 3>::value ? N + 3
: valid_bits_of<X, N + 4,
arith_overflow<X, N + 4>::value>::value
};
};


// 整数型のビット数を得る
template <typename X> struct bits_of {
enum {
value = valid_bits_of<X>::value + is_signed<X>::value
};
};


// MSBのみが立った数を得る
template <typename X> struct msb {
static X value() {
return X(1) << (bits_of<X>::value - 1);
}
};


valid_bits_ofで名前あってるかな?
なんで4つ飛びに調べてるかというと、Sun C++でテンプレートのネストが深すぎると警告がでたため。

符号つき数値型の表現方式判定

これは http://www.kijineko.co.jp/tech/cpptempls をまるパクリで。
ただし、クラス定義の中で静的クラス変数を定義できる処理系かちょっと思い出せなかったので、列挙定数に置き換え。
あと、符号なしの型を与えるとコンパイルエラーになるようにちょっとだけ修正。

// condが成立しない場合にコンパイルエラーにするマクロ
#define STATIC_ASSERT(cond) typedef char assertFailed[(cond) ? 1 : -1]


// 符号ありの型Xが2の補数表現ならvalue==1
template <typename X> struct is_2s_complement_unsafe {
enum { value = (X(-1) & 3) == 3 };
};
template <typename X>
class is_2s_complement: public is_2s_complement_unsafe<X> {
STATIC_ASSERT(is_signed<X>::value);
};

// 符号ありの型Xが1の補数表現ならvalue==1
template <typename X> struct is_1s_complement_unsafe {
enum { value = (X(-1) & 3) == 2 };
};
template <typename X>
class is_1s_complement: public is_1s_complement_unsafe<X> {
STATIC_ASSERT(is_signed<X>::value);
};

// 符号ありの型Xが符号ビット+絶対値表現ならvalue==1
template <typename X> struct has_sign_and_abs_part_unsafe {
enum { value = (X(-1) & 3) == 1 };
};
template <typename X>
class has_sign_and_abs_part: public has_sign_and_abs_part_unsafe<X> {
STATIC_ASSERT(is_signed<X>::value);
};

型の符号有無判定

http://www.kijineko.co.jp/tech/cpptempls を読んで、「numeric_limitsって便利だなあ」と感心することしきり。さっそく使ってみたい(超ミーハー)のだけど、仕事で使うとなると用意されてないかもしれない。

ということで、似たようなものをテンプレートメタプログラミングでつくれないかなと試行錯誤中。はてさて…

まずは型の符号有無をコンパイル時に判定するテンプレート。
// Xが符号つきの型ならvalue==1
template struct is_signed {
enum { value = 0 > X(-1) };
};

// Xが符号なしの型ならvalue==1
template struct is_unsigned {
enum { value = 0 < X(-1) };
};
こんな調子でいいのかな?

long longの左シフト

コンパイル時に整数型のビット数を得るテンプレートを試していて、(long long)(1ll << 64)が0にならないことに気が付いた。しかも、4294967296とかいう妙な値。

そんなわけで、検証プログラム。
#include <iostream>
int main(int argc, char *argv[]) {
signed long long sll = 1;
unsigned long long ull = 1;
for(int i = 30; i < 70; i++) {
std::cout << "1ll<<" << i << " = " << (sll << i)
<< "\t1ull<<" << i << " = " << (ull << i)
<< std::endl;
}
return 0;
}


Sun C++でコンパイルして実行してみると

1ll<<60 = 1152921504606846976 1ull<<60 = 1152921504606846976
1ll<<61 = 2305843009213693952 1ull<<61 = 2305843009213693952
1ll<<62 = 4611686018427387904 1ull<<62 = 4611686018427387904
1ll<<63 = -9223372036854775808 1ull<<63 = 9223372036854775808
1ll<<64 = 4294967296 1ull<<64 = 4294967296
1ll<<65 = 8589934592 1ull<<65 = 8589934592
1ll<<66 = 17179869184 1ull<<66 = 17179869184
1ll<<67 = 34359738368 1ull<<67 = 34359738368
1ll<<68 = 68719476736 1ull<<68 = 68719476736
1ll<<69 = 137438953472 1ull<<69 = 137438953472


g++でコンパイルして実行してみると
1ll<<60 = 1152921504606846976     1ull<<60 = 1152921504606846976
1ll<<61 = 2305843009213693952 1ull<<61 = 2305843009213693952
1ll<<62 = 4611686018427387904 1ull<<62 = 4611686018427387904
1ll<<63 = -9223372036854775808 1ull<<63 = 9223372036854775808
1ll<<64 = 1 1ull<<64 = 1
1ll<<65 = 2 1ull<<65 = 2
1ll<<66 = 4 1ull<<66 = 4
1ll<<67 = 8 1ull<<67 = 8
1ll<<68 = 16 1ull<<68 = 16
1ll<<69 = 32 1ull<<69 = 32
CPUはいずれもAMD Opteron。コンパイラのバージョンは

CC: Sun C++ 5.7 Patch 117831-02 2005/03/30
g++ (GCC) 3.4.3 (csl-sol210-3_4-branch+sol_rpath)

まあ、ビット幅を越えてシフトした場合の振る舞いは未定義だった気がするので、その意味ではおかしくはない。けど、コンパイラによって振る舞いが違うってのはちょっと意外だったなあ。

けど、ビット幅Nの型Xに対して常に(X)(X(1)<<N)==0が成立するとばかり思い込んでいたので、ちょっと期待が外れてしまったりして。

たらいまわし関数その2

さきのテンプレート版たらい回し関数(関数じゃないけど)、どうもおかしいと思ったら>と<がHTMLタグ扱いになってた… はずかしー

ちなみにg++のバージョンはg++ (GCC) 3.4.3 (csl-sol210-3_4-branch+sol_rpath)。ちょっと古いかもしれないので、4.xでは改良されているかもしれない。

で、今度はSun C++で挑戦。

% CC -V
CC: Sun C++ 5.7 Patch 117831-02 2005/03/30
% time CC tarai_t.cc
7.08u 0.17s 0:07.49 96.7%
% ./a.out
Tarai(384, 192, 0) = 384


これもかなり古いけど、意外とあっさりと成功。

2008-09-01

テンプレート版たらいまわし関数

Modern C++ Designなど読んでしまったもので、たらいまわし関数をコンパイル時に計算しようと思い立つ。

template <bool flag, typename T1, typename T2> struct Select {
typedef T1 Result;
};

template <typename T1, typename T2> struct Select<false, T1, T2> {
typedef T2 Result;
};

template <int x, int y, int z> struct Tarai;

template <int x, int y, int z> struct Tarai1 {
enum { value = y };
};

template <int x, int y, int z> struct Tarai2 {
enum { value = Tarai<
Tarai<x-1,y,z>::value,
Tarai<y-1,z,x>::value,
Tarai<z-1,x,y>::value
>::value };
};

template <int x, int y, int z>
struct Tarai {
typedef Select< (x <= y), Tarai1<x, y, z>, Tarai2<x, y, z> > Selected;
enum { value = Selected::Result::value };
};

#include <iostream>

int main()
{
//enum { x = 768, y = 384, z = 0 };
enum { x = 384, y = 192, z = 0 };
std::cout << "Tarai(" << x << ", " << y << ", " << z << ") = " << Tarai<x,y,z>::value << std::endl;
}


こんなものかな。しかし、テンプレートメタプログラミングはコンパイラのエラーを理解するのが大変だなあ…

% time g++ -ftemplate-depth-8000 tarai_t.cc
virtual memory exhausted: 資源が一時的に使用できません。
1215.41u 3.25s 22:23.57 90.7%


(´・ω・`)ショボーン

2008-08-30

d20 system

最近はゲームのたぐいはほとんどやってないけど、以前はroguelikeを少々やっていた。
もっとも、セーブファイルを保存していたり、デバッガを使ってwizardモードに入ったり、識別の魔法が好きな時に使えるパッチを作ったりというまっとうでない遊び方ではあるのだけど…

そんなわけで、D&D由来の文化はすこしばかりなじみがあり、Beolineliedさんの博識っぷりもどっぷり楽しめるクチである。

で、思い出したのだけど、そういえば中学生の時(約20年前)にD&D、しかもDMをやってんだよね… うーん、黒歴史だw

娯楽らしい娯楽もなかった田舎の中学生にとっては、翻訳調丸出しのルールブックも新鮮で楽しかったなあ。もっとも、部活だの仲間割れ(キャラクタのじゃなくてプレーヤーのw)なんだので、ベーシックルールセットさえ終えられなかった気がする。しかもシナリオは完全に自作で、今考えると超赤面ものですよ orz...

で、当時は(というか今でも?)ルールブックはめちゃめちゃ高くて、高レベル(一応当時でもイモータルのルールはあったような気がする)の世界はまったくの未知の世界だったりする。また、NetHackはAD&Dがベースになっているはずだけど、やはりこちらも一度も読んだことがない。

そんなわけで、Beolineliedさんとこを楽しんだはいいものの、「D&D3.5eとか4eってどうなってるんだろ、ルールブック買ってみたいけど、セッションやるわけじゃないし…」と悶々としていたある日のこと、そのベース部分がd20 systemとしてルールが公開されているという情報が!

さっそく見てると… これはすごい。企業戦略も見えなくはないんだけど、「あのルールブックの値段は何だったんだろう?」と思うほどあっけらかんと情報が詰まっていて、英語なのに夢中で読んでしまった次第。
そろそろ日本語でも4版が出るらしいのだけど、私家翻訳版とか作ってみたいなあポワワ (遅いってw)

2008-08-23

sendmailのスマートホストとOBP25

家庭内LANからいったんISPのメールサーバにメールを投げたかったので、いままでろくに使っていなかったローカルSolaris10マシンのsendmailをいじることに。

sendmailもしばらく使ってなかったなあ。ローカル配送自体やってなかったし、人間が読むメールはすべてISP頼みだったし。

そもそもsendmail.cfやCF自体いじったことがほとんどない。
大学にいたときはバリバリにsendmailを使っていたけれども、宛先に該当するユーザのGIDでリレーホストを切り替えるという凝ったことをやっていたので、末端の管理者は直接いじらずに過ごせていたので…

そんなわけで、まずはWebmin(w
/usr/sfw/lib/webmin/sendmail/以下のファイルはすべて/usr/local/bin/perlで起動するようになっているので、これを修正してさくっと設定… できなかった orz...

スマートホストは「ホスト経由でメールを送信」をいじれば簡単に設定可能なんだけど、最近のOBP25の設定まではできないようで、ISPのサーバからは接続を拒否されてしまう。

そんなわけで、重い腰を挙げてsendmail.cfの生成にチャレンジ。/etc/mail/cf/cf/sendmail.mcに

define(`SMART_HOST', `メールサーバのアドレス')
define(`RELAY_MAILER_ARGS', `TCP $h ポート')
を追加し、

cd /etc/mail/cf/cf/
make sendmail.cf
cp sendmail.cf /etc/mail
svcadm restart sendmail

でおk