阿尔法点亮LED灯(五)BSP工程管理

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

这里主要是对前面的工程进行优化,将各个不同的文件进行分类,学习如何整理工程、就和学习STM32一样创建工程的各个文件夹分类,实现工程文件 的分类化和模块化,便于管理

深入学习Makefile,学习Makefile的高级技巧,学习编写通用Makefile


提示:以下是本篇文章正文内容,下面案例可供参考

一、工程优化

将不同功能的源码文件放到不同的目录中。另外我们也需要将源码文件中,所有完成同一个功能的代码提取出来放到一个单独的文件中,也就是对程序分功能管理

新建一个工程,在工程里面建立 bsp、 imx6ul、 obj 和 project 这 4 个文件夹

bsp:存放驱动文件
imx6ul:存放跟芯片有关的文件,如SDK库文件
obj:存放编译生成的.o 文件
project:应用文件,也就是start.S 和 main.c 文件

在驱动bsp 文件夹下创建三个子文件夹: clk、 delay 和 led,分别用来存放时钟驱动文件、延时驱动文件和 LED 驱动文件

大致如下图:
在这里插入图片描述

二、路径添加

设置VSCODE头文件路径, 先创建.vscode目录,然后打开c/c++配置器,会在.vscode目录下生成一个叫做c_cpp_properties.json的文件,然后在includePath下按如下方式添加路径
在这里插入图片描述

三、Makefile编写

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)


注:Makefile实在写着有点难受,报错了都不知道是啥子意思,这里报错要么是makefile写错了,要么是链接脚本那里写错了。

1.前面几行都是定义了一些变量,INCDIRS包含了整个工程的.h文件的目录,所有的头文件目录都要添加到INCDIRS中;’'是换行符:表示本行和下一行属于同一行;=SRCDIRS包含了整个工程文件所以的.c和.s文件目录;

2.patsubst(模式字符串替换)是Makefile函数
函数原型

$(patsubst < pattern>,< replacement>,< text>)

查找< text >中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否
符合模式< pattern>,如果匹配的话,则以< replacement>替换。这里, < pattern>可以包括通配符“ %”,表示任意长度的字串。

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

通过函数 patsubst 给变量 INCDIRS 添加一个“-I”,因为Makefile指定头文件路径,需要-I
原来的路径就变为

INCLUDE := -I imx6ul -I bsp/clk -I bsp/led -I bsp/delay

3.变量 SFILES 保存工程中所有的.s 汇编文件(包含绝对路径),变量 SRCDIRS 已经存放了工程中所有的.c 和.S 文件,所以只需要从里面挑出所有的.S 汇编文件即可

foreach函数,作用:用来做循环用的
函数原型:

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

把参数中的单词逐一取出放到参数所指定的变量中,然后再执行 所包含的表达式。每一次 会返回一个字符串,循环过程中, 的所返回的每个字符串会以空格分隔,最后当整个循环结束时, 所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值

wildcard函数, 用来明确表示通配符,在Makefile规则中,通配符会被自动展开,但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数wildcard
比如,$(wildcard *.c)”来获取工作目录下的所有的.c文件列表

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

这里SFILES将会被展开为:

SFILES = project/start.S
CFILES = project/main.c bsp/clk/bsp_clk.c bsp/led/bsp_led.c bsp/delay/bsp_delay.c

4.变量 SFILENDIRCFILENDIR 包含所有的.S 汇编文件和.c 文件,相比变量 SFILES 和 CFILES, SFILENDIR 和 CFILNDIR 只是文件名,不包含文件的绝对路径,使用函数 notdir 将 SFILES 和 CFILES 中的路径去掉即可

函数原型

$(notdir < names…>)

从文件名序列< names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分,也就是提前目录下的函数

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

变成了如下

SFILENDIR = start.S
CFILENDIR = main.c bsp_clk.c bsp_led.c bsp_delay.c

5.变量SOBJSCOBJS 是.S 和.c 文件编译以后对应的.o 文件目录,默认所有的文件编译出来的.o 文件和源文件在同一个目录中,这里我们将所有的.o 文件都放到 obj 文件夹下,变量 OBJS 是变量 SOBJS 和 COBJS 的集合
内容如下

SOBJS = obj/start.o
COBJS = obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o

OBJS = obj/start.o obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o

==6.VPATH作用:指定搜索目录 ==

VPATH			:= $(SRCDIRS)

这里指定的搜素目录就是变量SRCDIRS 所保存的目录,当编译的时候所需的.S 和.c 文件就会在 SRCDIRS 中指定的目录中查找

7.(.PHONY)用来指明该目标是一个伪目标
这里提供一个清除它们的“目标”以备完整地重编译而用,但是不生成clean这个文件,这就是一个伪目标

“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以 make 无法生成它的依赖关系和决定它是否要执行。只有通过显示地指明这个“目标”才能让其生效,“伪目标”的取名不能和文件名重名

为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标就是“伪目标”

8.Makefile静态模式 ,静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活
< targets …>: < target-pattern>: < prereq-patterns …>

targets :定义了一系列的目标文件,可以有通配符,是目标的一个集合
target-parrtern :指明了 targets 的模式,也就是的目标集模式
prereq-parrterns :目标的依赖模式,它对 target-parrtern 形成的模式再进行一次依赖目标的定义

$(OBJS): obj/%.o : %.S  

表示将所有的.S文件编译为.o并且存放到obj目录下去

后面的都很熟悉,编译,链接,反汇编

四、链接脚本和下载

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

这里主要是添加 start.o 文件路径

最后就可以下载程序了…


总结

提示:这里对文章进行总结:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Super.Bear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值