Linux下规范性Makefile规则

文件目录

  • bsp
    • clk (时钟驱动)
      • bsp_clk.c
      • bsp_clk.h
    • delay (延时驱动)
      • bsp_delay.c
      • bsp_delay.h
    • led (LED驱动)
      • bsp_led.c
      • bsp_led.h
  • imx6ul
    • cc.h (变量类型声明)
    • fsl_common.h (NXP官方SDK通用宏定义文档)
    • fsl_iomuxc.h (NXP官方SDK寄存器地址定义文档)
    • imx6ul.h (常用头文件)
    • MCIMX6Y2.h (NXP官方SDK寄存器结构体和相关位定义文档)
  • obj
    .o文件目标地址
  • project
    • main.c (主函数)
    • start.S (启动文件)

Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
CROSS_COMPILE 	?= arm-linux-gnueabihf-
TARGET ?= bsp

CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump

INCDIRS := imx6ul \
bsp/clk \
bsp/led \
bsp/delay

SRCDIRS := project \
bsp/clk \
bsp/led \
bsp/delay


INCLUDE := $(patsubst %, -I %, $(INCDIRS))

SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))

SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))

SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)

VPATH := $(SRCDIRS)

.PHONY: clean

$(TARGET).bin : $(OBJS)
$(LD) -Timx6ul.lds -o $(TARGET).elf $^
$(OBJCOPY) -O binary -S $(TARGET).elf $@
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis

$(SOBJS) : obj/%.o : %.S
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<

$(COBJS) : obj/%.o : %.c
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<

clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

细节

工具配置

1
2
3
4
5
6
7
CROSS_COMPILE 	?= arm-linux-gnueabihf-     # 交叉编译工具前缀(ARM架构)
TARGET ?= bsp # 目标程序名称,默认输出文件名为 `bsp`

CC := $(CROSS_COMPILE)gcc # C 编译器
LD := $(CROSS_COMPILE)ld # 链接器
OBJCOPY := $(CROSS_COMPILE)objcopy # 二进制转换工具
OBJDUMP := $(CROSS_COMPILE)objdump # 反汇编工具

目录与文件管理

1
2
3
4
5
6
7
8
9
10
11
INCDIRS := imx6ul \            # 头文件搜索目录列表,"\"为换行符
bsp/clk \
bsp/led \
bsp/delay

SRCDIRS := project \ # 源码搜索目录列表,"\"为换行符
bsp/clk \
bsp/led \
bsp/delay

INCLUDE := $(patsubst %, -I %, $(INCDIRS)) # 将 INCDIRS 转换为 gcc 的 `-I` 选项

patsubst:

  • 函数用法:$(patsubst <pattern>,<replacement>,<text>

  • 名称:模式字符串替换函数——patsubst。

  • 功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么<replacement>中的这个“%”将是<pattern>中的那个“%”所代表的字串。(可以用“\”来转义,以“%”来表示真实含义的“%”字符)

  • 返回:函数返回被替换过后的字符串。

  • 示例:$(patsubst %.c,%.o, a.c b.c),把字串“a.c b.c”符合模式[%.c]的单词替换成[%.o],返回结果是“a.o b.o”

源码文件收集

1
2
3
4
5
6
7
8
9
10
11
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))  # 所有 .S 汇编文件
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c)) # 所有 .c C 文件

SFILENDIR := $(notdir $(SFILES)) # 去除路径,保留文件名(如 `start.S`)
CFILENDIR := $(notdir $(CFILES)) # 去除路径,保留文件名(如 `main.c`)

SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o)) # 汇编文件对应的 .o 文件(放在 obj 目录)
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o)) # C 文件对应的 .o 文件(放在 obj 目录)
OBJS := $(SOBJS) $(COBJS) # 所有目标文件

VPATH := $(SRCDIRS) # 指定源码搜索路径,Make 会在这些目录中查找依赖文件

foreach

  • 用法:$(foreach <var>, <list>, <expr>)

  • 功能:遍历 <list> 中的每个元素,将元素赋值给 <var>,然后展开 <expr>,最终将所有展开结果合并成一个空格分隔的字符串。

  • 示例中的用法:遍历 SRCDIRS 中的每个目录,收集所有 .S.c 文件的完整路径。

    1. dir 依次取 SRCDIRS 中的值(如 project, bsp/clk 等)
    2. $(wildcard $(dir)/*.S) 展开为 dir 目录下所有 .S 文件的路径(如 project/start.S, bsp/clk/clk.S)。
    3. 最终 SFILES 是所有 .S 文件的路径列表,CFILES 是所有 .c 文件的路径列表。

wildcard

  • 用法:$(wildcard <pattern>)
  • 功能:匹配符合 <pattern> 的文件路径,支持通配符 * 和 ?。
  • 示例中的用法:在 foreach 循环中,为每个 dir 目录生成文件列表。

生成二进制文件

1
2
3
4
$(TARGET).bin : $(OBJS)                       # 依赖所有 .o 文件
$(LD) -Timx6ul.lds -o $(TARGET).elf $^ # 1. 链接生成 ELF 文件
$(OBJCOPY) -O binary -S $(TARGET).elf $@ # 2. 提取二进制文件
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis # 3. 生成反汇编文件

编译规则

1
2
$(SOBJS) : obj/%.o : %.S      # 编译 .S 汇编文件(需预处理的汇编)
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
  • -nostdlib:不链接标准库,适用于裸机程序
  • -O2:优化等级为2
  • $(INCLUDE):包含头文件目录的-I选项
1
2
$(COBJS) : obj/%.o : %.c      # 编译 .c C 文件
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<

清理规则

1
2
clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

完整流程:

  1. 收集源码路径:
    • SFILES = project/start.S bsp/clk/clk.S
    • CFILES = project/main.c bsp/clk/clk.c
  2. 提取文件名:
    • SFILENDIR = start.S clk.S
    • CFILENDIR = main.c clk.c
  3. 生成目标文件列表
    • SOBJS = obj/start.o obj/clk.o
    • COBJS = obj/main.o obj/clk.o
    • OBJS = obj/start.o obj/clk.o obj/main.o obj/clk.o
  4. 编译时
    • Make 根据 VPATHprojectbsp/clk 目录中查找 start.Sclk.c 等文件。

Linux下规范性Makefile规则
http://akichen891.github.io/2025/03/02/Linux下规范性Makefile规则/
作者
Aki
发布于
2025年3月2日
更新于
2025年3月2日
许可协议