1. 程式人生 > >自動萬能makefile(linux ubuntu gcc/g++),讓makefile的編寫不在煩人

自動萬能makefile(linux ubuntu gcc/g++),讓makefile的編寫不在煩人

自動萬能makefile(linux ubuntu gcc/g++),讓makefile的編寫不在煩人

keyword: wildcard notdir patsubst findstring wordlist suffix foreach

 

功能:

     1、自動以makefile的父目錄名為Target檔名稱
     2、自動搜尋原始碼檔案(含子目錄)
     3、自動搜尋標頭檔案檔案(含子目錄)
     4、自動搜尋搜尋庫檔案(含子目錄)
     5、無需任何設定也可以編譯可執行檔案
     6、可以生成.a和.so檔案
 

 注意:本檔案不對您的程式碼編譯結果擔負任何法律和道德責任,使用時需謹慎

另一個專案管理級別的高度自動化的makefile連結地址:

https://blog.csdn.net/guestcode/article/details/81229127

 

本文demo下載地址:

https://download.csdn.net/download/guestcode/10451084

 

#########################################################
# 名稱:自動萬能makefile(linux ubuntu gcc/g++)
# 作者:碼客(盧益貴)
# 微信qq:48092788
# 時間:2018-5-20
# 功能:
#     1、自動以makefile的父目錄名為Target檔名稱
#     2、自動搜尋原始碼檔案(含子目錄)
#     3、自動搜尋標頭檔案檔案(含子目錄)
#     4、自動搜尋搜尋庫檔案(含子目錄)
#     5、無需任何設定也可以編譯可執行檔案
#     6、可以生成.a和.so檔案
#
# 注意:本檔案不對您的程式碼編譯結果擔負任何法律和道德責任,使用時需謹慎
#
#########################################################


###############################################
# 工程定義項(常用項,不設定為使用預設值)
###############################################
# 目錄名後面不需要“/”,正確的:“src”,錯誤的:“src/”,下同
# 輸出的目標檔名,不需路徑資訊
Target :=

# 原始檔目錄,預設為src目錄,如果沒有src則為當前目錄
SrcDir :=

# 標頭檔案目錄,預設為lib目錄,沒有lib則等於SrcDir
IncDir :=

# 庫檔案(*.a/*.so)和其標頭檔案的目錄,預設依次為lib\3rdparty目錄,否則為當前目錄
LibDir :=

# 目標檔案Target的輸出目錄
OutDir :=

# 臨時檔案目錄,預設時,SrcDir、LibDir都不為當前目錄時為obj,否則為當前目錄
ObjDir :=

# 除錯選項,任意值為除錯設定
DEBUG :=

###############################################
# 編譯定義項(常用項,不設定為使用預設值)
###############################################
# c/c++編譯器名稱,預設為自動搜尋,有cpp檔案則為g++,否則為gcc
# CC := gcc
CC :=
# 靜態庫檔案編譯器名稱,預設為ar
AR :=

# c編譯標誌,編譯器時gcc時設定,預設為:-Wall -O -g
GccFlags :=

# c++編譯標誌,編譯器時g++時設定,預設為:-std=c++11
GxxFlags :=

# 靜態庫編譯標誌,預設為:-cr
ArFlags :=

# 連結標誌,預設為:-lpthread -lrt
LdFlags :=


###############################################
# 工程定義項預設值,此後為非常用項,修改需謹慎
###############################################
# 如果Target沒有定義輸出的目標檔名,則預設為makefile的父目錄名
ifeq ($(Target), )
Target := $(shell pwd)/$(lastword $(MAKEFILE_LIST))
Target := $(shell dirname $(Target))
Target := $(notdir $(Target))
endif

# 如果沒有設定OutDir,預設為當前目錄
ifeq ($(OutDir), )
OutDir := .
endif

# 如果沒有設定SrcDir,預設為src,如果沒有src目錄則為當前目錄
ifeq ($(SrcDir), )
SrcDir := $(shell if [ -d src ]; then echo ./src; else echo .; fi;)
endif


# 如果沒有設定IncDir,預設為inc,如果沒有inc目錄等於SrcDir
ifeq ($(IncDir), )
IncDir := $(shell if [ -d inc ]; then echo ./inc; else echo $(SrcDir); fi;)
endif

# 如果沒有設定LibDir,預設依次為lib\3rdparty目錄,否則為當前目錄
ifeq ($(LibDir), )
LibDir := $(shell if [ -d lib ]; then echo ./lib; else echo ; fi;)
endif
ifeq ($(LibDir), )
LibDir := $(shell if [ -d 3rdparty ]; then echo ./3rdparty; else echo .; fi;)
endif

# 如果沒有設定臨時檔案目錄,預設為obj
ifeq ($(ObjDir), )
ObjDir := .
ifneq ($(SrcDir), .)
ifneq ($(LibDir), .)
ObjDir := ./obj
endif
endif
endif

###############################################
# 編譯定義項預設值
###############################################
# c/c++編譯器名稱,預設值
# 自動搜尋原始碼檔案字尾,有cpp的則自動設定編譯器是g++,反之是gcc
ifeq ($(CC), )
tmpVar := $(shell find ./ -type f -iname *.cpp)
ifeq ($(tmpVar), )
CC := gcc
else
CC := g++
endif
endif

# 靜態庫編譯器預設值
ifeq ($(AR), )
AR  := ar
endif

# c編譯標誌預設值,編譯器時gcc時設定
ifeq ($(GccFlags), )
GccFlags  := -Wall -O -g
endif

# c++編譯標誌預設值,編譯器時g++時設定
ifeq ($(GxxFlags), )
GxxFlags := -std=c++11
endif

# 編譯標誌預設值,最終使用CFlags來配置編譯選項
ifeq ($(CC), gcc)
CFlags := $(GccFlags)
else
CFlags := $(GxxFlags)
endif

# 靜態庫編譯標誌預設值
ifeq ($(ArFlags), )
ArFlags := -cr
endif

# 連結標誌預設值
ifeq ($(ArFlags), )
LdFlags := -lpthread -lrt
endif

# 生成動態庫時設定
ifeq ($(suffix $(Target)), .so)
CFlags += -fPIC
LdFlags += -shared
endif

ifneq ($(DEBUG), )
CFlags += -ggdb -rdynamic
else
CFlags += -O2 -s
endif


###############################################
# 自動搜尋關聯檔案,從此處開始至結束,不建議修改
###############################################
# c/cpp檔案原始碼檔案搜尋的目錄,用於編譯設定
VPATH := $(shell find $(SrcDir) -type d)

# 臨時檔案(*.o)列表,每個*.c/*.cpp對應一個*.o檔案,用於連結設定
ifeq ($(CC), gcc)
ObjFiles := $(shell find $(LibDir) -type f -iname *.c) #如果庫中有原始碼檔案
ifneq ($(ObjFiles), )
VPATH += $(shell find $(LibDir) -type d)
endif
ObjFiles += $(shell find $(SrcDir) -type f -iname *.c)
else
ObjFiles := $(shell find $(LibDir) -type f -iname *.c -o -iname *.cpp) #如果庫中有原始碼檔案
ifneq ($(ObjFiles), )
VPATH += $(shell find $(LibDir) -type d)
endif
ObjFiles += $(shell find $(SrcDir) -type f -iname *.c -o -iname *.cpp)
endif
ObjFiles := $(notdir $(ObjFiles))            #去掉目錄資訊
ObjFiles := $(ObjFiles:%.c=$(ObjDir)/%.o)    #每個*.c對應一個*.o檔案,並設定輸出到臨時目錄ObjDir
ObjFiles := $(ObjFiles:%.cpp=$(ObjDir)/%.o)  #每個*.cpp對應一個*.o檔案,並設定輸出到臨時目錄ObjDir

# *.a/*.so檔案列表,用於連結設定
LibFiles := $(shell find $(LibDir) -type f -iname *.a -o -iname *.so)
LibFiles := $(notdir $(LibFiles))    #去掉目錄資訊
LibFiles := $(LibFiles:lib%.a=-l%)   #每個*.a庫檔名前加-l引數標誌,去掉字尾.a和字首lib
LibFiles := $(LibFiles:lib%.so=-l%)  #每個*.so庫檔名前加-l引數標誌,去掉字尾.so和字首lib

# 所有include包含的*.h檔案所在的目錄列表,用於編譯設定
IncDirs := $(shell find $(IncDir) -type d) #*.c/*.cpp檔案所在目錄,預設每個*.c/*.cpp對應一個*.h檔案

# *.a/*.so和它們的定義檔案*.h所在的目錄列表,用於連結設定
LibDirs := $(shell find $(LibDir) -type d)
IncDirs += $(LibDirs)
LibDirs := $(LibDirs:%=-L%) #每個目錄名前加-I引數標誌

IncDirs := $(IncDirs:%=-I%) #每個目錄名前加-I引數標誌

###############################################
# 連結成最終檔案
###############################################
all:$(Target)
$(Target): $(ObjFiles)
	@echo "\nlinking file: "$(Target)
ifneq ($(OutDir), .)
	$(shell if [ ! -d $(OutDir) ]; then mkdir $(OutDir); fi;)
endif
ifeq ($(suffix $(Target)), .a)
	$(AR) $(ArFlags) -o $(OutDir)/$(Target) $^
else
	$(CC) $(CFlags) $^ $(LibDirs) $(LibFiles) -o $(OutDir)/$(Target) $(LdFlags)
endif

###############################################
# 編譯成obj檔案
###############################################
# 編譯c原始碼檔案,生成.o檔案
$(ObjDir)/%.o:%.c
ifneq ($(ObjDir), .)
	$(shell if [ ! -d $(ObjDir) ]; then mkdir $(ObjDir); fi;)
endif
	@echo "\ncompiling file: "$<
	$(CC) $(CFlags) -c $< -o 
[email protected]
$(IncDirs) $(ObjDir)/%.o:%.cpp ifneq ($(ObjDir), .) $(shell if [ ! -d $(ObjDir) ]; then mkdir $(ObjDir); fi;) endif @echo "\ncompiling file: "$< $(CC) $(CFlags) -c $< -o [email protected] $(IncDirs) ############################################### # 清理臨時檔案 ############################################### clean: ifeq ($(ObjDir), .) @rm -f *.o else $(shell if [ -d $(ObjDir) ]; then rm -r $(ObjDir);fi;) endif ifeq ($(OutDir), .) @rm -f $(Target) else $(shell if [ -d $(OutDir) ]; then rm -r $(OutDir);fi;) endif @echo "cleaned" .PHONY: all clean