C
Make
unittest
gcov

なんでもmake xxxで済ませたい

More than 1 year has passed since last update.

シンプルなC言語のプロジェクトを作ってみる
目的は、とりあえず、何をするにもmake xxxで済ませたい。

http://qiita.com/tksmiura/items/0a77e5c301532ae30c9a
の続き

http://qiita.com/szkny/items/07b4c93702b3f8090fa3
あたりを参考にして

ut_*.c という名前のソースをテストプログラムとしてビルドして実行する。(make のwildcardを利用するのでファイルを増やしてもMakefileの変更は不要)

make testとかmake gcovとか実行するビルドして、テストやカバレッジを取ってくれる。

% make test
cc -o ut_main ut_main.c
cc -o ut_sub ut_sub.c
result ut_main.c 3/3 
result ut_sub.c 0/0

make debugと実行するとデバッグビルドしてgdbの起動まで行う。

http://www.ne.jp/asahi/hishidama/home/tech/unix/cmd/make2.html
あたりを参照

プロジェクト全体は、
https://gist.github.com/tksmiura/fc273ba726ed380dcd5bf6488c24c553

にあげておきます。

#TARGETS
PROGRAM = main
DEBUG_TARGET = main_debug
HEADERS = $(wildcard *.h)
SRCS = main.c
TEST_SRCS = $(wildcard ut_*.c)
TESTS = $(basename $(TEST_SRCS)) 
GCOV_TESTS = $(TEST_SRCS:.c=_gcov)

# ENVIRONMENT
CC ?= gcc
CFLAGS ?= -Wall -O2
DEBUG_OPTION ?= -O0 -g
DEBUGGER = gdb -tui
GCOV = gcov

# suffixes
.SUFFIXES: .c .o .debug_o

#default target
all: $(PROGRAM)

#
# target
#

# サフィックスルール
.c.o:
    $(CC) $(CFLAGS) -c $<

#依存関係
define MAKEOBJECTS
$(1:.c=.o): $(1) $(HEADERS)
endef
$(foreach VAR,$(SRCS),$(eval $(call MAKEOBJECTS,$(VAR))))

$(PROGRAM): $(SRCS:.c=.o)
    $(CC) -o $(PROGRAM) $^

#
# debug(gdb)
#
.c.debug_o:
    $(CC) $(CFLAGS) $(DEBUG_OPTION) -o $@ -c $<

#依存関係
define MAKEDEBUG
$(1:.c=.debug_o): $(1) $(HEADERS)
endef
$(foreach VAR,$(SRCS),$(eval $(call MAKEDEBUG,$(VAR))))


$(DEBUG_TARGET): $(SRCS:.c=.debug_o)
    $(CC) -o $@ $^

.PHONY: debug
debug: $(DEBUG_TARGET)
    $(DEBUGGER) $^

#
# unit test 
#

# targets for test
define MAKETARGETS
$(1): $(1).c $(HEADERS)
    $(CC) -o $(1) $(1).c
endef
$(foreach VAR,$(TESTS),$(eval $(call MAKETARGETS,$(VAR))))

.PHONY: test
test: $(TESTS)
    @for test in $(TESTS) ; do \
        ./$$test ;\
    done

#
# gcov
#

# target gov (unit test only) 
define MAKETARGETS_GCOV
$(1)_gcov: $(1).c
    $(CC) -o $(1)_gcov --coverage $(1).c
endef
$(foreach VAR,$(TESTS),$(eval $(call MAKETARGETS_GCOV,$(VAR))))

.PHONY: gcov
gcov: $(GCOV_TESTS)
    @for test in $(GCOV_TESTS) ; do \
        ./$$test ;\
    done
    $(GCOV) -b $(TEST_SRCS:.c=.gcda)

#
# clean
#
.PHONY: clean
clean:
    $(RM) $(PROGRAM) $(DEBUG_TARGET) $(TESTS) $(GCOV_TESTS)
    $(RM) $(SRCS:.c=.o) $(SRCS:.c=.debug_o) 
    $(RM) *.gcda *.gcno *.gcov 

全体的に手抜きなので、ヘッダはwildcardで*.hを検索し、

HEADERS = $(wildcard *.h)

どれかが変更されれば、リビルドされるように設定。
(defineでルールを定義してforeachで展開)

#依存関係
define MAKEOBJECTS
$(1:.c=.o): $(1) $(HEADERS)
endef
$(foreach VAR,$(SRCS),$(eval $(call MAKEOBJECTS,(VAR))))

実際、#includeしてない場合も考えられますが、いちいち依存関係を記述する手間を省くため。こうしています。

デバッグ用のオブジェクトを*.debug_oとしているは自分でもどうかと思っていますが、フォルダ分けとかも面倒な感じなのでこうしています。