makefile讲解

makefile基础知识

1、赋值符号的区别:

  =  是最基本的赋值,用到了之后才赋值,不能在变量后追加内容
  :=  是覆盖之前的值,立即赋值,可以在变量后追加内容   ?= 是如果没有被赋值过就赋予等号后面的值   += 是添加等号后面的值

2、自动变量:

  $<    第一个依赖文件的名称
  $?    所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚
  $@  目标的完整名称
  $^    所有的依赖文件,以空格分开,不包含重复的依赖文件

3、常用的函数:

  1. $(patsubst %.c,%.o,x.c.cbar.c)
  把字串“x.c.cbar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o”
  2.$(filter <pattern...>,<text> )
  以<pattern>模式过滤<text>字符串中的单词,保留符合模式<pattern>的单词。可以有多个模式。 
  3.$(filter-out <pattern...>,<text> )
  4.$(foreach <var>,<list>,<text> )
  把参数<list>中的单词逐一取出放到参数<var>所指定的变量中, 然后再执行<text>所包含的表达式。每一次<text>会返回一个字符串,循环这个过程。
  5.shell函数,例如files := $(shell echo *.c)

通用的makefile文件的编译过程:

  从顶层开始递归进入子目录,当进入到一个目录的最底层时,开始使用编译器编译,再将该层的所有.o文件打包成build-in.o,返回它的上一层目录再递归进入子目录,当编译完所有的子目录后,就开始编译顶层的.c文件,最后将顶层的.o文件和顶层每个子目录的build-in.o链接成我们的目标文件。

实战:

  假如一个目录结构如下:

  a

  ----d

  ----a.c

  b

  ----b.c

  c

  ----c.c

  main.c

  makefile

  makefile.built

顶层的Makefile

 #定义各个编译用到的工具
CROSS_COMPILE =         #交叉编译器 arm-none-Linux-gnueabi- AS = $(CROSS_COMPILE)as #汇编器 LD = $(CROSS_COMPILE)ld #连接器 CC = $(CROSS_COMPILE)gcc #编译器 CPP = $(CC) -E #预处理 AR = $(CROSS_COMPILE)ar #归档文件 NM = $(CROSS_COMPILE)nm   #列出object文件中的符号 STRIP = $(CROSS_COMPILE)strip  #丢弃目标文件中的符号 OBJCOPY = $(CROSS_COMPILE)objcopy #转换目标文件格式 OBJDUMP = $(CROSS_COMPILE)objdump #反汇编 export AS LD CC CPP AR NM #将变量导出供下一个makefile使用 export STRIP OBJCOPY OBJDUMP CFLAGS := -Wall -O2 -g #CFLAGS 指定编译参数
#CFLAGS += -I $(shell pwd)/include
LDFLAGS :
= export CFLAGS LDFLAGS TOPDIR := $(shell pwd) export TOPDIR TARGET := test obj-y += main.o  #obj-y  main.o 编译链接进项目 obj-y += a/ obj-y += b/ obj-y += c/ all :
  # make的递归执行,make的“-C”选项,是首先进入子目录而后再执行make。
  #当需要将一个普通命名的文件作为makefile文件时,需要使用make的“-f”、“--file”或者“--makefile”选项来指定。
make -C ./ -f $(TOPDIR)/Makefile.build $(CC) $(LDFLAGS) -o $(TARGET) built-in.o clean: rm -f $(shell find -name "*.o") #删除命令,默认是 rm -f rm -f $(shell find -name "*.d") rm -f $(TARGET)

#执行make时,目标“all”被作为终极目标。
#伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它 是否要执行。
#我们只有通过显示地指明这个“目标”才能让其生效。
#为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,
#不管是否有这个文件,这个目标就是“伪目标”。 .PHONY:all clean

Makefile.build

    PHONY := build    #定义一个PHONY变量
    build :  #开头说明build伪目标,使其成为Makefile.build的第一个目标
    obj-y :=  
    subdir-y :=  
    include Makefile  
    __subdir-y  := $(patsubst %/,%,$(filter %/, $(obj-y)))  #筛选出当前目录的目标变量中的子目录,并且去掉/,在这里我们获得了子目录的名字
    subdir-y    += $(__subdir-y)  
    subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)  #对于subdir-y里面的每一个值(目录),增加一个相应的目录/built-in.o的变量值
    cur_objs := $(filter-out %/, $(obj-y))  # 得到obj-y中的.o文件
    dep_files := $(foreach f,$(cur_objs),.$(f).d)  # .$(f).d 第一个.表示隐藏的 后面的.表示后缀
    dep_files := $(wildcard $(dep_files))  
   #ifneq ($(dep_files),) # include $(dep_files) #endif PHONY += $(subdir-y) build : $(subdir-y) built-in.o $(subdir-y): make -C $@ -f $(TOPDIR)/Makefile.build built-in.o : $(cur_objs) $(subdir_objs) $(LD) -r -o $@ $^ dep_file = .$@.d %.o : %.c $(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $< .PHONY : $(PHONY)

子目录下的Makefile

    obj-y += a.o  
    obj-y += d/  

就是添加该目录下的文件和子目录,子目录要以 / 结尾。

  

原文地址:https://www.cnblogs.com/hypnus-ly/p/8574593.html