AVR ライブラリ開発用 Makefile

#1. これは何？ 何ができるの？

　Atmel 社製のマイコンチップ， 8 bit AVR シリーズ用のライブラリを開発する際に私が使っている Makefile です。 src ディレクトリ内のソースファイルを自動検索してコンパイルし，できたオブジェクトをライブラリファイルに束ねるだけのシロモノです。

#2. とりあえず晒す

　なにはともあれ，とりあえず晒します。 コメントとかは書いていないのでわかりづらいと思いますが，何卒ご容赦ください。

```mf:Makefile
#------------------------------
# Configurations
#------------------------------
ENV = Windows

TARGET = libavr8.a
TARGETDIR = ./lib

INCDIR = ./include
ifneq ($(INCDIR),)
  INCLUDES = -I $(INCDIR)
endif

SRCDIR = ./src
SRCSUFFIX = %.c

OBJDIR = ./obj
OBJSUFFIX = %.o

DEPSUFFIX = %.d

#------------------------------
# Commands and Options
#------------------------------
MKDIR = mkdir -p
RM = rm -rf
ifeq ($(ENV),Windows)
  MKDIR = mkdir
  RM = del /q /s
endif

CC = avr-gcc
CFLAGS = -Wextra -Wall -O2 -MMD -MP -c

AR = avr-ar
ARFLAGS = rcs

ifeq ($(TARGETDIR),)
  TARGETDIR = ./
  PROGRAM = $(TARGET)
else
  PROGRAM = $(TARGETDIR)/$(TARGET)
endif

ifeq ($(ENV),Windows)
  SRCDIRFILES = $(shell dir /s /b $(subst /,\,$(SRCDIR)))
  SRCDIRFILES := $(patsubst $(shell cd)\\%,./%,$(SRCDIRFILES))
  SRCDIRFILES := $(subst \,/,$(SRCDIRFILES))
else
  SRCDIRFILES = $(shell find $(SRCDIR))
endif

SRCS = $(filter $(SRCSUFFIX),$(SRCDIRFILES))
OBJS =  $(patsubst $(SRCDIR)%,$(OBJDIR)%,$(SRCS))
OBJS := $(patsubst $(SRCSUFFIX),$(OBJSUFFIX),$(OBJS))
DEPS =  $(patsubst $(OBJSUFFIX),$(DEPSUFFIX),$(OBJS))

OBJDIRS = $(dir $(OBJS))

ifeq ($(ENV),Windows)
  MKTARGETDIR = $(MKDIR) $(subst /,\,$(TARGETDIR))
  MKOBJDIRS   = $(MKDIR) $(subst /,\,$(OBJDIRS))

  RMPROGRAM = $(RM) $(subst /,\,$(PROGRAM))
  RMOBJDIR  = $(RM) $(subst /,\,$(OBJDIR))
else
  MKTARGETDIR = $(MKDIR) $(TARGETDIR)
  MKOBJDIRS   = $(MKDIR) $(OBJDIRS)

  RMPROGRAM = $(RM) $(PROGRAM)
  RMOBJDIR  = $(RM) $(OBJDIR)
endif


#------------------------------
# Processes
#------------------------------

all: create-dirs $(TARGET)

create-dirs:
	@echo Create directories
ifneq ($(TARGETDIR),)
	@[ -d $(TARGETDIR) ] || $(MKTARGETDIR)
endif
ifneq ($(OBJDIRS),)
	@[ -d "$(OBJDIRS)" ] || $(MKOBJDIRS)
endif

$(TARGET): $(OBJS)
	$(AR) $(ARFLAGS) $(PROGRAM) $(OBJS)

$(OBJDIR)/%.o: $(SRCDIR)/%.c
	$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^

clean:
	@$(RMPROGRAM)
	@$(RMOBJDIR)

#------------------------------
# Check variables
#------------------------------

check-vars:
	@echo ENV         = $(ENV)

	@echo TARGETDIR   = $(TARGETDIR)
	@echo INCDIR      = $(INCDIR)
	@echo SRCDIR      = $(SRCDIR)
	@echo OBJDIR      = $(OBJDIR)

	@echo TARGET      = $(TARGET)

	@echo INCLUDES    = $(INCLUDES)

	@echo SRCSUFFIX   = $(SRCSUFFIX)
	@echo OBJSUFFIX   = $(OBJSUFFIX)
	@echo DEPSUFFIX   = $(DEPSUFFIX)

	@echo MKDIR       = $(MKDIR)
	@echo RM          = $(RM)

	@echo CC          = $(CC)
	@echo CFLAGS      = $(CFLAGS)

	@echo AR          = $(AR)
	@echo ARFLAGS     = $(ARFLAGS)

	@echo PROGRAM     = $(PROGRAM)

	@echo SRCDIRFILES = $(SRCDIRFILES)
	@echo SRCS        = $(SRCS)
	@echo OBJS        = $(OBJS)
	@echo DEPS        = $(DEPS)

	@echo OBJDIRS     = $(OBJDIRS)

	@echo MKTARGETDIR = $(MKTARGETDIR)
	@echo MKOBJDIRS   = $(MKOBJDIRS)
	@echo RMPROGRAM   = $(RMPROGRAM)
	@echo RMOBJDIR    = $(RMOBJDIR)

-include $(DEPS)
```

#3. 簡単な説明など
##3.1. 特徴
　基本的には Gmaj7sus4 さんの 「[ソースが複階層化された場合のMakefile（第五回） - ソフトウェアまわりの備忘録](http://gmaj7sus4.hatenablog.com/entry/2013/12/18/165224)」 と[前回記事](http://qiita.com/guttally/items/f8c8ba044bfba677a4be)との組み合わせです。便利な Makefile とその解説を公開してくださった Gmaj7sus4 さんに感謝です。

　src ディレクトリ配下に存在するソースファイル (*.c) を自動的に探してコンパイルします。 新しいソースファイルが追加された場合や，src 配下のディレクトリ構成が変更になった場合でも，Makefile を修正する必要はありません。 一応 Windows 環境でのみ動作確認をしていますが，環境スイッチ変数 `ENV` の値を空に設定すれば Linux などの環境でもたぶん動くと思います。

##3.2. 想定するディレクトリ構成
　上記 Makefile は以下のようなディレクトリで使用されることを想定しています。

```
work
|---include
|   |---libavr8   // 外部に公開するヘッダファイルを格納するディレクトリ
|
|---lib
|   |---libavr8.a // ターゲットとなるライブラリファイル
|
|---obj // オブジェクトファイル (*.o) と依存関係ファイル (*.d) が格納されるディレクトリ
|   |   // src 配下と同じディレクトリ構造が make create-dirs で作られる
|   ~
|---src // ソースファイル (*.c) と非公開ヘッダファイル (*.h) が格納されるディレクトリ
|   |---uasrt
|   ~   |---usart_private.h
|       |---usart_mega328p
|       ~   |---usart_mega328p.h
|           |---usart_mega328p.c
|           |---usart_mega328p_tx.c
|           |---usart_mega328p_rx.c
|
|---Makefile      // 上記の Makefile
```

##3.3. check-vars って何をしてるの？

　ビルドに関連する動作は何もしていません。 この Makefile を作るときにデバッグ目的で作ったもので，使用している変数の一覧を表示するだけです。 コンパイルやビルドには全く不要ですが，今後 Makefile を修正するときに便利そうなので残してあります。

#4. 追記
2015.1.9 13:52

* ar コマンドの引数に objs が指定されていなかった誤りを修正。
* ディレクトリ変数が空の時に上手く動作しない点を修正。