makefile的介绍和规则在博客 《由浅入深写一个makefile文件》里
from:https://www.cnblogs.com/lidabo/p/4521123.html
1、子目录里的makefile
在每个子目录文件夹里都写一个makefile
以encoding文件夹里的makfile为例:
obj-y += ascii.o
obj-y += encoding_manager.o
obj-y += utf-16be.o
obj-y += utf-16le.o
obj-y += utf-8.o
如果子目录encoding里还有个文件夹 比如test
则加一行:
obj-y += test/
小技巧 在UltraEdit里改成列模式,obj-y += 就可以只输入一次了
2、顶层目录的makefile
export 是用来提供该子目录makefile(sub make)中访问的,同一级的另外一个makefile中,是无法访问/得到的。
#----------------------------------------------指定编译工具链---------------------------------------------------
CROSS_COMPILE = arm-linux- #交叉编译工具 没有就不填
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld #链接工具(地址连接)https://blog.csdn.net/xungjhj/article/details/70847214
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
export STRIP OBJCOPY OBJDUMP
CFLAGS := -Wall -O2 -g #编译器参数
CFLAGS += -I $(shell pwd)/include #指定编译器头文件(根据实际项目手动修改)
#shell pwd的意思是执行shell的pwd命令
LDFLAGS := -lm -lfreetype #指定编译器链接库(根据实际项目手动修改)
export CFLAGS LDFLAGS #将定义的变量导出来,方便其他makefile使用
TOPDIR := $(shell pwd) #获得当前程序的顶层目录
export TOPDIR #输出顶层目录
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 #-C 生成.o文件 -f进入当前目录,使用顶层的makefile.build进行编译
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o #将编译好的built-in.o文件链接生成我们的目标文件
#------------------------------------------------顶层的清除规则-------------------------------------------------------
clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET)
distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
优先进入最底层的test
3、顶层目录的makefile.build
$(filter PATTERN…,TEXT)
函数名称:过滤函数—filter。
函数功能:过滤掉字串“TEXT”中所有不符合模式“PATTERN”的单词,保留所
有符合此模式的单词。
filter-out ---->不匹配
NEW = $(patsubst “%.c”, “%.s”, ${SRC})
函数功能:字符串替换
https://blog.csdn.net/myxmu/article/details/8588147
$(foreach < var >, < list > ,< text >)
这个函数的意思是,把参数< list >;中的单词逐一取出放到参数< var >;所指定的变量中,然后再执行< text>;所包含的表达式。每一次< text >;会返回一个字符串,循环过程中,< text >;的所返回的每个字符串会以空格分隔,最后当整个循环结束时,< text >;所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
所以,< var >;最好是一个变量名,< list >;可以是一个表达式,而< text >;中一般会使用< var >;这个参数来依次枚举;中的单词。举个例子:
names := a b c d
files := $(foreach n,$(names),$(n).o)
PHONY := __build #定义一个PHONY变量
__build: #开头说明__build伪目标,使其成为Makefile.build的第一个目标
obj-y := #定义当前目录的目标变量,初始值为空
subdir-y := #定义当前目录的子目录变量,初始值为空
include Makefile #将当前目录的Makefile包含进来,初始化obj-y
# 假设obj-y := a.o b.o c/ d/ 那如何取出c/ d/
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# $(filter %/, $(obj-y)) : c/ d/ --> c d
# __subdir-y : c d
# subdir-y : c d
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))#筛选出当前目录的目标变量中的子目录,然后将%/ 替换成%
subdir-y += $(__subdir-y)
# subdir_objs: c/built-in.o d/built-in.o
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o) #对于subdir-y里面的每一个值(目录),增加一个相应的目录/built-in.o的变量值
# cur_objs: a.o b.o
cur_objs := $(filter-out %/, $(obj-y)) #过滤到%/的文件,得到obj-y中的.o文件
dep_files := $(foreach f,$(cur_objs),.$(f).d) #取出依赖文件,赋值给dep_file #dep_files: .a.d .b.d
dep_files := $(wildcard $(dep_files)) #判断依赖文件是否存在
ifneq ($(dep_files),) #根据依赖文件名,判断依赖文件是否存在,存在就包含就来
include $(dep_files)
endif
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文件
dep_file = .$@.d
%.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $< #用于将目录下所有的.c文件编译成.o文件
.PHONY : $(PHONY) #将PHONY声明为伪目标
4、总结
本程序的Makefile分为3类:
- 顶层目录的Makefile
- 顶层目录的Makefile.build
- 各级子目录的Makefile
一、各级子目录的Makefile:
它最简单,形式如下:
obj-y += file.o
obj-y += subdir/
"obj-y += file.o"表示把当前目录下的file.c编进程序里,
"obj-y += subdir/"表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。
注意: "subdir/“中的斜杠”/"不可省略
二、顶层目录的Makefile:
它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外,主要是定义工具链、编译参数、链接参数──就是文件中用export导出的各变量。
三、顶层目录的Makefile.build:
这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o
详细的讲解请看视频。
四、怎么使用这套Makefile:
1.把顶层Makefile, Makefile.build放入程序的顶层目录
2.修改顶层Makefile
2.1 修改工具链
2.2 修改编译选项、链接选项
2.3 修改obj-y决定顶层目录下哪些文件、哪些子目录被编进程序
2.4 修改TARGET,这是用来指定编译出来的程序的名字
-
在各一个子目录下都建一个Makefile,形式为:
obj-y += file1.o
obj-y += file2.o
obj-y += subdir1/
obj-y += subdir2/ -
执行"make"来编译,执行"make clean"来清除,执行"make distclean"来彻底清除