とりあえず用 Makefile

# とりあえず用 Makefile
make はビルドツールです。
私は CoffeeScript の JavaScript への変換などに make コマンドを使っています。

私が make にさせたい動作は、

    拡張子が「.coffee」のファイルがあったら、coffee コマンドでそれを JavaScript に変換する

というものです。
要は、myscript.coffee などを書いたとき、とりあえず make しておけば myscript.js が得られるようにしたいのです。

make の動作を制御するには、その設定を Makefile に記述する必要があります。
本稿は、私が使っている Makefile の紹介です。

make の詳細については以下を参照ください。
- [Manpage of MAKE](http://linuxjm.sourceforge.jp/html/GNU_make/man1/make.1.html)

## 動作環境について
Makefile は GNU make 用に記述されています。
また、make が呼び出すコマンド(例えば、coffee コマンド)は、OS にインストールされている必要があります。
私は、Ubuntu Linux で使用しているので、細部で Ubuntu に依存しているところがあるかも知れませんが、大抵の UNIX、Linux、POSIX系OS で動作すると思います。

## この Makefile について
Makefile は本稿末尾に掲載しています。
make は(デフォルト動作では)カレントディレクトリの Makefile ファイルを読み込みます。
なので、基本的には Makefile はカレントディレクトリに置いて使います。

make 実行時は引数にターゲットを指定します。
この Makefile がサポートするターゲットは以下です。

|ターゲット|説明|
|:-------|:---|
|build|成果物を生成する。例えば「myscript.coffee」があった時「myscript.js」を生成する|
|clean|成果物を消去する。例えば「myscript.coffee」があった時「myscript.js」を消去する|

ターゲットを省略した場合は「build」を指定したとみなされます。
実行例は以下です。

```shell-session
$ make                     # buildターゲット実行    (成果物を生成)
$ make clean               # cleanターゲット実行    (成果物を消去)
```

## Makefile を実行する
毎回 Makefile を作業ディレクトリにコピーするのは面倒です。
この Makefile は先頭行に shebang を記載しています。
shebang とは以下のもので、シェルスクリプトなどによく見られます。(make のパス(/usr/bin/make)は、お使いの環境と異なる場合があります)

    #!/usr/bin/make -f

これがあれば、Makefile 実行権を付与すると実行することができます。

```shell-session
$ chmod +x Makefile
$ ./Makefile                    # 実行できる。(make -f Makefile と同じこと)
```

私は以下のように環境を作っています。 

```shell-session
$ cd ~/etc/tmpl/mk/
$ ls Makefile
Makefile                             # Makefile は ~/etc/tmpl/mk に置く
$ chmod +x Makefile                  # 実行権を付与
$ cd ~/bin/
$ ln -s ~/etc/tmpl/mk/Makefile mk    # mk という名前でシンボリックリンクを作る
````

あるいは単純に以下のようにしてもいいです。

```shell-session
$ cd ~/bin/
$ ls Makefile
Makefile                             # Makefile は ~/bin/ に置く
$ chmod +x Makefile                  # 実行権を付与
$ mv Makefile mk                     # mk という名前にリネーム
```

私の環境では、~/bin に PATH を通しています。なので、上のようにすることで、「mk」とタイプすると、(Makefile を毎回コピーしなくても)この Makefile を実行することができます。

```shell-session
$ mk                     # buildターゲット実行    (成果物を生成)
$ mk clean               # cleanターゲット実行    (成果物を消去)
```

## オプション「-n」
これは参考情報です。
make にはいろいろオプションがあります。
私が一番よく使うオプションは「-n」です。
これは、実際にはターゲットを実行しませんが、どのように make が動作しようとするか見るだけのオプションです。

```shell-session
$ mk -n                 # buildターゲット実行の様子を見る (実際には成果物を生成しない)
$ mk -n clean           # cleanターゲット実行の様子を見る (実際には成果物を消去しない)
```

----
# Makefile
「xxx.coffee」を「xxx.js」に変換する以外にも以下の動作をサポートします。

| ソースファイル  | 作られるファイル   | 実行するコマンド | 説明          |
|:--------------|:----------------|:--------------|:-------------|
|xxx.coffee     | xxx.js          | coffee        |CoffeeScriptソースからJavaScriptファイルを作る|
|xxx.haml       | xxx.html        | haml          |Haml形式ファイルからHTML5文書を作る|
|xxx.xhaml      | xxx.xhtml       | haml          |Haml形式ファイルからXHTML文書を作る|
|xxx.ghaml      | xxx.goml        | haml          |Haml形式ファイルからGOML(HTML5)文書を作る|
|xxx.md         | xxx.html        | markdown      |Markdown形式ファイルからHTML5文書を作る
|xxx.less       | xxx.css         | lessc         |LESSソースからCSSファイルを作る|
|xxx.sass       | xxx.css         | sass          |SCSSソースからCSSファイルを作る
|xxx.erl        | xxx.beam        | erlc          |ErlangソースをBEAMファイルにコンパイルする|
|xxx.hs         | xxx (実行形式)   | ghc           |Haskellソースをコンパイルする|
|xxx.ml         | xxx (実行形式)   | ocamlc        |OCamlソースをコンパイルする|
|xxx.c          | xxx (実行形式)   | ${CC}         |Cソースをコンパイルする|
|xxx.cpp        | xxx (実行形式)   | ${CXX}        |C++ソースをコンパイルする|
|xxx.d          | xxx (実行形式)   | gdc           |Dソースをコンパイルする|
|xxx.m          | xxx (実行形式)   | gcc           |Objective-Cソースをコンパイルする|
|xxx.java       | xxx.class       | javac         |Javaソースをclassファイルにコンパイルする|
|xxx.scala      | xxx.class       | scalac        |Scalaソースをclassファイルにコンパイルする|
|xxx.v          | xxx (実行形式)   | iverilog      |Verilogソースをコンパイルする|
|xxx.cs         | xxx.exe         | dmcs          |C#.monoソースをexeファイルにコンパイルする|
|xxx.fs         | xxx.exe         | fsharpc       |F#.monoソースをexeファイルにコンパイルする|
|xxx.dot        | xxx.png         | dot           |DOT形式(Graphviz)ファイルからPNG画像ファイルを作る|
|xxx.ry         | xxx.rb          | racc          |Racc文法ファイルからRubyスクリプトを作る|
---
(注意)
Makefile のコマンド行の先頭はタブである必要があります。
コピー＆ペーストをするとタブの部分がスペースに置き換わってしまうかも知れません。
その場合は以下のようにしてタブを復元してください。

```shell-session
$ sed 's/^    /\t/' Makefile >tmp      # 変換するスペースは4つです (「s/^   /\t/」の部分)
$ mv tmp Makefile
```

```mf:Makefile
#!/usr/bin/make -f

#----------------------------------------------------------------------
#
# javaScript
#
COFFEE      := coffee
COFFEEFLAGS := -b
TARGETS     += ${patsubst %.coffee, %.js, ${wildcard *.coffee}}

.SUFFIXES : .js .coffee

%.js : %.coffee
    ${COFFEE} ${COFFEEFLAGS} -c $<

#----------------------------------------------------------------------
#
# HTML/XHTML/GOML
#
HAML        := haml
HAMLFLAGS   := -q
XHAMLFLAGS  := ${HAMLFLAGS}
GHAMLFLAGS  := ${HAMLFLAGS}
MARKDOWN    := markdown
MDFLAGS     :=
TARGETS     += ${patsubst %.haml,  %.html,  ${wildcard *.haml}}     \
               ${patsubst %.md,    %.html,  ${wildcard *.md}}       \
               ${patsubst %.xhaml, %.xhtml, ${wildcard *.xhaml}}    \
               ${patsubst %.ghaml, %.goml,  ${wildcard *.ghaml}}

.SUFFIXES : .html  .haml    \
                   .md      \
            .xhtml .xhaml   \
            .goml  .ghaml

%.html : %.haml
    ${HAML} ${HAMLFLAGS} $< $@

%.xhtml : %.xhaml
    ${HAML} -f xhtml ${XHAMLFLAGS} $< $@

%.goml : %.ghaml
    ${HAML} ${GHAMLFLAGS} $< $@

%.html : %.md
    echo '<!DOCTYPE html>'           >$@
    echo '<meta charset="UTF-8">'   >>$@
    echo '<title></title>'          >>$@
    echo ''                         >>$@
    ${MARKDOWN} ${MDFLAGS} $<       >>$@

#
# CSS
#
LESSC       := lessc
LESSFLAGS   :=
SASS        := sass
SCSSFLAGS   :=
SASSFLAGS   := ${SCSSFLAGS}
TARGETS     += ${patsubst %.less, %.css, ${wildcard *.less}}    \
               ${patsubst %.scss, %.css, ${wildcard *.scss}}

.SUFFIXES : .css .less  \
                 .scss

%.css : %.less
    ${LESSC} ${LESSFLAGS} $< $@

%.css : %.scss
    ${SASS} ${SASSFLAGS} $<:$@

#----------------------------------------------------------------------
#
# Erlang
#
ERLC        := erlc
ERLFLAGS    :=
TARGETS     += ${patsubst %.erl, %.beam, ${wildcard *.erl}}

.SUFFIXES : .beam .erl

%.beam : %.erl
    ${ERLC} ${ERLFLAGS} $<

#----------------------------------------------------------------------
#
# Haskell
#
GHC         := ghc
GHCFLAGS    :=
TARGETS     += ${patsubst %.hs, %, ${wildcard *.hs}}

.SUFFIXES : .hs

% : %.hs
    ${GHC} ${GHCFLAGS} -o $@ $<

#
# OCaml
#
OCAMLC      := ocamlc
OCAMLFLAGS  :=
TARGETS     += ${patsubst %.ml, %, ${wildcard *.ml}}

.SUFFIXES : .ml

% : %.ml
    ${OCAMLC} ${OCAMLFLAGS} -o $@ $<

#----------------------------------------------------------------------
#
# C/C++
#
TARGETS     += ${patsubst %.c,   %, ${wildcard *.c}}    \
               ${patsubst %.cpp, %, ${wildcard *.cpp}}

.SUFFIXES : .c  \
            .cpp

#----------------------------------------------------------------------
#
# D
#
GDC         := gdc
GDCFLAGS    :=
TARGETS     += ${patsubst %.d, %, ${wildcard *.d}}

.SUFFIXES : .d

% : %.d
    ${GDC} ${GDCFLAGS} -o $@ $<

#----------------------------------------------------------------------
#
# Objective-C
#
OBJCC       := gcc
OBJCFLAGS   :=
TARGETS     += ${patsubst %.m, %, ${wildcard *.m}}

.SUFFIXES : .m

% : %.m
    ${OBJCC} ${OBJCFLAGS} -o $@ $<

#----------------------------------------------------------------------
#
# Java/Scala
#
JAVAC       := javac
JAVAFLAGS   :=
SCALAC      := scalac
SCALAFLAGS  :=
TARGETS     += ${patsubst %.java,  %.class, ${wildcard *.java}} \
               ${patsubst %.scala, %.class, ${wildcard *.scala}}

.SUFFIXES : .class .java    \
                   .scala

%.class : %.java
    ${JAVAC} ${JAVAFLAGS} $<

%.class : %.scala
    ${SCALAC} ${SCALAFLAGS} $<

#----------------------------------------------------------------------
#
# Verilog
#
IVERILOG        := iverilog
IVERILOGFLAGS   :=
TARGETS         += ${patsubst %.v, %, ${wildcard *.v}}

.SUFFIXES : .v

% : %.v
    ${IVERILOG} ${IVERILOGFLAGS} -o $@ $<

#----------------------------------------------------------------------
#
# C#/F# (.mono)
#
DMCS        := dmcs
DMCSFLAGS   :=
FSHARPC     := fsharpc
FSHARPFLAGS :=
TARGETS     += ${patsubst %.cs, %.exe, ${wildcard *.cs}}    \
               ${patsubst %.fs, %.exe, ${wildcard *.fs}}

.SUFFIXES : .exe .cs    \
                 .fs
%.exe : %.cs
    ${DMCS} ${DMCSFLAGS} $<

%.exe : %.fs
    ${FSHARPC} ${FSHARPFLAGS} $<

#----------------------------------------------------------------------
#
# Graphviz
#
DOT         := dot
DOTFLAGS    :=
TARGETS     += ${patsubst %.dot, %.png, ${wildcard *.dot}}

.SUFFIXES : .png .dot

%.png : %.dot
    ${DOT} ${DOTFLAGS} -Tpng -o $@ $<

#----------------------------------------------------------------------
#
# Racc
#
RACC        := racc
RACCFLAGS   := -g
TARGETS     += ${patsubst %.ry, %.rb, ${wildcard *.ry}}

.SUFFIXES : .ry .rb

%.rb : %.ry
    ${RACC} ${RACCFLAGS} -o $@ $<

#======================================================================
#
# dependencies
#
.PHONY: build clean

build : ${TARGETS}

clean :
    ${RM} ${TARGETS}
```