1. Makefile-exe
CC:=gcc CXX:=g++ RM:=rm -rf OUTDIR:=$(EXEDIR) EXENAME:=$(PROJNAME) EXESRCS:=$(COMPILE_FILES) CFLAGS:=$(COMPILE_FLAGS) LDFLAGS:=$(LINK_FLAGS) DEBUG:=Y EXEOBJS:=$(patsubst %.cpp,%.oo,$(EXESRCS)) EXEOBJS:=$(patsubst %.c,%.o,$(EXEOBJS)) EXEDEPS:=$(patsubst %.cpp,%.dd,$(EXESRCS)) EXEDEPS:=$(patsubst %.c,%.d,$(EXEDEPS)) ifeq ($(DEBUG),Y) CFLAGS+=-O0 -ggdb3 else CFLAGS+=-O3 -fomit-frame-pointer endif .PHONY:all clean all:$(OUTDIR).dir $(OUTDIR)/$(EXENAME) $(OUTDIR)/$(EXENAME):$(EXEDEPS) $(EXEOBJS) $(CXX) $(EXEOBJS) -o $@ $(LDFLAGS) -include $(EXEDEPS) %.d: %.c @$(CC) -MM $(CFLAGS) $< | sed -e 's,^[0-9a-zA-Z._-]*: \([0-9a-zA-Z._-]*/\),\1&,' -e 's,^\([0-9a-zA-Z._-/]*\)\.o:,\1.o \1.d:,' > $@ %.dd: %.cpp @$(CXX) -MM $(CFLAGS) $< | sed -e 's,^[0-9a-zA-Z._-]*: \([0-9a-zA-Z._-]*/\),\1&,' -e 's,^\([0-9a-zA-Z._-/]*\)\.o:,\1.oo \1.dd:,' > $@ %.o:%.c $(CC) $(CFLAGS) -c $< -o $@ %.oo:%.cpp $(CXX) $(CFLAGS) -c $< -o $@ %.dir: @echo "Checking directory $*" @if [ ! -d $* ]; then \ echo "Making directory $*"; \ mkdir -p $* ;\ fi; clean: -$(RM) $(EXEOBJS) $(EXEDEPS) $(OUTDIR)/$(EXENAME)
2. Makefile-so
CC:=gcc
CXX:=g++
LD:=ld
RM:=rm -rf
OUTDIR:=$(LIBDIR)
LIBNAME:=lib$(PROJNAME)
LIBSRCS:=$(COMPILE_FILES)
CFLAGS:=$(COMPILE_FLAGS)
LDFLAGS:=$(LINK_FLAGS)
DEBUG:=Y
LIBOBJS:=$(patsubst %.cpp,%.oo,$(LIBSRCS))
LIBOBJS:=$(patsubst %.c,%.o,$(LIBOBJS))
LIBDEPS:=$(patsubst %.cpp,%.dd,$(LIBSRCS))
LIBDEPS:=$(patsubst %.c,%.d,$(LIBDEPS))
CFLAGS+=-I. -Wall
ifeq ($(DEBUG),Y)
CFLAGS+=-O0 -ggdb3
else
CFLAGS+=-O3 -fomit-frame-pointer
endif
.PHONY:all clean
all:$(OUTDIR).dir $(OUTDIR)/$(LIBNAME)
$(OUTDIR)/$(LIBNAME):$(LIBDEPS) $(LIBOBJS)
$(CC) -shared -fPIC $(LIBOBJS) -o [email protected] $(LDFLAGS)
-include $(LIBDEPS)
%.d: %.c
@$(CC) -MM $(CFLAGS) $< | sed -e 's,^[0-9a-zA-Z._-]*: \([0-9a-zA-Z._-]*/\),\1&,' -e 's,^\([0-9a-zA-Z._-/]*\)\.o:,\1.o \1.d:,' > $@
%.dd: %.cpp
@$(CXX) -MM $(CFLAGS) $< | sed -e 's,^[0-9a-zA-Z._-]*: \([0-9a-zA-Z._-]*/\),\1&,' -e 's,^\([0-9a-zA-Z._-/]*\)\.o:,\1.oo \1.dd:,' > $@
%.oo:%.cpp
$(CXX) $(CFLAGS) $(DEFS) -c $< -o $@
%.o:%.c
$(CC) $(CFLAGS) $(DEFS) -c $< -o $@
%.dir:
@echo "Checking directory $*"
@if [ ! -d $* ]; then \
echo "Making directory $*"; \
mkdir -p $* ;\
fi;
clean:
-$(RM) $(OUTDIR)/* $(LIBOBJS) $(LIBDEPS)
3. Makefile-src
PROJNAME:=engine
LIBDIR:=../lib
LINK_FLAGS:=-lSDL -lGL -lGLU -lGLEW -lstdc++ -lMagick++ -lassimp
COMPILE_FLAGS:=-I/usr/include/SDL -I/usr/include/ImageMagick -I/usr/local/include/assimp -I../include -D_GNU_SOURCE=1 -D_REENTRANT -DARCH_X86=1 -Wno-int-to-pointer-cast
COMPILE_FILES:= util/Array.c\
util/Timer.c
include ../Makefile-so
4. 編譯靜態庫
如果是編譯靜態庫,使用下面的命令進行編譯:
AR:=ar
RANLIB:=ranlib
(OUTDIR)/$(LIBNAME):$(DEPS) $(OBJS)
$(AR) cr $@ (OBJS)
$(RANLIB) $@
基本上上面的用法就足夠了,多多使用就好。
5. gcc 選項
-I :頭文件位置(編譯時用)-l: 引用的庫的名稱(鏈接時用)
-L:引用的庫的位置(鏈接時用)
-Wall: 打開所有警告
-Wno-xxx:關閉某個警告
-O0 -ggdb3:沒有編譯優化,加入gdb調試信息-O3:最優化編譯優化
-g或者-ggdb3生成調試信息
-D:定義的預編譯的變量名
-M:生成文件關聯的信息
-MM:同上,但是去除#include <...h>這樣的關聯信息
CFLAGS LDFLAGS:gcc內部定義的變量自動化變量:
$@ 目標文件 $^ 所有依賴文件 $< 第一個依賴文件
6. 依賴文件
生成依賴.d文件:
需要生成這個文件的原因:有時候如果頭文件發生了改動,但是.c文件沒有發生改動,如果單純的依賴.c文件會導致頭文件的更新無法反映到可執行程序中去。
應採用下面這種方式來實現:
$EXENAME: $DEPENDENCE $OBJS
%.d:%.c
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
其中$@.$$$$表示以.d+進程號作爲一個臨時文件($$表示進程號,至於爲什麼要用4個,這是因爲首次要經過shell的處理,shell中$$表示$);
sed使用的是替換功能 sed 's/{old_string}/{new_string}/g' 或者採用逗號作爲分隔符sed 's,{old_string},{new_string},g', 分割符自己定義,只要和匹配模式裏面的字符不衝突就好
其中的匹配用到了正則表達式(正則表達式確實很強大,在grep, awk中均用到了,grep用於找到行,awk用於找到列)
這個是GNU Makefile中文手冊上的用法,比較好理解(一個sed命令,兩個重定向);
上面的腳本中是老師的用法:
@$(CC) -MM $(CFLAGS) $< | sed -e 's,^[0-9a-zA-Z._-]*: \([0-9a-zA-Z._-]*/\),\1&,' -e 's,^\([0-9a-zA-Z._-/]*\)\.o:,\1.o \1.d:,' > $@
分兩步進行:第一步,先選出字符串中符合 XXX: aaa bbb格式的字符串;第二步,替換,將xxx.o替換成xxx.o xxx.d
7. Makefile內置函數
wildcard: 通配符 ,用法 $(wildcard *.c),獲取當前目錄下的所有的.c文件patsubst: 模式替換,用法$(patsubst %.cpp %.oo $(SRCFILES)),將SRCFILES中所有的cpp換成.oo
ar xxxx.a a.o b.o :將a.o b.o加入到靜態庫中
ranlib xxxx.a :爲庫文件創建索引表
(ar t xxx.a:顯示庫中有哪些目標文件, nm -s xxx.a 顯示索引表)