2009年11月8日日曜日

【make】2 ルール(その1)

やってみると、やっぱりmakeはルールベースプログラミングでありDSLなんだなぁ、ということをあらためて感じる。


* 2 ルール
- ルールにはいくつかの種類がある。
- 'GNU make'は'make'と互換性がある。
- ルールの書き方について、'GNUM make'は'make'を進
化させて、使いやすくした部分がある。

** 2.1 明示的ルール

ターゲットは複数行にわけたり、単一行にまとめたりできる。

hoge.o piyo.o: puyo.h ponyo.h moge.h

これは、

hoge.o: puyo.h ponyo.h moge.h
piyo.o: puyo.h ponyo.h moge.h

これと等価。

hoge.o: puyo.h ponyo.h moge.h

これは、

hoge.o: puyo.h ponyo.h
hoge.o: moge.h

これと等価。

*** 2.1.1 ワイルドカード
- makeのワイルドカードは、Bournese Shellと同じ記
法。
- ワイルドカードは、makeのどの項にも使える。
- ワイルドカードの展開は、ターゲットと前提条件に
ついてはmakeが実施し、コマンドについてはシェル
が実行する。

例。
------
hoge: *.c
gcc -o $@ $^
------

- ワイルドカードは、シェルと同じように展開されて
から解釈される。なので、

*.o : piyo.h

というルールは、まだobject fileがひとつも存在し
ないディレクトリにおいては、

------
: piyo.h
------

となってしまう。

*** 2.1.2 疑似ターゲット

- 疑似ターゲット(phony target)なるものあり。
- これは、ターゲットで指定した名前のファイルは存
在しない。すなわち、そのターゲットのコマンドは
ターゲット名のファイルを生成しないようなもので
あること。

例。
------
clean:
rm -f *.o
------

- これだけだと、cleanってファイルが間違って存在し
てしまったら、'make clean'してもこの掃除処理は
実行されなくなってしまう。
- なのでこうする。

------
.PHONY: clean
clean:
rm -f *.o
------

- 応用。疑似ターゲットはmakefile内でのプロシージャ
呼び出しみたいに使える。

------
.PHONY: clean
clean: hoge
rm -f *.o

hoge:
ls -l *.o
------

- 疑似ターゲットは、エイリアス的にもつかえる。使
い勝手が向上する。

------
.PHONY: task-a
task-a: jugemujugemugokounosurikirekaijarisuigyo

jugemujugemugokounosurikirekaijarisuigyo: hoge.h piyo.h
gcc -o $@ $^
------

- よくある疑似ターゲット

| ターゲット | 意味 |
|------------+--------------------------------------------------|
| all | アプリケーションを構築するすべての作業を行う |
| install | 構築したアプリケーションをシステムに配置する |
| clean | 構築したアプリケーションを削除する |
| distclean | 配布状態に含まれていないものをすべて削除する |
| TAGS | TAGSを作成する |
| info | Texinfoのソースからinfoファイルを作成する |
| check | アプリケーションに関するすべてのテストを実施する |


*** 2.1.3 空のターゲット

- 疑似ターゲットは常に「最新ではない」と判断され
る。そのため、指定されれば常に実行される。
- なので、指定したときは常に実行される処理にはよ
い。
- 指定とは別に実行するかしないかを制御するにはどう
するか。それを制御するために、touchで時刻を更新
するファイルを利用すればよい。

- 例えば、次のようにするとhoge.cが更新されたときだ
け、piyoが実行される。

------
hoge: piyo hoge.c
gcc hoge.c -ohoge

piyo: hoge.c
size $^
touch size
------

** 2.2 変数

- 変数の基本的なかきぶりは次のとおり。

$(variable-name)

- bashでは、これはcommand substitutionだな。bash
での変数参照は、${PATH}などのcurly bracket。
bashとmake、揃えてくれればいいのに、ややこし
い。。。

*** 2.2.1 自動変数

- 自動変数は、実行ルールが決定した後に、makeが自
動的にその値を設定する。

- 自動変数の一覧

| 形式 | 意味 |
|------+------------------------------------------------------------------|
| $@ | ターゲット文字列 |
| $% | ターゲット文字列の一部。"hoge(piyo)"ならpiyo。 |
| $< | 最初の前提条件 |
| $? | 前提条件のうち、ターゲットよりも新しいもの達をスペース区切りで |
| $^ | 前提条件すべてをスペース区切りで。重複しないようにダブリを削除。 |
| $+ | 前提条件すべてをスペース区切りで。重複しないようにダブリあり。 |
| $* | ターゲット文字列の一部。通常は、suffixを削除したもの。 |

- 自動変数のテストmakefile

これでひととおりの挙動の確認ができる。

------
# 行頭に'#'を置くとその行はmakeのコメント行。行頭以外の置き方もあるがそれは後述。

### このプログラムの動かし方
#
# ファイルの一括削除
# make distclean
#
# 必要ファイルの作成
# make all
#
# すべてのテストを実行
# make check

### ルールの構文 (簡略版2)
# target1 target2 ... targetN : prerequiste1 prerequiste2 ... prerequisteM
# command1
# command2
# ...
# commandK

### コメントについて
# commandを書くゾーンは、行頭の'#'はmakeのコメント
# であり、それ以外はshellに渡される。それがコメント
# かどうかはshellが判断する。それ以外のゾーンでは、
# 行頭ではなくても'#'があればそれ以降はmakeのコメン
# ト。

.PHONY: all # この行はallが疑似ターゲットであることを指定している。
all: update-file1 update-file2 update-file3 hoge.c piyo.c foolib(hoge.c) foolib(piyo.c)

# phonyはまとめて指定できる。
.PHONY: check distclean update-file1 update-file2 update-file3 \
update-hoge update-piyo \
test-\# test-@ test-percent test-< test-? test-? test-^ test-+ test-*.c
# '\'でmakeの継続行になる。commandゾーンであれば
# shellにわたり、shellの継続行となる。

check: test-\# test-@ update-hoge test-percent test-< test-? test-? test-^ test-+ test-*.c

distclean:
rm -f file1 file2 file3 \
hoge.c piyo.c foolib

update-file1:
touch file1

update-file2:
touch file2

update-file3:
touch file3

update-hoge:
touch hoge.c

update-piyo:
touch piyo.c

hoge.c:
echo '#include ' > hoge.c

piyo.c:
echo '#include ' > piyo.c

# ar なarchiveについてはその構成ファイルを指定する
# ことができる。これは実戦的には.a形式のためのもの。
foolib(hoge.c): hoge.c
# $%
ar cr foolib hoge.c
## foolib(hoge.c) end
## next test maybe start

foolib(piyo.c): piyo.c
# $%
ar cr foolib piyo.c
## foolib(piyo.c) end
## next test maybe start

test-\#:
# これはmakeのコメント。commandゾーンだがshellに渡されない。
# これはmakeとしてはcommand。shellはコメントと解釈する。
## test-# end
## next test maybe start

test-@:
# ターゲット文字列(すなわちファイル名)
# $@
## test-@ end
## next test maybe start

test-percent: foolib(hoge.c) foolib(piyo.c)
## test-percent end
## next test maybe start

test-<: file1 file2 file3
# 最初の前提条件
# $<
## test-< end
## next test maybe start

test-?: update-file3 file1 file2 file3
# 前提条件のうち、ターゲットよりも新しいもの達をスペース区切りで。
# $?
touch test-\?
## test-? end
## next test maybe start

test-^: file1 file2 file3 file1
# 前提条件すべてをスペース区切りで。重複しないようにダブリを削除。
# $^
## test-^ end
## next test maybe start

test-+: file1 file2 file3 file1
# 前提条件すべてをスペース区切りで。重複しないようにダブリあり。
# $+
## test-+ end
## next test maybe start

test-*.c:
# ターゲット文字列の一部。通常は、suffixを削除したもの。
# $*
## test-*.c end
## next test maybe start
------

- 自動変数の修飾子

- ここまでのところ、makefileもソースファイルも
バイナリファイルも同一のディレクトリの同一階
層にあることを前提としている。
- しかし、makeは同一ディレクトリの中のサブディ
レクトリにあるファイルも扱える。(後で出てくる
はず)
- するとターゲットはパスを含むものもOK。
(hoge/piyo/puyo.c)など。

- この形式のターゲットのために、自動変数の修飾
子'D'と'F'がある。

例。

-------
all: dist/src/hoge.c

dist/src/hoge.c:
# target : $@
# target (directory part) : $(@D)
# target (file part) : $(@F)
-------


こつこつ。

2009年11月6日金曜日

【make】 1 簡単なメイクファイルを書いてみよう


* 1 簡単なメイクファイルを書いてみよう

** 1.1 ターゲットと必須項目

- makefileにはプログラムを構築するためのルールを
記述する。
- ルールは、target、prereq (前提項目)、commandsの
3つから構成される。
- ルールの構文は次のとおり (簡略版1)。

target: prereq1 prereq2 ... prereqn
commands

例1
------
hello: hello.c
gcc hello.c -o hello
------

例2
------
foo.o: foo.c foo.h
gcc -c foo.c
------

例3
------
bar: bar.o lexer.o -lfl
gcc -c bar.o lexer.o -lfl -obar
------

- makeは、gccと同じように、-lにてリンクする
システムライブラリを表現できる。
- makefileの先頭にあるルールをデフォルトルールと
呼ぶ。
- makeの引数にはターゲットを書く。対応するルール
が実行される。
- 引数なしで起動した場合はデフォルトルールが実行
される。
- commandsはサブシェルに渡される。

** 1.2 依存関係の検証

- GNU make は、ターゲットと前提条件の連鎖を辿り、
指定されたターゲットを作成するために必要な作業
を特定して、実行する。

** 1.3 再構築作業を最小にする

- makeは、ターゲットファイルが存在する場合、ターゲッ
トファイルと前提条件ファイル達の更新日時を比較し
て、前提のなかにターゲットよりも新しいものがある
ときだけ、Commandsを実行する。

** 1.4 makeの実行

- ここまでの前提。
- makeのルールを記述したファイルは次のいずれか
である。
- makefile
- Makefile
- GNUMakefile
- ファイルはすべて同一ディレクトリにある。
- そのディレクトリにてmakeを実行する。

** 1.5 makefileの基本文法

- ルールの構文 (簡略版2)

target1 target2 ... targetN : prerequiste1 prerequiste2 ... prerequisteM
command1
command2
...
commandK

- commandの前はタブです。
- コメント文字は'#'。
- '\'でcommandを次行に継続できる。(シェルと同じ)


こつこつ。

makeの勉強

makeの基礎を一通り勉強してみることにした。

GNU Make

やっぱりmakeはいまだいろいろなところで使われている。
ASDFとかrakeとかantとか、もっと便利な選択肢はあるんだけど、やはり読めるくらいの理解は有用な気がする。

ブログには、要点メモをアップしていこうと思う。
この要点メモだけで、makeの基礎を習得できるようなものにできたらいいなぁ。

こつこつ。

英語の勉強

英語の勉強を、その後もちょこちょこ続けている。教材はロゼッタワールド。まだ途中なのですが、現時点での所感を少し。

  • ロゼッタワールドは、よい教材。
  • だいぶ上達したはず。まず、映画にしてもニュースにしても大抵のものは聞き取れるようになった。
  • しかし、しゃべる方を、ロゼッタワールドだけで習得するのはきついかもしれない。
  • というのは、ロゼッタワールドでしゃべる練習をしていると、やはり日本語にはない発音が山のようにあることに自然に気づく。
  • 聞きとることはできるのだが、その音を自分の口で発音することができない。いろいろ口の形や舌の動き等を試行錯誤してやってみるのだが、やたら時間がかかる。単語ひとつの発音ができるようになるのに5時間くらいかかったりする。
  • 子供だとこのモノマネ試行錯誤でも素早く習得できるのかもしれないが、大人にとっては効率が悪いような。
  • なので、英語独特の発音について、口舌の動きや呼気について解剖解説したものを併用した方がよい。
  • そこで次のものを試している。
    英語の発音がよくなる本

こつこつ。

2009年11月4日水曜日

UbuntuとDebianではEmacs22は別パッケージング

Emacs22のソースをしらべていたら差異があった。

なんと、forkしている。

https://wiki.ubuntu.com/MichaelOlson/WhyDifferentEmacs

ただ、lennyとinterpidでは、documentの分離とかに違いはないような?、なんだけどpatchesが微妙に違う。

add-onなelispについてはどちらもdebian emacs policy準拠なようだ。

そこで、debian emacs policyを仕様としては参照しつつ、パッケージは日頃使っているUbuntuで探ってみることにする。

Emacs22 の起動処理

仕事でやっていることが、勉強とだんだんかぶってきた。
ごりごりやっているのだが、ここに書けない。。。これはどうしたらよいか考えてみる。
さて、仕事とは無関係なこととして、Emacs22の環境整備をはじめた。まず、起動プロセスの調査から。


** Emacs22の起動プロセス

- infoに情報あり。Elisp, 39.1 Starup Emacs。
- 詳細を知るにはソースを読む。次のものがメイン。
- configure
- src/emacs.c
- lisp/loadup.el
- lisp/startup.el
- 呼び出しというか実行順はこんな感じ。
call src/emacs.c
...
load lisp/loadup.el
...
load lisp/startup.el
...
load lisp/loaddefs.el
...
load lisp/site-load.el
...
load lisp/site-init.el
call normal-top-level (eval top-level)
[normal-top-level (startup.el)]
...
call command-line (startup.el)
...
...
call Frecursive_edit (keyboard.c)

- loadup.elに含まれるものは、通常、temacsによっ
てdumpされ、emacsのイメージに含まれている。
昔はマシンのスピードが遅かったので、
site-load.elやsite-init.elをカスタマイズした
上で、自分用のイメージをdumpしていた。今はマ
シンのスピードが速いので、これらを使うのは得
策ではない。

- ここでは、EmacsおよびElisp librariesのデプロイ
を検討するための基礎情報に重点を置く。


0-1. 標準ライブラリパス

the standard library path.

- Emacsのcompile時にデフォルト値を決定。

- サイトのライブラリの置き場所として(デフォルト
では)、

- `/usr/local/share/emacs/VERSION/site-lisp'
- `/usr/local/share/emacs/site-lisp'

が設定される。前者はemacsのVERSIONに特化したも
の。後者はVERSIONに関わらないもの。

しかし、サイトのライブラリの置き場所だけでなく
設定ファイルの置き場所も兼ねている。configure
の中は次のとおり。

ac_default_prefix=/usr/local
# prefixを確定する機構
datarootdir='${prefix}/share'
datadir='${datarootdir}'
lispdir='${datadir}/emacs/${version}/lisp'
locallisppath='${datadir}/emacs/${version}/site-lisp:'\
'${datadir}/emacs/site-lisp'
lisppath='${locallisppath}:${lispdir}:${datadir}/emacs/${version}/leim'

- Emacs内では'load-path'変数にてこの値は管理され
る。よって、起動の途中でこの変数の値が変更され
れば、それ以降は変更された値が有効になる。

- debianのコンパイルではどういう設定になっている
かは要調査。


0-2. system type

- Emacsのcompile時に決定。
- emacs.cにて定義。

----
DEFVAR_LISP ("system-type", &Vsystem_type,
doc: /* Value is symbol indicating type of operating system you are using.
Special values:
`gnu/linux' compiled for a GNU/Linux system.
`darwin' compiled for Darwin (GNU-Darwin, Mac OS X, ...).
`macos' compiled for Mac OS 9.
`ms-dos' compiled as an MS-DOS application.
`windows-nt' compiled as a native W32 application.
`cygwin' compiled using the Cygwin library.
`vax-vms' or
`axp-vms' compiled for a (Open)VMS system.
Anything else indicates some sort of Unix system. */);
----


1-1. サブディレクトリ

subdirectories.

- loadup.elの所作。
- lispディレクトリのサブディレクトリを設定する。
設定するのはつぎのもの。
- emacs-lisp
- language
- international
- textmodes


1-2. サブディレクトリ

subdirectories.

- normal-top-level関数(startup.el)の所作。
- load-pathに含まれている各ディレクトリについて、
そこにsubdirs.elまたはleim-list.elがあれば、そ
れを実行する。通常subdirs.elには、関数
normal-top-level-add-subdirs-to-load-pathの呼
び出しがあり、そこにあるサブディレクトリを
load-pathに追加する。


2. ウィンドウシステムの初期化

loading the initialization library for the
window system.

- a windows systemでEmacsを起動しているなら、
`term/WINDOWSYSTEM-win.el'をloadする。

3. 言語環境と端末コーディング

the language environment and the terminal
coding system.

- Infoの説明では、これはウィンドウシステムの初
期化の前だが、sourceだと順番が逆。
- normal-top-level関数(startup.el)が、
set-locale-environment関数
(international/mew-cmds.el)を呼び出すことによ
り実現。

3-2. ユーザの特定

- comman-line関数 (startup.el) の所作。
- 環境変数などにアクセスするための基礎として、
userを特定する。


4. 初期化オプションの処理 (後半)

- comman-line関数 (startup.el) の所作。

- emacs.cが前半処理を実施。それはloadup.el部分
に入るまえに実施される。

5. before-init-hook

- Infoでは5と6は逆。sourceではこの順番。

- comman-line関数 (startup.el) の所作。
- before-init-hookを実行する。


6. ウィンドウフレームとフェイス

- comman-line関数 (startup.el) の所作。
- ウィンドウフレームとフェイスを初期化する。


7. site-start.elの特定とload

- comman-line関数 (startup.el) の所作。

- 標準ライブラリパスを順番に探す。みつかったとこ
ろで探索をやめ、それをload する。
- '--no-site-file'を起動オプションに指定すると、
このファイルはloadされない。


8. ユーザのInit Fileの特定とload

- comman-line関数 (startup.el) の所作。

ここで特定したホームディレクトリへのパスを"~"で
あらわす。
- 次の順でInit Fileを探す。みつかったところで探
索をやめて、みつかったものをloadする。

a. '~/.emacs'
b. '~/.emacs.elc'
c. '~/.emacs.el'
d. '~/.emacs.d/init.elc'
e. '~/.emacs.d/init.el'

- '-q'すなわち'--no-init-file'を起動オプションに
指定すると、このファイルはloadされない。
- また'-Q'すなわち'--batch'を起動オプションに指
定すると、このファイルはloadされない。
- '-u'にてユーザを指定すると'~'はそのユーザのホー
ムディレクトリを参照するためInit Fileが変更さ
れる。
- load関数の機構なら、'~/.emacs.d/init'も探索対
象になるはずだが、どうなのか。(要調査)


9. サイトのdefault.elの特定とload

- comman-line関数 (startup.el) が支配。

- 標準ライブラリパスを順番に探す。みつかったとこ
ろで探索をやめ、それをloadする。
- '-q'すなわち'--no-init-file'を起動オプションに
指定すると、このファイルはloadされない。
- 変数'inihibit-default-init'がnon-nilだと、こ
のファイルはloadされない。


10. after-init-hook

- comman-line関数 (startup.el) の所作。
- after-init-hookの実行。


11. initial-major-mode

- comman-line関数 (startup.el) の所作。
- *scratch*がまだfundamental-modeなら、
initial-major-mode関数を呼び出してこれを変更。


12. TERMTYPEの特定とterm/TERMTYPEのload

- normal-top-level関数 (startup.el) の所作。
- 次の手順で特定しloadする。

a. (getenv "TERM")にて環境変数TERMの値を得る。
b. aで得た文字列について、一番最初のハイフン以前
の値をTERMTYPEとする。例えば、TERMが'aaa-48' な
らば、TERMTYPEは'aaa'。
c. term/TERMTYPEがloadすべきファイルとなる。こ
れを標準ライブラリパスから探してloadする。

- 変数term-file-prefixがnilだと、このファイルは
loadされない。


13. initial echo area message

- これはsourceには無いような?


14. processing the action arguments

- これもsourceには無いような?


15. emacs-startup-hook, term-setup-hookの実行

- normal-top-level関数 (startup.el) の所作。

- emacs-startup-hookの実行。
- term-setup-hookの実行。


16. frame-notice-user-settings

- normal-top-level関数 (startup.el) の所作。
- user-settingsが有効になるようにnoticeをかける。


17. window-setup-hookの実行

- normal-top-level関数 (startup.el) の所作。
- window-setup-hookの実行。


18. initial scratch message、display startup screenの表示

- normal-top-level関数 (startup.el) の所作。
- 画面にメッセージ表示。



** Emacs22のloadとrequire

*** load

(load FILE &optional NOERROR NOMESSAGE NOSUFFIX MUST-SUFFIX)

FILEに含まれているLisp codeを実行する。
load-suffixes変数に定義されている順にsuffixをFILE
にファイルを探す。最後にsuffixをつけないでFILEその
ままで探す。探す対象ディレクトリはload-path変数に
含まれているもの。

*** autoload

(autoload FUNCTION FILE &optional DOCSTRING INTERACTIVE TYPE)

FUNCTIONが呼び出されたら、FILEをloadする。
DOCSTRINGを書けば、未load状態でもFUNCTIONの説明を
表示することができる。

autoload cookie `;;;###autoload' を関数定義の直前
に書いておくと、update-file-autoloads関数によって、
その関数に対するautoloadがloaddefs.elに追加される。

*** require

(require FEATURE &optional FILENAME NOERROR)

FEATUREがload済みでなければ、それをFILENAMEから
loadする。FEATUREがfeatures変数の値(list)に含まれ
えていないなら、loadは実行されない。

FILENAMEが省略されている場合は、FEATUREのprint name
(おそらくシンボルの印字名)がFILENAMEの代替となる。

*** provide

(provide FEATURE &optional SUBFEATURES)

FEATUREがこのEmacsの a feature であることを周知す
る。SUBFEATURES はシンボルのリスト。このFEATUREに
付随して実現されている features を周知する。

*** package

Emacs22にCLのようなpackageシステムは存在しない。

2009年10月31日土曜日

復活

10月は体調不良に苦しんだが、なんとかカムバックできた。。。

勉強再開だ!