2012年7月28日土曜日

自分的 Fedora17 初期設定メモ

このところずっとUbuntu ユーザーだったんですが、諸事情 (2個前の「Zenbook Prime フリーズ問題」)がありまして、Fedora 17をインストールしてみました。

かなり久しぶりにFedoraに触ると、初期設定にとまどったので、備忘録としてメモっておく。


・日本語環境にする

「システム設定」→「地域と言語」
「言語」タブで日本語を選択。
「システム」タブで「設定のコピー...」をクリック。いったんログアウト。


・IME の ON/OFF を別キーに割り当てる

自分は日本語IMEのONに「変換」キー、OFFに「無変換」キーを割り当てたい人です。
Ubuntu の IBus は ON と OFF を別々に割り当てられるのに、Fedoraの IBusはトグルしか設定ができないみたい。
scim-mozc はバグなのか、動きませんでした。
ibus-mozc に以下の設定をすると、とりあえず自分のやりたいことはできた。

IBus が ON/OFF を別キーに設定できないなら、Mozcの機能で IME ON/OFFを別キーで切り替えるようにします。

「システム設定」→「地域と言語」を起動。
「レイアウト」タブで日本語以外は全部削除し、常に ibus-mozcだけが起動する状態にする。

デスクトップ右上のMozcのアイコンを右クリックして出てきたメニューから「Properties」を選ぶと、Mozcの設定ができる。
「一般」タブの「キー設定の選択」でことえりを選ぶ。
「編集...」をクリック。
「編集」ドロップダウンメニューの中からエクスポートを選ぶ。
keymap.txt に保存し、

DirectInput        Henkan      IMEOn
Precomposition MuHenkan IMEOff

の2行を追加。

「キー設定の選択」でカスタムを選び、「編集」ドロップダウンメニューのインポートを選んで、今作成した keymap.txtを取り込む。

これでうまくいきました。



・Chromiumブラウザ

自分はChromium (Chrome)ブラウザを使いたい人。

Ubuntu だとデフォルトで chromium がリポジトリに入っているが、Fedoraにはデフォルトでは入っていなかった。
http://fedoraproject.org/wiki/Chromium
に書いてあった。

http://repos.fedorapeople.org/repos/spot/chromium-stable/fedora-chromium-stable.repo
の内容を /etc/yum.repos.d
に放り込めばよいらしい。

2012年7月26日木曜日

Make のポータビリティについて考える

Makefile のポータビリティについて考えてみる。

Makefile 中では、 $(MAKE)$(AWK) など、変数で記述することがよく行われる。
これはポータビリティを考える上で当然である。

たとえば、Linux 上で普通 make といえば、GNU make のことを指す。
一方、Free BSDでは、make は GNU拡張されていない普通のmake のことであり、GNU makeのコマンド名は gmake だったりする。
そこで、make というコマンド名を直接 Makefile 中に埋め込むのではなく、 $(MAKE) という変数名で記述するわけだ。

今回、考えたいのは echo コマンドについて。Makefile 中でもよく使われている。
echo コマンドは環境によって、仕様にかなり違いがあり、シェルビルトインのechoもあるので、ポータビリティを考えだすと結構複雑だったりする。

例えば、bash を使っている人は

$ echo "hoge\npiyo"
hoge\npiyo
$ echo -e "hoge\npiyo"
hoge
piyo
$ type echo
echo はシェル組み込み関数です

となる。

一方、tcsh では

$ echo "hoge\npiyo"
hoge
piyo
$ echo -e "hoge\npiyo"
-e hoge
piyo
$ which echo
echo: シェルに入っているコマンドです.

となる。


最近の Ubuntu や Mint に標準で入っている dashの場合、

$ echo "hoge\npiyo"
hoge
piyo
$ echo -e "hoge\npiyo"
-e hoge
piyo
$ type echo
echo is a shell builtin


つまり、bash, tcsh, dash いずれもシェルビルトインのechoを持つが、bashビルトインのechoはデフォルトでは \n といったエスケープシーケンスを解釈してくれず、エスケープシーケンスを解釈させるためには -e オプションをつける必要がある。

一方、tcsh や dash のビルトインのecho はデフォルトでエスケープシーケンスを解釈してくれる代わりに、 -e オプションは解釈してくれない。

さらにシェルビルトインではない /bin/echo の仕様はプラットフォームごとに違うのだが、Linux であれば

$ /bin/echo "hoge\npiyo"
hoge\npiyo
$ /bin/echo -e "hoge\npiyo"
hoge
piyo

となり、bashビルトインのechoと同じような挙動をする。

このようにechoの仕様は結構違う。

そこで、Makefile の中で echo を使った場合、call される echo はどれなのか?
(ここでは GNU make についてのみ考える。)

これについては O'REILLY の「GNU Make」 の5章の冒頭に書かれている。
原著は以下で参照できる。

要約するとこういうことだ。
・make はコマンドを1行ごとに取り出し、サブシェルに渡して実行する。
・ただし、ワイルドカードやリダイレクションなどシェルの特殊文字が使われていない場合、高速化のためにサブシェルに渡さず、makeが直接コマンドを実行する。
・呼び出すサブシェルはデフォルトで /bin/sh であるが、make の変数 SHELL により変更できる。
・ただし、この変数は環境変数から引き継ぐものではない。make は環境変数を makeの変数として取り込むが、 SHELL だけは例外である。


本当にそうなっているか、以下の Makefile で実験してみる。


all1:
@echo --version
@type echo

all2:
@echo --version | cat
@type echo | cat

all3: SHELL=/bin/bash
all3:
@echo --version
@type echo



以下は Fedora 上で実行した結果である。

$ make all1
echo (GNU coreutils) 8.15
Copyright (C) 2012 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

作者 Brian Fox および Chet Ramey。
make: type: コマンドが見つかりませんでした
make: *** [all1] エラー 127
$ make all2
--version
echo はシェル組み込み関数です
$ make all3
--version
echo はシェル組み込み関数です



all1 は make が直接コマンドを実行しており、 /bin/echo が実行されている。
(そのため、 --version オプションを解釈している。)

all2  はパイプを使っている。ワイルドカードやリダイレクト、パイプなどを使っているとサブシェル /bin/sh の中で実行する。
Fedoraでは /bin/sh は bashへのシンボリックリンクになっているので、結局は bashビルトインのecho を実行している。(そして --version オプションを解釈しない

all3 は make 変数 SHELL の値を /bin/bash に書き換えているので、bash ビルトインのecho を実行している。

前述のように、make 変数の SHELL は環境変数の SHELL とは無関係だ。
SHELL だけは環境変数から引き継が仕様になっている理由は、ユーザーの使っているシェルがmakefileの動作に影響しないためだ。
例えば、tcsh をデフォルトにしているユーザーは 環境変数 SHELL/bin/tcsh になっているはずだが、だからといって、 makefile のルールを tcsh で実行するのはナンセンスだ。スクリプトを C shell系で記述することはほとんどないわけだから。

all1all2 の実行結果の違いを見てもわかるように、ワイルドカード、リダイレクト、パイプなどのシェルの特殊文字を使っているかどうかによって、サブシェルを呼ぶか、make が直接実行するかが変わる点は注目に値する。

make がサブシェルを呼ぶ場合、makefile 内で明示的に変数 SHELL を書きかえない限りは、 /bin/sh を呼ぶ。
Redhat 系ならば /bin/sh はbash へのシンボリックリンクだが、Ubuntu や Mint は dash へのシンボリックリンクになっているので、前述のように echo の動作が変わってくることになり、環境によっては期待通りに動いてくれないかもしれない。
環境によっては /bin/sh がシンボリックリンクではなく、本物の Bourne Shell なこともあるだろう。

対策として、 ECHO=/bin/echo のように変数を用意し、 $(ECHO) を使用することで、常に /bin/echo を実行するようにするということが考えられる。

サポートするビルド環境を、Linux などの単一のプラットフォームに限定するならば、これでもよい。
だが、 /bin/echo の仕様はプラットフォームごとに結構違うので、別のプラットフォームに移植するときに問題になり、ポータビリティには欠けると思う。

例えば、Linux の /bin/echo-e オプションを解釈するが、FreeBSDの /bin/echo は解釈しない。
また、echo の改行を抑制するためには、Linux や FreeBSD では -n オプションを使用するが、Solaris や HP-UX は
echo "hoge\c"
のように \c で改行を抑制するようだ。

そういうわけで、多様なプラットフォームへの対応しないといけない場合、
Makefile に
SHELL=/bin/bash
と書いておき、常にbashビルトインのechoを使わせるようにするのがいいのではないかと思った。
(本当にこれで大丈夫なのかは確認していないのですが。。)
ただし、その場合、make が直接コマンドを実行するという最適化は行われなくなる。

まあ、一番良いのは、あまりマニアックなオプションは使わないにこしたことはないです。

2012年7月15日日曜日

Zenbook Prime フリーズ問題

先日、Zenbook Prime (UX21A-K1256) を購入しました。

リカバリーディスクを作ったあと、さっそくWindows 7 を削除し、Ubuntu 12.04 LTS Desktop 64bitをインストールしました。

タッチパッドの右クリックが効かない(左クリックと同じになる)という問題はあるものの、自分はBluetoothマウスを使用するので、さほど問題にはなりません。
気に入って使い出したのだが、しょっちゅうフリーズする。

・電源入れて使い始めてすぐにフリーズしたことがあるので、熱問題ではないと思う。
・フリーズすると、急に熱くなって、ファン音がうるさくなる。
・フリーズすると、マウスポインタは止まり、Alt + SysRq + R + S + E + I + U + B も反応しません。


もしかしてハズレ引いてしまったのかな。
Windows7のまま使っていてフリーズ多発ならメーカーに文句も言えるが、OS入れ替えちゃってるし、クレームは言いづらいよな〜。

試行錯誤しています。

OS再インストールしてみた。
→ 効果なし。

Ubuntu 12.04 LTS Desktop 32bit をインストールしてみた。
→ やっぱりフリーズ。

Linux Mint 13 Maya をインストールしてみた。
→ やっぱりフリーズ。Mint もベースは Ubuntu だからそりゃそうか。

Fedora 17 64bit をインストールしてみた。
→ フリーズせずに、使えています。

<解決>
コメントでいただいたリンク先を読むと、Ubuntu の kernel 3.2.0-26でWi-Fi接続時にkernel panicが発生する問題があるそうな。
現時点ではkernel 3.2.0-27にアップデートされているようです。
しばらく使っていてもフリーズしませんので、大丈夫のようです。ありがとうございました。

自分用の .emacs

emacs の設定は全く詳しくないが、webで見つけて使っている設定をメモ。
それほどいじり倒していませんが、とりあえず必要なもの。



Cのインデントをスペース4個で行う場合。あんまり使っていない。
;;; indent with 4 spaces

(setq-default tab-width 4 indent-tabs-mode nil)

(add-hook 'c-mode-common-hook
          '(lambda ()
             (c-set-style "GNU")
             (setq c-basic-offset 4)))



上のと排他利用だが、Cのインデントはタブで行う。
なおかつ、タブの表示幅はスペース8個分とする。
Linuxのソースを書くときはこっち。
(Linusさんはインデントはスペース8個分で、1行は80文字以内にせよと言っている)
;;; indent with tab
(add-hook 'c-mode-common-hook
        (lambda ()
                (setq tab-width 8)
                (setq c-basic-offset 8)
                (setq indent-tabs-mode t)
                ))

(set-default-coding-systems 'utf-8)




列番号を表示する。行番号はデフォルトで表示されている。
(column-number-mode 1)



文字サイズ変更。
デスクトップなら、デフォルトのままで問題ないのですが、最近 Zenbook Primeを買いまして。
11.6インチのディスプレイに1920x1080の解像度はさすがに文字が小さすぎますので、文字をちょっと大きくしました。


(set-face-attribute 'default nil
   :height 140)






GNU global用。コード読むのに欠かせません。
Meta-t でタグジャンプなど。
Meta-* で戻る。


(setq gtags-mode-hook
      '(lambda ()
         (local-set-key "\M-t" 'gtags-find-tag)
         (local-set-key "\M-r" 'gtags-find-rtag)
         (local-set-key "\M-s" 'gtags-find-symbol)
         (local-set-key "\C-t" 'gtags-pop-stack)
         ))

(add-hook 'c-mode-common-hook
          '(lambda()
             (gtags-mode 1)
             (gtags-make-complete-list)
             ))



MOZC用。emacs-mozc のインストールが必要。


(require 'mozc)
(set-language-environment "Japanese")
(setq default-input-method "japanese-mozc")






Ubuntuならば、上記だけでOKなんですが、Fedora ならば以下も追記しておく必要がありました。



(autoload 'gtags-mode "gtags" "" t)
(load-file "~/gtags.el")



gtags.el を ~/の下に置いた場合です。
このファイル、yum install global でインストールした場合は、入ってないみたいなので、tarballを拾ってきて入れました。

2012年7月14日土曜日

自分仕様の grep

make のリスタートあり/なし その2


今回も make がリスタートする条件をもう少し調査してみる。
前回見たように、基本的にインクルードファイルが更新されればmakeは最初からやり直します。
(ただしインクルードファイルが.PHONY指定されている場合は除く。)

ちょっと面白い実験。次の Makefile を用意。


$(warning restart)
include foo.mk


all:
@echo $@


foo.mk: FORCE
touch -t 07010000 $@


.PHONY: FORCE
FORCE:



$ touch foo.mk 
$ ls -l
合計 4
-rw-rw-r-- 1 hoge hoge 109  7月 14 18:45 Makefile
-rw-rw-r-- 1 hoge hoge   0  7月 14 18:46 foo.mk
$ make
Makefile:1: restart
touch -t 07010000 foo.mk
Makefile:1: restart
touch -t 07010000 foo.mk
all
$ ls -l
合計 4
-rw-rw-r-- 1 hoge hoge 109  7月 14 18:45 Makefile
-rw-rw-r-- 1 hoge hoge   0  7月  1 00:00 foo.mk
$ make
Makefile:1: restart
touch -t 07010000 foo.mk
all


インクルードファイルの日付が変化すれば、たとえ古くなっていても make はリスタートするようだ。



では、日付が変化しさえすれば、make はリスタートするのかというと、必ずしもそうでもない。

次のような Makefile を用意。


$(warning restart)
include foo.mk


all:
@echo $@


foo.mk: bar
:


bar: baz
touch foo.mk



$ touch bar 
$ touch baz
$ make
Makefile:1: restart
touch foo.mk
:
Makefile:1: restart
touch foo.mk
all
$ make
Makefile:1: restart
touch foo.mk
all


bar, baz の順にtouch してから make すると、 bar の構築ルールのところで、 foo.mk  が更新される。
続いて、 foo.mk の構築ルール : が実行されたあと、make がリスタートする。
(このとき、 : が実行される理由は以前「make の動きを解剖する」参照)

さらにもう一回、makeを実行するときは : は実行されず、make のリスタートもない。
make がリスタートするためにはインクルードファイルの日付が変更され、かつそのインクルードファイルの構築ルールが実行される必要があるようだ。

だから、Makefile 中で foo.mk の構築ルールの : を削除した場合も make のリスタートは起こらない。

make のリスタートあり/なし


以前、「make に無前ループ防止機能?」に書いたとおり、以下の make は毎回 foo.mk が再構築されて、makeがリスタートする。




$(warning restarting)
include foo.mk


all:
    @echo $(BAR)


foo.mk: FORCE
    echo "BAR:=1" > $@


.PHONY: all FORCE
FORCE:






FORCE 指定を外せば、当然ながら foo.mk が存在しない場合にだけ、 foo.mk が構築されて、make がリスタートする。



$(warning restarting)
include foo.mk


all:
@echo BAR is $(BAR)


foo.mk:
echo "BAR:=1" > $@


.PHONY: all






$ make
Makefile:1: restarting
Makefile:2: foo.mk: そのようなファイルやディレクトリはありません
echo "BAR:=1" > foo.mk
Makefile:1: restarting
BAR is 1
$ make
Makefile:1: restarting
BAR is 1








foo.mk.PHONY 指定すると、リスタートしてくれないようだ。



$(warning restarting)
include foo.mk


all:
@echo BAR is $(BAR)


foo.mk:
echo "BAR:=1" > $@


.PHONY: all foo.mk


$ ls
Makefile
$ make
Makefile:1: restarting
Makefile:2: foo.mk: そのようなファイルやディレクトリはありません
echo "BAR:=1" > foo.mk
BAR is
$ ls
Makefile  foo.mk
$ make
Makefile:1: restarting
echo "BAR:=1" > foo.mk
BAR is 1



make とシンボリックリンク

make とシンボリックリンクはかなり相性が悪いと思っていて、自分は使用しないようにしている。

理解しておくべき基本的な事柄として、make は依存関係間で日付を比較するときに、シンボリックリンクそのものの時刻ではなくて、リンク先のファイルの日付を参照する。
touchコマンドもシンボリックリンク自体の日付を更新するのではなくて、リンク先のファイルの日付を更新する。

シンボリックリンクによって、コンパイル対象のファイルまたはディレクトリを切り替えている場合には、注意を要する。
リンク先が切り替わったとしても、必ずしも再コンパイルしてくれません。

例えば、 foo.cbar.c という2つのファイルがあったとして、どちらか一方へ、 source.c というシンボリックリンクを貼り、コンパイルする。

Makefile は以下のようだとする。


app: source.c
        gcc -o $@ $^



$ ls
Makefile  bar.c  foo.c
$ ln -s foo.c source.c
$ make
gcc -o app source.c
$ ls
Makefile  app  bar.c  foo.c  source.c
$ ln -sf bar.c source.c 
$ make
make: `app' は更新済みです


最初に、 foo.c へリンクを貼り、makeしています。
次に、 bar.c へリンクを貼り直しています。
この時点でシンボリックリンク source.c の日付は更新されますが、これは make は見ません。
bar.capp を比較し、app の方が新しいため、make は再コンパイルしてくれないわけです。

複数のソースディレクトリがあって、コンパイル対象を切り替えたい(例えば Linux Kernel の arch みたいに)ことはしばしばあるが、シンボリックリンクは使わないほうがよいと思う。

以前のLinux Kernelはmake中に include/asm から include/asm-(ARCH)へシンボリックリンクを張っていたが、今は廃止している。

組み込みのブートローダーとして有名な u-boot はいまだに、arch の選択にシンボリックリンクを張っているが、make の不具合が多いような気がする。
経験的に、defconfig で対象ボードを切り替える前に、いったんmrproper しないと危険です。

2012年7月2日月曜日

make の動きを解剖する その2

前回、makeが構築ルールを実行する時はどんなときなのか、調べてみました。
前回は、PHONYターゲットについては触れていませんでした。

今回は、それについて補足調査します。

用意するMakefile

all: a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b

c:
    @echo -n c

$ touch c
$ touch b
$ touch a
$ make



これは、当然の結果ですね。何も構築する必要がありません。


次に c を PHONYターゲットにします。

all: a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b

.PHONY: c
c:
    @echo -n c


$ touch c
$ touch b
$ touch a
$ make
cb


c を PHONY ターゲットにした場合、問答無用で c の構築ルールが実行されるだけでなく、 c を依存関係に引き連れている b の構築ルールも必ず実行されます。
ただし、 a の構築ルールまでは実行されていないことから、その上の階層までは伝搬しないようです。

make の動きを解剖する

make では ファイル間の依存関係を精査し、必要なオブジェクトのみを再構築するのが基本である。
ただし、PHONYターゲットのように、必ずしもファイル実体を伴わないルールもある。
それらの依存関係が複雑にからんだ場合、それぞれの構築ルールを実行すべきか否か、makeはどのように決定しているのかだろうか。

私は make 内部実装はいっさい見ていないが、いくつかの実験を行い、内部の動きを推論することにする。


(実験1)
次の内容の Makefile を用意。

all: a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b

c:
    @echo -n c



ファイル a とファイル b の間の関係としては、次の5通りがある。
それぞれ make を実行したときの表示結果を示す。

(1) ab も存在しない → 実行結果 cba
(2) a だけが存在 → 実行結果 cba
(3) b だけが存在 → 実行結果 cba
(4) ab も存在し、 a の方が新しい → 実行結果 cb
(5) ab も存在し、 b の方が新しい → 実行結果 cba


この結果から推論できること:
(推論1)

a: b
    @echo -n a

という依存関係と構築ルールがあったとき、「ファイル a もファイル b も存在し、かつ a の方が新しい」(これを以下、条件1と呼ぶ)が成立すると、構築ルールを実行しない。
条件1が成立しないときは構築ルールを実行する。


では、条件1が成り立つかどうか評価するのは、どの時点なのだろうか?


(実験2)
次のMakefile を用意する。

all: a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b
    @touch b

c:
    @echo -n c


条件1が成り立つ状態にしてから、このmakefileを実行してみる。
$ touch b
$ touch a
$ make
cba


(推論2)
この実験結果から、条件1が成り立つかどうか評価しているのは、 b の構築が終わったあとだと考えられる。
なぜならば、make を開始した時点では、条件1が成立している。
@touch b」を行った後で、条件1が成立しなくなる。
@echo -n a」が実行されているという結果を見れば、 ab の日付比較は直前に行われているはず。
これはmakeの動きとしては当然である。
依存関係ツリーの下位から順番に構築している中で、更新されるファイルがあるはずだからだ。


しかし、事態はそう簡単ではない。
推論2を否定する実験結果を示そう。

(実験3)

all: a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b
    @touch b
    @touch a

c:
    @echo -n c



を実行してみる。

$ make
cba

a: b
    @echo -n a

の直前では、条件1が成立しているはずなのに「@echo -n a」が実行されている。
残念ながら、(推論2)は間違っているようだ。



では、(実験1)〜(実験3)をすべて説明できる推論として次を考える。

(推論3)
a: b
    @echo -n a

という依存関係と構築ルールがあったとき、「make開始時点のファイル a と、このルールを実行する直前のファイル b を比較する。両者とも存在し、 a の方が新しい」(これを以下、条件2と呼ぶ)が成立すると、構築ルールを実行しない。
それ以外の時は、構築ルールを実行する。

さて、この推論が正しいかどうか実験してみる。


(実験4)

all: a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b
    @touch -t 201207021200 b
    @touch -t 201207021300 a

c:
    @echo -n c



$ touch -t 201207021159 a
$ make
cba
$ rm b
$ touch -t 201207021201 a
$ make
cb


make を実行前のファイルaの時刻が11時59分なら、条件2が成立しないので、「@echo a」を実行している。
一方、ファイルaの時刻が12時01分なら、条件2が成立するので、「@echo a」を実行しない。
Makefileの中で、ファイルaの時刻を13時に更新しているが、これは見ていない。
これは(推論3)を支持する結果である。


(実験5)

all: a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b

c:
    @echo -n c
    @rm a



$ touch b
$ touch a
$ make
cb

途中で、ファイル a は消されているにもかかわらず、「@echo -n a」は実行されていない。
make開始時点で a が存在しているかどうかしか見ていないから。



実験5を書きかえて、以下のようにしてみる。

(実験6)

all: clean a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b

c:
    @echo -n c

clean:
    rm -f a


$ touch b
$ touch a
$ make
rm -f a
cba


これは(推論3)が間違っていることを示す結果です。

(実験7)

all: touch a
    @echo

a: b
    @echo -n a

b: c
    @echo -n b

c:
    @echo -n c

touch:
    touch b
    touch a


$ make
touch b
touch a
cb


実験6, 実験7も説明できる推論として以下を考える。

(推論4)
a: b
    @echo -n a

という依存関係と構築ルールがあったとき、「この依存関係ツリーを処理する直前のファイル a と、このルールを実行する直前のファイル b を比較する。両者とも存在し、 a の方が新しい」が成立すると、構築ルールを実行しない。
それ以外の時は、構築ルールを実行する。


いろいろ実検してたが、makeが構築ルールを実行するかどうかの判断は結構複雑のようだ。
実装コードを見ずに、実検してみた限りでは、(推論4)のようになっていると思うのだが。。