• 适用所有的应用程序
  • 程序的编译过程
    • 一个C/C++程序要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)、链接(linking)四个步骤才能变成可执行程序
    • 预处理:头文件包含、宏展开等操作
    • 编译:.c文件转成汇编.s文件,进行语法、语义上的解析
    • 汇编:.s=>.o 汇编转成机器码
    • 链接:.o + 各种库文件 链接在一起
    • 预处理、编译、汇编三个步骤一般合在一起操作,习惯叫做编译
    • 先编译,再链接
    • 编译过一次后,后续修改了哪个文件,就单独编译对应文件,再链接
    • 修改头文件,就单独编译“用到了此头文件的源文件”
  • makefile核心:规则

    1. 目标:依赖1 依赖2
    2. 命令
  • 命令执行的条件

    • 依赖 比 目标 的时间新
    • 没有 目标 文件
  • gcc -c : 执行预处理、编译、汇编三个步骤
    • gcc -c -o a.o a.c
  • makefile如果当前的依赖文件不存在,则会以当前的依赖文件作为目标不断的往下查找规则,直到匹配为止
  • 通配符:%.c,”%”符号表示匹配所有,和一般的”*”一样
  • $@:表示目标
  • $<:表示第一个依赖; $^:表示所有依赖

    1. target: a.o b.o
    2. gcc -o target a.o b.o
    3. %.o: %.c
    4. gcc -c -o $@ $<
  • 上面这个makefile有bug:修改源文件包含的.h头文件时,无法进行更新编译

  • 加上一行: a.o: a.c a.h 就可以了
  • 但这样太麻烦了,应该用自动的规则来匹配依赖

    1. target: a.o b.o
    2. gcc -o target a.o b.o
    3. %.o: %.c
    4. gcc -Wp,-MD,$@.d -c -o $@ $<
    5. clean:
    6. rm *.o target
  • gcc 的”-Wp,-MD,$@.d”命令用来生成目标的依赖文件

  • 直接执行make时,默认执行的是第一条规则(生成第一个目标)
  • 怎么把命令生成的依赖文件包含进入目标文件中?
    • 先判断某个文件是否存在,存在才能包含
    • image.png
    • wildcard函数
    • image.png
    • foreach函数 ```makefile objs := a.o b.o

target: $(objs) gcc -o target $^ #所有的依赖

依赖文件:.a.o.d .b.o.d

dep_file := $(foreach f,$(objs),.$(f).d) # 将objs变量的全部都重新命名为.xx.o.d的格式 dep_file := $(wildcard $(dep_file)) # dep_file变量中的.d文件存在就取出来

wildcard函数筛选、取出当先目录下存在的文件

ifneq ($(dep_file),) # 如果文件存在(dep_file变量不为空) include $(dep_file) endif

%.o: %.c gcc -Wp,-MD,.$@.d -c -o $@ $< clean: rm *.o target

  1. - 一个工程中,一般都有多个目录,要如何支持多个目录下文件的编译呢?
  2. - 仿照内核makefile
  3. - 每个子目录下都建立一个makefile,只包含所涉及的文件: obj-y += a.o
  4. - 顶层目录的makefile
  5. ```makefile
  6. CROSS_COMPILE = arm-linux- # 工具链, 就想用gcc时为空就好
  7. AS = $(CROSS_COMPILE)as
  8. LD = $(CROSS_COMPILE)ld
  9. CC = $(CROSS_COMPILE)gcc
  10. AR = $(CROSS_COMPILE)ar
  11. NM = $(CROSS_COMPILE)nm
  12. CPP = $(CC) -E
  13. STRIP = $(CROSS_COMPILE)strip
  14. OBJCOPY = $(CROSS_COMPILE)objcopy
  15. OBJDUMP = $(CROSS_COMPILE)objdump
  16. # 进入各个子目录编译时想直接使用这些变量,使用export
  17. export AS LD CC CPP AR NM
  18. export STRIP OBJCOPY OBJDUMP
  19. CFLAGS := -Wall -O2 -g # -Wall列出所有警告 -O2优化选项
  20. CFLAGS += -I $(shell pwd)/include # 指定当前目录下的include目录为头文件目录
  21. # -I 头文件目录 -- 指定系统头文件外用到的头文件目录
  22. # -L 库文件目录
  23. LDFLAGS := -lm -lfreetype
  24. export CFLAGS LDFLAGS # 导出编译选项、链接选项
  25. TOPDIR := $(shell pwd)
  26. export TOPDIR
  27. TARGET := show_file
  28. obj-y += main.o
  29. obj-y += dispaly/
  30. obj-y += draw/
  31. obj-y += encoding/ # 进入对应子目录
  32. obj-y += fonts
  33. all :
  34. make -C ./ -f $(TOPDIR)/Makefile.build
  35. $(CC) $(LDFLAGS) -o $(TARGET) built-in.o
  36. clean:
  37. rm -f $(shell find -name "*.o")
  38. rm -f $(TARGET)
  39. distclean:
  40. rm -f $(shell find -name "*.o")
  41. rm -f $(shell find -name "*.d") # 删除依赖文件
  42. rm -f $(TARGET)
  • 默认头文件在对应工具链中image.png
  • makefile中使用”=”的称为延时变量(递归调用扩展型变量),它的值只有在使用时才会定下来;用”:=”是立即变量(简单扩展型变量),值马上确定下来
  • 使用递归调用扩展型变量最大的缺点是不能在变量后面追加内容
  • 递归到最底层目录下将.c编译为.o,并打包成built-in.o;然后逐步往上层目录编译打包直到顶层目录
  • image.png
  • 顶层目录的makefile严重依赖Makefile.build ```makefile PHONY := build build: # 假目标, 想要生成的目标

obj-y := subdir-y := # 子目录

include Makefile # 包含当前目录下的makefile

取出子目录 obj-y := a.o b.o c/ d/

$(filter %/, $(obj-y)) : c/ d/

__subdir-y : c d

subdir-y := $(patsubst %/, %, $(filter %/, $(obj-y))) $ filter %/,$(obj-y) 把%/格式的筛选出来 subdir-y += $(subdir-y)

c/built-in.o d/built-in.o

subdir-objs := $(foreach f,$(subdir-y),$(f)/built-in.o)

a.o b.o

cur_objs := $(filter-out %/, $(obj-y)) # 取出当前目录的目标 dep_file := $(foreach f,$(cur_objs),.$(f).d) # 将objs变量的全部都重新命名为.xx.o.d的格式 dep_file := $(wildcard $(dep_file)) # dep_file变量中的.d文件存在就取出来

wildcard函数筛选、取出当先目录下存在的文件

ifneq ($(dep_file),) # 如果文件存在(dep_file变量不为空) include $(dep_file) endif

PHONY += $(subdir-y)

__build : $(subdir-y) duilt-in.o

$(subdir-y): make -C $@ -f $(TOPDIR)/Makefile.build # 进入子目录递归的使用makefile.build

duilt-in.o : $(cur_objs) $(subdir-objs) $(LD) -r -o $@ $^ # 打包用LD来,不是用AR

dep_file = .$@.d # 用到才赋值 %.o : %.c $(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c $@ $<

.PHONY : $(PHONY) ```

  • image.png
  • image.png