メモ置き場

メモ置き場です.開発したものや調べたことについて書きます.

[tex: ]

お気に入りMakefile

普段使っているMakefileは以下の通り.

CC = g++
CFLAGS = -std=c++11
LDFLAGS = 
LIBS = 
INCLUDE = -include ./include
SRC_DIR = ./src
OBJ_DIR = ./obj
BIN_DIR = ./bin

SRC_SUF = .cxx
OBJ_SUF = .o
DIP_SUF = .d
BIN_SUF =

TARGET = run

SOURCES = $(shell ls $(SRC_DIR)/*$(SRC_SUF)) 
OBJS = $(subst $(SRC_DIR),$(OBJ_DIR), $(SOURCES:$(SRC_SUF)=$(OBJ_SUF)))
TARGETBIN = $(addprefix $(BIN_DIR)/, $(TARGET))
DEPENDS = $(OBJS:$(OBJ_SUF)=$(DIP_SUF))

all: $(TARGETBIN)
    $(TARGETBIN): $(OBJS) $(LIBS)
    @if [ ! -d $(BIN_DIR) ]; \
        then echo "mkdir -p $(BIN_DIR)"; mkdir -p $(BIN_DIR); \
    fi
    $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)


$(OBJ_DIR)/%.o: $(SRC_DIR)/%$(SRC_SUF)
    @if [ ! -d $(OBJ_DIR) ]; \
        then echo "mkdir -p $(OBJ_DIR)"; mkdir -p $(OBJ_DIR); \
    fi
    $(CC) $(CFLAGS) $(INCLUDE) $(LDFLAGS) -o $@ -c $<

clean:
    $(RM) -rf $(OBJ_DIR) $(BIN_DIR) $(DEPENDS)

-include $(DEPENDS)

説明

Makefileの基本的な構文は

<task> : (必要なファイル)
    シェルで実行したいコマンド

の形を取っている.taskを実行するのに必要なファイルがあった場合,それを作成するためのタスクが先に呼ばれて…となる.たとえば

aho : 
    echo "aho"

というMakefileを作って

$ make aho
aho

と返ってくる.この場合は必要なファイルがないのでahoのコマンドだけが実行される.先頭に@をつけるとコマンドの結果を標準出力に出さない様にできる.if文みたいに改行するようなコマンドだと,\をつける必要がある.コマンドのところで改行すると,別々のコマンドと解釈される.

変数の設定もできて上の例だとCC=g++みたいなところがそう.
変数に値を追加して行くこともできて

hoge = fuga1
hoge += fuga2
hoge += fuga3

などもできる.変数のアクセスは$(hoge)とすればよい.

SOURCES = $(shell ls $(SRC_DIR)/*$(SRC_SUF)) 

$(shell ...)とすると,シェルの結果を変数に代入できる.上の場合だと,

ls ./src/*.cxx

の結果がSOURCESに入る.ちなみに上のMakefileではSOURCES変数は書いたけど使っていない.

OBJS = $(subst $(SRC_DIR),$(OBJ_DIR), $(SOURCES:$(SRC_SUF)=$(OBJ_SUF)))
TARGETBIN = $(addprefix $(BIN_DIR)/, $(TARGET))

substとかaddprefixはMakefileで使える関数.他にもたくさんある.

subst $(from), $(to), $(text)

では$(text)の$(from)を$(to)に置換.上記例だと$(text)は

$(SOURCES:$(SRC_SUF)=$(OBJ_SUF))

になっている.

$(hoge:$(old)=$(new))

で,$(hoge)の$(old)を$(new)に置き換えることになる.

addprefix $(add), $(to)

で$(to)に$(add)を追加できる.

想定した使い方

作業ディレクトリにMakefileとsrcディレクトリ,includeディレクトリを作成.srcにはプログラムの本体,includeにはヘッダファイルが入っている.
makeをすると,objディレクトリ,binディレクトリが作成されそれぞれにオブジェクトファイルとバイナリファイルができる.
make cleanすると,src,includeディレクトリだけ残して削除される.
TARGETが複数ある場合は使えない.どうやるかは調べてできたら追記して行く.