今まで、従属規則の生成には、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) -ilt; -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 にプシュした!