linux项目用Makefile编写
一 工程必备
顶层Makefile 顶层Makefile.build 子目录Makefile
二 编译过程
从顶层开始递归进入子目录,当进入到一个目录的最底层时,开始使用GCC编译,再将该层的所有.o文件打包成build-in.o,返回它的上一层目录再递归进入子目录,当编译完所有的子目录后,就开始编译顶层的.c文件,最后将顶层的.o文件和顶层每个子目录的build-in.o链接成我们的目标文件
三 顶层Makefile解析
#----------------------------------------------指定编译工具链---------------------------------------------------
CROSS_COMPILE = #指定编译器种类
AS = $(CROSS_COMPILE)as #
LD = $(CROSS_COMPILE)ld #链接工具
CC = $(CROSS_COMPILE)gcc #编译工具
CPP = $(CC) -E #
AR = $(CROSS_COMPILE)ar #打包工具
NM = $(CROSS_COMPILE)nm #
STRIP = $(CROSS_COMPILE)strip #优化工具
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CC CPP AR NM #将定义的变量导出,方便其他makefile使用
export STRIP OBJCOPY OBJDUMP #将定义的变量导出,方便其他makefile使用
TOPDIR := $(shell pwd) #获得当前程序的顶层目录
CFLAGS := -Wall -O2 -g #编译器参数
INCLUDES := -I$(shell pwd)/include #指定编译器头文件(根据实际项目手动修改)
LDFLAGS := -lm -lfreetype -lvga #指定编译器链接库(根据实际项目手动修改)
export TOPDIR CFLAGS LDFLAGS INCLUDES #将定义的变量导出,方便其他makefile使用
TARGET := show_file #编译后的程序名(根据实际项目手动修改)
#-------------------------顶层要生成的.o文件以及顶层文件夹(根据实际项目手动修改)------------------
obj-y += main.o
obj-y += display/
obj-y += draw/
obj-y += encoding/
obj-y += fonts/
#--------------------------------------------顶层的第一个规则(默认规则)-----------------------------------------
all :
make -C ./ -f $(TOPDIR)/Makefile.build __build #进入当前目录,使用顶层的makefile.build中的伪目标__build进行编译
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o #将编译好的built-in.o文件链接生成我们的目标文件
#------------------------------------------------顶层的清除规则-------------------------------------------------------
clean:
make -C ./ -f $(TOPDIR)/Makefile.build cleans #进入当前目录,执行Makfile.build中的伪目标cleans
rm -f $(shell find -name "*.o") #删除所有的.o文件
rm -f $(shell find -name "*.d") #删除所有的.d文件
rm -f $(TARGET) #删除目标文件
.PHONY:all clean
四 顶层Makefile.build解析
PHONY := __build #定义一个PHONY变量
__build: #开头说明__build伪目标,使其成为Makefile.build的第一个目标
obj-y := #定义当前目录的目标变量,初始值为空
subdir-y := #定义当前目录的子目录变量,初始值为空
include Makefile #将当前目录的Makefile包含进来,初始化obj-y
#obj-y:=a.o b.o c/ d/
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) #筛选出当前目录的目标变量中的子目录,并且去掉
#$(filter %/, $(obj-y)):c/ d/
#__subdir-y:c d
subdir-y += $(__subdir-y) #将开始定义的subdir-y赋值为__subdir-y
#subdir-y:c d
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o) #对于subdir-y里面的每一个值(目录),增加一个相应的目录/built-in.o的变量
#subdir_objs:c/built-in.o d/built-in.o
cur_objs := $(filter-out %/, $(obj-y)) #得到obj-y中的.o文件
#cur_objs:a.o b.o
INCLUDES += $(foreach f, $(subdir-y), -I$(TOP)/$(f)/include) #-I用于后面编译的时候的参数,表示需要包含这个路径下的头文件
#ICLUDES也可以写到子目录下的Makefile中
#例如,INCLUDES += -I$(TOP)/c/include
PHONY += $(subdir-y) #将$(subdir-y)也加入到变量PHONY中
--------------------------------------------Makefile. build的第一个规则--------------------------------------------------------------
__build : $(subdir-y) built-in.o #第一个规则
$(subdir-y): #第一个规则的第一个依赖规则
make -C $@ -f $(TOPDIR)/Makefile.build #依次进入该子目录变量里面存储的值,使用的Makefile.build进行编译
built-in.o : $(cur_objs) $(subdir_objs) #第一个规则的第二个依赖规则
$(LD) -r -o $@ $^ #该规则的命令:将该目录下的.o和$(subdir_obj)打包成built-in.o文件
%.o : %.c #第一个规则的第二个依赖规则的依赖规则
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $< #用于将目录下所有的.c文件编译成.o文件
#这里根据系统编译的情况来决定是否使用-Wp,一般不使用-Wp
subdirs_clean := $(foreach f, $(subdirs-y), $(f)_clean) #将各个子目录名后面添加“_clean”字符,这里是为了与subdirs区分
cleans: $(subdirs_clean)
$(subdirs_clean): #这里不能直接使用subdirs-y,是因为这个名称在上面已经使用过了,
#如果再次使用,会将之前的那个覆盖掉,所以要换名称
make -C $(patsubst %_clean, %, $@) clean #patsubst是去掉subdirs_clean中的字符"_clean",这里就是进入子目录执行make clean
.PHONY : $(PHONY) cleans #将PHONY声明为伪目标
五 子目录Makefile
子目录的Makefile就是包含该目录下所有的目标文件名和子目录文件夹名。
它最简单,形式如下:
obj-y += file.o
obj-y += subdir/
"obj-y += file.o"表示把当前目录下的file.c编进程序里,
"obj-y += subdir/"表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。
注意: "subdir/"中的斜杠"/"不可省略
转载自:http://www.cnblogs.com/lidabo/p/4521123.html