2012年12月24日月曜日

portsにあるものを一般ユーザとしてインストールする方法(FreeBSD)

(2014年3月 加筆修正)(2016年7月 加筆修正)

自分がroot権限を持っていないFreeBSDマシンに新しいソフトウェアをインストールするにはどうしたらよいか。 あるいは、自分の管理下のマシンでも、一般ユーザとしてソフトウェアをインストールしたいことがある(例えば、portsシステムで不要なconflictを起こしたくないときなど)。

もちろん、大抵のものはソースコードが公開されていて、自分でコンパイルすればよいのだけれど、FreeBSDにインストールするには、大抵はMakefileの編集が必要で、結構大変。 せっかくportsとして先人が数多のソフトウェアをFreeBSDで使えるように整えてくれたのだから、一般ユーザもportsシステム使えたらいいのにと思う。

このような背景のもと、 最近、games/nethack34をユーザ権限で、homeの下にinstallしてみたので、記録し公開する。 (ユーザ権限でインストールした、真の理由は察してください。)

1. インストール場所の用意、portsの知恵を借りる。

mkdir ~/nethack/
mkdir ~/nethack/ports/
mkdir ~/nethack/ports/distfiles/
cp -r /usr/ports/games/nethack34/* ~/nethack/ports/

2. Makefile を編集する。

portsのdirectoryで普通にmakeしようとすると、rootにしか書き込み権限のないところに作業ディレクトリを作ろうとしたり、logを残そうとしたりしてmakeに失敗する。 だから、さっきコピーしたMakefileを編集する。

~/nethack/ports/Makefileの一番上に、以下を追加する。
DISTDIR= ${HOME}/nethack/ports/distfiles/
PREFIX= ${HOME}/nethack/
WRKDIR= /tmp/work/
TARGETDIR= ${HOME}/nethack/
PORT_DBDIR=/tmp/var/db/ports
INSTALL_AS_USER= yes

3. makeして、配置する。

(この部分を2016年7月に更新しました(次の節の第2段落も削除)。更新前の記述は、取り消し線つきで灰色にした部分。昔は手作業でやっていた。)
cd ~/nethack/ports/
make
で、/tmp/wrok/stage/${HOME}/nethack/の下に一通りのものができる。 これをhomeの下にコピーする。
cp -r /tmp/wrok/stage/${HOME}/nethack/* ${HOME}/nethack/
これでできあがり。必要ならばPathを通しておこう。
cd ~/nethack/ports/
make
make install
でもinstallは途中でsuをしようとして失敗するので、手で配置する。
mkdir ~/nethack/lib/nethack/
mkdir ~/nethack/bin/
cp -r /tmp/work/nethack-3.4.3/dat/* ~/nethack/lib/nethack/
cp /tmp/work/nethack-3.4.3/src/nethack ~/nethack/bin/nethack
この~/nethack/bin/nethackが実行ファイル。
実行したら、permがないとか、saveする場所がないとか怒られたので、以下も実行した。
mkdir nethack/lib/nethack/save/
touch ~/nethack/lib/nethack/perm

4. 補足

上のMakefileの編集内容は、nethackでなくてもどのportsでも同じはず。
nethackの場合は、実行ファイルに$PREFIXがあらわに書き込まれる。て、${PREFIX}/lib/nethack/の下のファイルを見に行くので、安易に/tmpとかしないように注意(もしかして$PREFIXでなくて$TARGETDIRかも)。
環境変数は、/usr/ports/Mk/bsd.*.mkあたり(とくにbsd.port.mk)を参考にすればよろしい。

install中にあらわれるsuの対処法は不明。unpackしたsourceのMakefile(ここでは/tmp/work/nethack-3.4.3/Makefile)を参考にすればよい。

それから、MASTERDIRが存在するportsのときは、MakefileのMASTERDIR変数も処置しておくことが必要なので忘れないように(例えば、nethack34-nox11のMASTERDIRはnethack-34)。場合によってはMASTERDIRもhomeの下にコピーしてしまってもいいかもしれない。

2014年3月追記
久しぶりに同じことをやろうとしたら、
Switching to root credentials to create /var/db/ports/games_nethack34
su: Sorry
と出て、うまく動かなかった。 バージョン管理システムが CVS から Subversion に変更になったことと関係があるのかな。 (参考:FreeBSDハンドブック 5.6. Ports Collection の利用
フォーラムでの議論を参考に、Makefileに
PORT_DBDIR=/tmp/var/db/ports
INSTALL_AS_USER= yes
と追加する必要があった。
なお、現在の環境は、9.2-STABLE #5 r260877Mである。

2016年7月追記
久しぶりに同じことをやってmakeまでしたら、 installすべきもの一式が、
/tmp/wrok/stage/home/_account_name_/nethack/
の下にbin、lib、shareのディレクトリなどに整理されてできあがっていることに気がついた。
(上記のパスは、Makefileで設定しているところの
${WRKDIR}/stage/${TARGET_DIR}である。)
したがって、「配置する」のが単純に
cp -r /tmp/wrok/stage/${HOME}/nethack/* ${HOME}/nethack/
とすれば良くなった。 (参考:FreeBSD portsのStageDir - msllの日記にportsであらわれるstageについて書いてあります。)
ちなみに
make install
とすると、packageを登録しようとして、権限が足りなくて何も起こらない。
なお、現在の環境は、10.3-STABLE #22 r300148である。

2012年7月8日日曜日

xclock (もどき) on windows (xclock in java applet)

私は xclock が大好きである。
いつでもデスクトップの右肩に表示していてほしいくらい大好きだ。
(参考:昔の記事「"Startup Applications" で立ち上げた xclock を "Always on Top" かつ "Always on Visible Workspace" にしたい。 -> devilspie を導入した」)

しかし、windows用のxclockを見つけることができなかった。
窓の社などでwindows用のアナログ時計が公開されているのは知っているけれど、xclock ほど可憐なものは見つけられなかった (あくまでも私の主観です、美しい時計のもたくさんあります)。

自分で windows 用のプログラムを書くのは(環境整備が)ちょっと大変そうだったので、お手軽にJava appletを書くことにした。

まずは、xclock を大きく表示してスクリーンショットで撮って、針の形とか目盛の大きさとかをgimpで拡大して読み取って、いろいろ計算して、、、完成した。


左側が自作のjava applet、右側が本物のxclock

「完成品のソースコード」は自由に参考にしてかまいません。ただし、コードの品質は著作者は一切保証しませんし、コード使用によるすべての責任は使用者、引用者本人が負うものとします。

(上記は、一応のために書きましたが、java なので sandbox 内で実行されますし、通信するプログラムでもありません。読んでいただければ安全だと納得できると思います。)  

完成品のソースコード
(幅がはみ出ちゃったけど気にしない。)
Clock.java

// Clock.java  (quantum, 2012)
// Xclock-like java applet.

import java.applet.Applet;
import java.awt.*;
import java.lang.Math;
import java.util.*; // Date, Formatter
import java.io.*;
import javax.imageio.ImageIO;

public class Clock extends Applet{
    Image offimage;
    Graphics offgraphics;
    int size=300;
    Calendar cal1=Calendar.getInstance();    

    Tics tics1 = new Tics(size);
    Hand lh1=new Hand(size,true);
    Hand sh1=new Hand(size,false);
    Day d1=new Day(size);
    Image hatoimage;
    public Clock(){
        try{
            hatoimage=ImageIO.read(new File("hato.png"));
        }catch(Exception e){
            e.printStackTrace();
            hatoimage = null;
        }
    }
    public void paint(Graphics g){
        tics1.paint(g);
        sh1.paint(g);
        lh1.paint(g);
        d1.paint(g);
    }
    public void update(Graphics g){
        int w = getSize().width, h=getSize().height;
        //      if(offimage == null){
        offimage=createImage(w,h);
        offgraphics=offimage.getGraphics();
        offgraphics.setColor(getBackground());
        offgraphics.fillRect(0,0,w,h);
        paint(offgraphics);             
        //      }
        if(cal1.get(Calendar.MINUTE)==0 && cal1.get(Calendar.SECOND)<10 && hatoimage != null){
            try{
                //              offimage=ImageIO.read(new File("hato.png"));
                offimage=hatoimage;
                g.drawImage(offimage, 0,0, this);                       
            }catch(Exception e){
                e.printStackTrace();
                offimage = null;
            }
        }
        g.drawImage(offimage, 0, 0, this);
    }
        
    public void start() { (new Thread(new MyRun())).start();}
    class MyRun implements Runnable{
        public void run(){
            while(true){
                try{Thread.sleep(500);}catch(Exception e){}
                cal1=Calendar.getInstance();
                sh1.setdirection((cal1.get(Calendar.HOUR_OF_DAY)%12)/12.0
                                 +cal1.get(Calendar.MINUTE)/12.0/60.0);
                lh1.setdirection(cal1.get(Calendar.MINUTE)/60.0
                                 +cal1.get(Calendar.SECOND)/60.0/60.0);
                d1.setcal(cal1);
                repaint();
            }
        }
    }

    static class Tics{  
        double theta,R,d,l,size;
        int[] x=new int[4];
        int[] y=new int[4];
        double[] xd=new double[4];
        double[] yd=new double[4];
        public Tics (double s){
            size=s;R=size*360.0/800.0;d=size/200.0;
        }
        public void paint(Graphics g){
            g.setColor(Color.black);
            for(int i=0;i<60;++i){
                theta=i/60.0*2*Math.PI;
                l=size*36.0/800.0/2.0;
                if((i%5)==0){l=2*l;}
                xd[0]=R*Math.sin(theta)-d/2.0*Math.cos(theta); 
                xd[1]=R*Math.sin(theta)+d/2.0*Math.cos(theta); 
                xd[2]=R*Math.sin(theta)+d/2.0*Math.cos(theta)-l*Math.sin(theta);
                xd[3]=R*Math.sin(theta)-d/2.0*Math.cos(theta)-l*Math.sin(theta);
                
                yd[0]=R*Math.cos(theta)+d/2.0*Math.sin(theta); 
                yd[1]=R*Math.cos(theta)-d/2.0*Math.sin(theta); 
                yd[2]=R*Math.cos(theta)-d/2.0*Math.sin(theta)-l*Math.cos(theta);
                yd[3]=R*Math.cos(theta)+d/2.0*Math.sin(theta)-l*Math.cos(theta);
                
                for(int j=0;j<4;++j){
                    x[j]=(int)Math.round(xd[j]+size/2.0);
                    y[j]=(int)Math.round(-yd[j]+size/2.0);
                }
                g.fillPolygon(x,y,4);
                                //              s=String.format("%d,%d,%d,%d",y[0],y[1],y[2],y[3]);
                //              g.drawString(s,30,330);
            }
        }
    }

    static class Hand{
        double size,direction,phi,r1,r2;
        boolean islong;
        int[] x=new int[3];
        int[] y=new int[3];
        double[] xd=new double[3];
        double[] yd=new double[3];
        public Hand(double s,boolean l){
            size=s; islong=l;direction=0;
            if(l==true){
                phi=134.4/180.0*Math.PI;r1=277.0/800.0;r2=34.3/800.0;
            }else{
                phi=134.4/180.0*Math.PI;r1=152.4/800.0;r2=35.4/800.0;
            }
        }
        public void setdirection(double d){
            direction=2*Math.PI*d;
        }
        public void paint(Graphics g){
            xd[0]=r1*size*Math.sin(direction);
            yd[0]=r1*size*Math.cos(direction);
            xd[1]=r2*size*Math.sin(direction+phi);
            yd[1]=r2*size*Math.cos(direction+phi);
            xd[2]=r2*size*Math.sin(direction-phi);
            yd[2]=r2*size*Math.cos(direction-phi);
            for(int j=0;j<3;++j){
                x[j]=(int)Math.round(xd[j]+size/2.0);
                y[j]=(int)Math.round(-yd[j]+size/2.0);
            }
            g.fillPolygon(x,y,3);       
        }
    }
    static class Day{
        double size;
        Calendar cal;
        public Day(double s){
            size=s;
            cal=Calendar.getInstance();
        }
        public void setcal(Calendar c){
            cal=c;
        }
        public void paint(Graphics g){
            g.setFont(new Font("Helvetica",Font.BOLD,(int)(size*0.08)));
            String s=String.format("%tm/%td %ta",cal,cal,cal);
            g.drawString(s,(int)(size*0.25),(int)(size*0.75));
        }
    }
}

Clock.html
<html>
<head><title>sample</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"></meta>
</head>
<body>
<applet code="Clock.class" width=300 height=300></applet>
</body>
</html>

使い方
1. xclock用のディレクトリを作る。
2. 上記のソースコードをClock.java、Clock.htmlとして保存する。300 x 300 の鳩の絵を hato.png として保存する。
3. Clock.javaをコンパイルする。
4. hato.png のあるディレクトリでアプレットビューアでClock.htmlを実行する。

注意
正時に鳩の絵が表示されるのが嫌な人は、hato.png を置かなくて大丈夫です。

日本語版の windows などの日本語環境だと、曜日の表示が日本語になります。英語がいい人は、Lang=C appletviwer Clock.htmlとすればいいはずです。たぶん。

こんな汚いソースコードは嫌じゃ!と言う人は、自分で直してください。  

参考文献
教養学部の学生だったの頃の、久野先生の講義の資料
Java の APIドキュメント

2012年3月19日月曜日

SFと科学 グレッグ・イーガン「宇宙消失」と小澤の不等式

最近、グレッグ・イーガン著の宇宙消失を読んだ。
それから、今月号の日経サイエンスの特集は小澤の不等式だった。
日経サイエンス  2012年4月号 特集:小澤の不等式
どちらも量子力学の観測問題をテーマとしたお話だったので、比較してみた。

宇宙消失
ジャンル: 物語
初出:
1992 英語原著出版(原題: Quarantine)
1999 日本語訳出版
観測の意味: 観測主体の意識が重要な意味をもつ

小澤の不等式
ジャンル: 科学
初出:
2003 Ozawa, M "Universally valid reformulation of the Heisenberg uncertainty principle on noise and disturbance in measurement" Phys. Rev. A 67, 042105-(1--6) (2003)
観測の意味: 観測を客観的な実験として扱える


正確さを失わないで書評を書けそうにないので、感想を少しだけ書く。
(物理の話は、文庫本の最後についている琉球大の前野昌弘先生の解説が
的確でわかりやすい。この方の ウェブページもおもしろい。物理を勉強すると物語の背景がわかるようになるので、Hard Sience Fiction はよりおもしろくなると私は思う)

感想
モッドがない私たちは、小さい確率でしか起こらないことを起こるように望んでも、多くの場合は願いどおりにならない。でも、古典的な意味で、確率を変えることはできる。
たとえば、バランスのとれた食事をしていれば、そうでない場合に比べて健康的でいられる確率があがる。早起きすれば、有意義に一日をすごせる確率が上がる。
これらの確率に関する事実を踏まえて、食事や起床時間をどうするかを意識的に決めていくことができるのが、自我と知性を持った人間なのだと思う。

2012年2月16日木曜日

今年の風邪(インフルエンザかも)の経過

毎年、熱を出すたびに「一体いつになったら治るのだろう」
と思うので、今年の経過はここに記録しておくことにする。

Fig.1 体温の時系列データ。縦軸は見にくいが、37度〜40度の範囲を表示している。

1月X日
夕食後、だるさを感じた。
湯船に浸かっていても寒気がしておかしいと思った。
入浴後、検温して発熱を確認した。

1月(X+1)日
起床後、熱が下がっているが念のためそのまま寝ていた。
午前中の睡眠から目覚めると、再び体温が上がっていた。
午後も悪化が続き、夕方、マジで死ぬかと思った。
起きるのがとにかくつらかった。
夜、足首を中心に全身が痛かった。怖い夢を見てうなされていた。

この日、食べたかったもの
ジュース、果物

1月(X+2)日
朝、体温は高いもののあまりつらくはなかった。
午前中は寝たり起きたりしていたが、午後からは布団の中でニコリしていた。
食欲が少し出てきた。

この日、食べたかったもの
スープ、バナナミルク、豆腐、炒めりんご

1月(X+3)日
熱が下がり、起きられるようになったので、起きてテレビを見たり、
布団に戻ってニコリしたりしていた。咳が出るようになった。

1月(X+7)日
咳が残っているが、ほぼ元気になった。

1月(X+14)日
いつの間にか、咳もなくなっていた。

風邪、インフルエンザに気をつけましょう。