今まで、従属規則の生成には、X11 のコマンドであるところの「makedepend」を長らく使って来た、しかし、makedepend コマンドが無い場合(X11 関係アーカイブをインストールする必要がある)
や、コンパイラがインクルードファイルを検索する挙動とは多少違う場合もあったりしていた。
そこで、「gcc」の「-MM」オプションを使ってインクルードパスを収集する方法に切り替えた。
※このコンパイラーオプションは、コンパイラー自らのパスでインクルードファイルのフルパスを出力する、この時、「#if、#endif」などの制御文なども評価する。
通常、コンパイラーは、ソースコードと同じ場所にオブジェクトを生成する、ソースコードを共有して、複数のアプリケーションを作成すると、それでは、不具合が起こる場合もあり(コンパイラーオプションや、デバッグ、リリースビルドなど)、アプリケーション毎に、生成されたオブジェクトコードを管理したい。
そこで、生成オブジェクトを特定のディレクトリーに集中させるようにした。
また、複数のアプリケーションで Makefile の修正を最小限に出来るように、多少の工夫をしてみた。
Makefile の構文を学習しなおしたり、google 先生に教えてもらった make 関係のリンクを観たりで、自分の思ったような構成に出来たので紹介する。
ディレクトリーは以下のような構成にしている。
project:
common: ---> アプリケーション共通のソースコードを格納するディレクトリー
...: ---> ソースモジュール毎のディレクトリー
... ---> ソース郡
...:
...
...:
...
xxxx: ---> xxxx アプリケーションディレクトリー
xxxx.cpp ---> xxxx アプリケーション固有のソースコード
Makefile ---> xxxx アプリケーションの Makefile
yyyy: ---> yyyy アプリケーションディレクトリー
yyyy.cpp
Makefile
・各アプリケーションで共通するソースコード郡を「common」ディレクトリーに配置している。
・アプリケーションは、専用ディレクトリーを設けて、そこで、生成された二次ファイルを格納する。
※通常、「release」、「debug」のどちらか
一番のキモは、-MM コマンドの仕様で痛い部分を回避する為の小細工で、以下のリンクを参考にした。
※スイマセン、殆ど同じような物です、VPATH の指定が追加されたくらいです。
Makefile 別ディレクトリに中間ファイル & 自動依存関係設定
この問題は、オブジェクトファイルのパスがフルパスにならない点で、これを改善する為、sed による整形を使って、回避している。
リンクの sed スクリプトでは、「.o」のマッチングが不十分で、特定のファイル名の組み合わせなどで整形を失敗する、そこで、適切に修正した。
「\.o:」「.」を「\.」にする事で、正確に「.」(ピリオド)にマッチするようになる、また、一応、セパレーター「:」を追加して、厳密にマッチするようにしてある。
※詳しくは sed の仕様、-MM の説明を参照の事
「VPATH」を指定すると、make が、ファイルを検索するルートを指定出来るので、関係ソースコードを羅列する部分がスッキリする。
・以下の例は、アプリケーション「player」の Makefile です。
・「TARGET」アプリケーション名(Windows では .exe を追加する)
・「ICON_RC」アプリケーションアイコン指定がある場合、リソースの記述を行う
icon.rcの例
EXE_ICON ICON res/player.ico
・「BUILD」ビルドディレクトリー(debug、又は、release)
※従属規則 *.d 、とオブジェクトファイル *.o が格納される。
・「VPATH」共有ソースコードのルートディレクトリー
・「CSOURCES」C 言語ソースコードのリスト
・「PSOURCES」C++ 言語ソースコードのリスト
・「STDLIBS」標準的ライブラリーのリスト
・「OPTLIBS」オプションライブラリーのリスト
・「INC_SYS」システム系のインクルードパス
・「INC_LIB」ローカルライブラリーのインクルードパス
※従属規則に含まれない
・「PINC_APP」C++ 言語用、インクルードパス
・「CINC_APP」C 言語用、インクルードパス
※従属規則に含まれる
・「LIBDIR」ローカルライブラリーオブジェクトのリンクパス
# Makefile
TARGET = player.exe
ICON_RC = icon.rc
# 'debug' or 'release'
BUILD = release
VPATH = ../common
CSOURCES = minizip/ioapi.c \
minizip/unzip.c
PSOURCES = main.cpp \
player.cpp \
core/glcore.cpp \
.....
STDLIBS =
OPTLIBS = glfw3 glew32 opengl32 glu32 gdi32 imm32 \
pthread \
openal winmm dsound \
png16 jpeg_x86 openjp2 \
freetype \
id3tag \
z \
mad \
faad mp4ff
INC_SYS = /usr/local/boost_1_54_0
INC_LIB = /usr/local/include \
/usr/local/include/libpng16 \
/usr/local/include/libjpeg_x86 \
/usr/local/include/openjpeg-2.0 \
/usr/local/include/freetype2
PINC_APP = . ../common
CINC_APP = . ../common
LIBDIR = /usr/local/lib
INC_S = $(addprefix -I, $(INC_SYS))
INC_L = $(addprefix -I, $(INC_LIB))
INC_P = $(addprefix -I, $(PINC_APP))
INC_C = $(addprefix -I, $(CINC_APP))
CINCS = $(INC_S) $(INC_L) $(INC_C)
PINCS = $(INC_S) $(INC_L) $(INC_P)
LIBS = $(addprefix -L, $(LIBDIR))
LIBN = $(addprefix -l, $(STDLIBS))
LIBN += $(addprefix -l, $(OPTLIBS))
#
# Compiler, Linker Options, Resource_compiler
#
CP = g++
CC = gcc
LK = g++
RC = windres
POPT = -O2 -std=gnu++11
COPT = -O2
LOPT =
PFLAGS = -DWIN32 -DHAVE_STDINT_H
CFLAGS = -DWIN32
ifeq ($(BUILD),debug)
POPT += -g
COPT += -g
PFLAGS += -DDEBUG
CFLAGS += -DDEBUG
endif
ifeq ($(BUILD),release)
PFLAGS += -DNDEBUG
CFLAGS += -DNDEBUG
endif
# -static-libgcc -static-libstdc++
LFLAGS =
# -Wuninitialized -Wunused -Werror -Wshadow
CCWARN = -Wimplicit -Wreturn-type -Wswitch \
-Wformat
CPPWARN = -Wall
OBJECTS = $(addprefix $(BUILD)/,$(patsubst %.cpp,%.o,$(PSOURCES))) \
$(addprefix $(BUILD)/,$(patsubst %.c,%.o,$(CSOURCES)))
DEPENDS = $(patsubst %.o,%.d, $(OBJECTS))
ifdef ICON_RC
ICON_OBJ = $(addprefix $(BUILD)/,$(patsubst %.rc,%.o,$(ICON_RC)))
endif
.PHONY: all clean
.SUFFIXES :
.SUFFIXES : .rc .hpp .h .c .cpp .o
all: $(BUILD) $(TARGET)
$(TARGET): $(OBJECTS) $(ICON_OBJ) Makefile
$(LK) $(LFLAGS) $(LIBS) $(OBJECTS) $(ICON_OBJ) $(LIBN) -o $(TARGET)
$(BUILD)/%.o : %.c
mkdir -p $(dir $@); \
$(CC) -c $(COPT) $(CFLAGS) $(CINCS) $(CCWARN) -o $@
lt;
$(BUILD)/%.o : %.cpp
mkdir -p $(dir $@); \
$(CP) -c $(POPT) $(PFLAGS) $(PINCS) $(CPWARN) -o $@
lt;
$(ICON_OBJ): $(ICON_RC)
$(RC) -i
lt; -o $@
$(BUILD)/%.d : %.c
mkdir -p $(dir $@); \
$(CC) -MM -DDEPEND_ESCAPE $(COPT) $(CFLAGS) $(INC_C)
lt; \
| sed 's/$(notdir $*)\.o:/$(subst /,\/,$(patsubst %.d,%.o,$@) $@):/' > $@ ; \
[ -s $@ ] || rm -f $@
$(BUILD)/%.d : %.cpp
mkdir -p $(dir $@); \
$(CP) -MM -DDEPEND_ESCAPE $(POPT) $(PFLAGS) $(INC_P)
lt; \
| sed 's/$(notdir $*)\.o:/$(subst /,\/,$(patsubst %.d,%.o,$@) $@):/' > $@ ; \
[ -s $@ ] || rm -f $@
run:
./$(TARGET)
clean:
rm -rf $(BUILD) $(TARGET)
clean_depend:
rm -f $(DEPENDS)
dllname:
objdump -p $(TARGET) | grep "DLL Name"
tarball:
tar cfvz $(subst .exe,,$(TARGET))_$(shell date +%Y%m%d%H).tgz \
*.[hc]pp Makefile ../common/*/*.[hc]pp ../common/*/*.[hc]
bin_zip:
$(LK) $(LFLAGS) $(LIBS) $(OBJECTS) icon.o $(LIBN) -mwindows -o $(TARGET)
rm -f $(subst .exe,,$(TARGET))_$(shell date +%Y%m%d%H)_bin.zip
zip $(subst .exe,,$(TARGET))_$(shell date +%Y%m%d%H)_bin.zip *.exe *.dll res/*.*
-include $(DEPENDS)
完全な Makefile は Github にプシュした!