【MakeFile】Linux下的工程管理(BSP)及通用性makefile编写

一、BSP工程管理原理

​ BSP工程管理的目的就是为了模块化整理代码,同一个属性的文件存放在同一个目录里面。

​ 1、新建所需的文件夹,将同一属性的文件放到相应的文件夹中。

​ 2、修改clk、led、delay驱动,创建对应的驱动文件,然后放置到对应的目录中。

​ 3、根据编写的新驱动文件,修改main.c文件内容。

二、Makefile编写

API函数说明:

patsubst函数:

格式:

$(patsubst pattern,replacement,text)

功能简述:

这是一个替换函数,将text的文本按照pattern规则,依次替换为replacement

替换时text的文本以“空格”‘TAB“”回车换行“分割来逐一匹配,是否符合pattern模式。如果匹配成功,则替换为replacement。其中pattern和replacement均可以使用%做为通配符(如需原本的%,则需要%进行转义)

举例:将INCLUDES变量中所有字符段,都加一个 - I。

$(patsubst %, -I %, $(INCLUDES))

foreach函数:

格式:

$(foreach <var>,<list>,<text> )

功能简述:

循环执行指定的功能,将list中的单词逐一取出,放到参数var指定的变量中,再执行text的功能。函数的返回值是text所有各段字符串的组合,var为局部临时变量,函数执行完就被释放了。

举例:

src := 1 2 3 4
out := $(foreach i, $(src), i.c)

此时的out为

1.c 2.c 3.c 4.c

wildcard函数:

格式:

$(wildcard PATTERN...) 

功能简述:
将通配符展开。因为$引用变量时,通配符会失效,所以用这个展开通配符匹配的字符

举例:目录下有1.c 2.c 3.c 4.c 这四个C文件

obj := $(patsubst %.c, %o,$(wildcard *.c))

通配符*会依次配到这四个c文件,$(wildcard *.c)展开为1.c 2.c 3.c 4.c 字符串,然后由patsubst函数将.c替换为.o,返回替换结果。此时:obj为1.o 2.o 3.o 4.o

notdir函数

格式:

$(notdir <names...> )

功能简述:

去除文件路径的函数,保留后缀。

举例:

dir :=./led/led.c
src :=$(notdir $(dir))

去除路径,此时src结果为led.c

VPATH

Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。

静态模式

功能简述:更加容易地定义多目标的规则。
格式:

<targets ...>:<target-pattern>:<prereq-patterns>
<commands>
...

targets 定义了一系列的目标文件,是一个集合,可以有通配符。
target-pattern 指明了targets的模式,也就是目标集模式
prereq-patterns 是目标的依赖模式,对target-pattern 形成的模式再进行依次依赖目标的定义。
$(SOBJS) : obj/%.o : %.S表示将所有的.S编译成.o并存放到obj目录下。

工程文件结构

.
├── bsp                              # 板级支持包
│   ├── clk                          # 时钟驱动
│   │   ├── bsp_clk.c
│   │   └── bsp_clk.h
│   ├── delay                        # 延时驱动
│   │   ├── bsp_delay.c
│   │   └── bsp_delay.h
│   └── led                          # 链接驱动                 
│       ├── bsp_led.c
│       └── bsp_led.h
├── imx6ul                           # imx6ul官方库函数
│   ├── cc.h
│   ├── fsl_common.h
│   ├── fsl_iomuxc.h
│   ├── imx6ul.h
│   └── MCIMX6Y2.h
├── imx6ul.lds                       # 链接脚本
├── imxdownload                      # 下载脚本
├── ledc_bsp.code-workspace          # vsc工程
├── load.imx
├── Makefile                         
├── obj                              # 存放obj文件
└── project                          # 工程main和start文件
    ├── main.c
    └── start.S

链接脚本:

SECTIONS{
        . = 0X87800000;
        .text :
        {
                obj/start.o
                *(.text)
        }
        .rodata ALIGN(4) : {*(.rodata*)}
        .data ALIGN(4)   : { *(.data) }
        __bss_start = .;
        .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
        __bss_end = .;
}

Makefile

编写步骤:
1.定义目标文件及交叉编译链的变量
2.定义源文件路径及头文件路径的变量
3.引用头文件,加入-I(patsubst)
4.找到相应路径下的源文件,c和S文件。(foreach wildcard)
5.转换为不带路径的源文件名
6.定义object文件
7.指定VPATH路径,及告诉make依赖文件和目标文件在哪里寻找
8.
9.编写clear清除编译文件。(.PHONY)

TARGET                          ?= test
CROSS_COMPILER                  ?= arm-linux-gnueabihf-
																	
CC                              := $(CROSS_COMPILER)gcc
LD                              := $(CROSS_COMPILER)ld

OBJCOPY                         := $(CROSS_COMPILER)objcopy
OBJDUMP                         := $(CROSS_COMPILER)objdump

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

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

# 所有C、S文件的路径及文件名
CFILES                          := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SFILES                          := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))

# 所有C、S文件
CFILENDIR                       := $(notdir $(CFILES))
SFILENDIR                       := $(notdir $(SFILES))

# 所有C -> obj文件,放在obj目录下
COBJS                           := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
SOBJS                           := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))

# 所有的.o文件
OBJS                            := $(SOBJS) $(COBJS)

VPATH                           := $(SRCDIRS)

$(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 $@ $<



.PHONY:clear
clear:
	rm -rf $(OBJS) $(TARGET).bin  $(TARGET).elf  $(TARGET).dis

print:
	@echo INCLUDE = $(INCLUDE)
	@echo CFILES  = $(CFILES) $(SFILES)
	@echo CFILENDIR  = $(CFILENDIR)
	@echo SFILENDIR  = $(SFILENDIR)
	@echo ---OBJ = $(OBJS)

总结:

1.VPATH 用于指定源文件的目录。(当当前目录找不到,就VPATH目录下寻找)不能少。

2.-o问题,原本为 输入 -o输出 若将 输入输出写一块,只能这样写 -o 输出 输入

3.gcc参数说明:

-Wall编译后显示所有警告
-nostdlib 不链接标准库(启动文件)
-O2 优化编译及效率

4.静态模式

<targets ...>: <target-pattern>: <prereq-patterns ...>

$(OBJS): obj/%.o : %.S 表示将所有的.S文件编译为.o并且存放到obj目录下去。

猜你喜欢

转载自blog.csdn.net/qq_44078824/article/details/119948816