ARM裸机_5_ledc_bsp_Makefile详解

Makefile使用:

近日,在学习imx6ull裸机开发时候,对于其Makefile文件编写一直处于懵懂状态,为方便日后深入学习,本文章以正点原子BSP-工程管理实验闪烁小灯为例,对其中Makefile文件语法进行注释解析。


代码及解释

实验imx6ul.lds代码如下

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代码如下:

CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET		  ?= ledc

其中赋值符有如下几种类型:

=:在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值
:=:不会使用后面定义的变量,只能使用前面已经定义好的,这就是“=”和“:=”两个的区别
?=:表示如果变量时,前面没有被赋值,那么此变量就是当前赋值的值,如果前面已经赋过值了,那么就使用前面赋的值。

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

此处CC经赋值后,结果为:
CC = arm-linux-gnueabihf-gcc 这样做的目的是便于我们之后使用变量,其他的同理。

INCUDIRS	:= imx6u     \
			   bsp/clk   \
			   bsp/led   \
			   bsp/delay 

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

此段代码定义的两个变量分别代表含义:
INCUDIRS:包含头文件定义的目录;
SRCDIRS:包含源文件定义的目录;
\:表示语句还没有写完,这样我们可以另起一行写,使得代码更加整洁美观。

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

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

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

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

.PHON:clean

其中对于各个变量进行解释:
INCLUDE
在找到所有".h"文件后,编译时候必须加"-I",编译源码时候需要指定头文件路径。比如bsp_ledc_h变为-I bsp_ledc_h。此处使用patsubst函数完成快速添加;

SFILES:
表示通过foreach函数循环将变量SRCDIRS(定义的文件目录)中的值放入dir·中,执行wildcard通配符获取所有变量dir/目录下的.S文件提取出来,循环完成后赋值给变量SFILES

.PHON
表示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 $@ $<
$(LD) -Timx6ul.lds -o $(TARGET).elf $^ 链接:

链接用来将众多的.o 文件链接到一个指定的链接位置。我们需要确定可执行文件其运行起始地址,也就是链接地址。

这里我们要区分存储地址运行地址这两个概念:
存储地址就是可执行文件存储在哪里,可执行文件的存储地址可以随意选择。
运行地址就是代码运行的时候所处的地址,这个我们在链接的时候就已经确定好了,代码要运行,那就必须处于运行地址处,否则代码肯定运行出错。

确定了链接地址以后就可以将前面编译出来的.o文件链接到imx6ul.lds指定的地址,本条命令相当于:arm-linux-gnueabihf-ld -Timx6ul.lds -o $(TARGET).elf $^

imx6ul.lds :其相当于以前的text 0X87800000 led.o是指定链接地址
-o:是指定链接生成的 elf 文件名。
$^:自动化变量$^意思是所有依赖文件的集合

上述命令执行完以后就会在工程目录下多一个led.elf文件。

但是led.elf 文件也不是我们最终烧写到 SD 卡中的可执行文件,我们要烧写的.bin 文件,因此还需要将 led.elf 文件转换为.bin 文件了。

$(OBJCOPY) -O binary -S $(TARGET).elf $@ 格式转换

本条命令相当于arm-linux-gnueabihf-objcopy -O binary -S $(TARGET).elf $@其类似于格式转化。

-O:指定以什么格式输出
binary:以二进制格式输出
-S:不要复制源文件中的重定位信息和符号信息
-g:不复制源文件中的调试信息
$@:自动化变量, 意思是目标集合,这里就是ledc.bin

命令执行完成以后,生成最终的 led.bin 文件。

$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis 反汇编

大多数情况下我们都是用 C 语言写试验例程的,有时候需要查看其汇编代码来调试代码,因此就需要进行反汇编,一般可以将 elf 文件反汇编,本条命令相当于
arm-linux-gnueabihf-objdump -D -m arm $(TARGET).elf > $(TARGET).dis

-D选项表示反汇编所有的段

$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<编译文件

.s文件编译为.o文件

-c选项是编译源文件,但是不链接
-o选项是指定编译产生的文件名字

执行上述命令以后就会编译生一个工程中所有的 C文件和汇编文件都会编译生成一个对应的.o 文件,我们需要将这.o 文件链接起来组合成可执行文件。

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

print:

	@echo INCLUDE = $(INCLUDE)
	@echo SFILES  = $(SFILES)
	@echo CFILES  = $(CFILES)
	@echo SFILENDIR   = $(SFILENDIR)
	@echo CFILENDIR   = $(CFILENDIR)
	@echo SOBJS   = $(SOBJS)
	@echo COBJS   = $(COBJS)
	@echo OBJS    = $(OBJS)

clean: 清除所有的.elf, .bin, .disOBJS(此处变量OBJS表示.o)文件。

print: @echo 变量:在终端打印出变量名。

代码使用的Makefile函数详解:

patsubs函数

函数模型:$(patsubst <pattern>, <replacement>, <text>)

查找text中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式pattern,如果匹配的话,则以replacement替换。

这里,pattern可以包括通配符%,表示任意长度的字串。如果replacement中也包含“%”,那么,replacement中的这个“%”将是pattern中的那个“%”所代表的字串。其结果返回为:替换过后的字符串。

示例: $(patsubst %, -I %, bsp_led.h bsp_delay.h)

把字串bsp_led.h bsp_delay.h符合模式%(其表示全部的text符合匹配,也就是选取全部的字符串text)的单词替换成-I bsp_led.h -I bsp_delay.h ,返回结果是-I bsp_led.h -I bsp_delay.h


wildcard通配符

函数模型:$(wildcard *.o)

当我们在变量中想使用通配符可以使用此方式

例如:
objects = *.o
这里的*.o并不会展开,所以objects的值就是“*.o”。

那当我们想要让通配符在变量中展开,也就是让 objects 的值是所有[.o]的文件名的集合,那么,你可以这样:
objects := $(wildcard *.o)


foreach函数

函数模型:$(foreach <var>,<list>,<text>)

这个函数的意思是,把参数list中的单词逐一取出放到参数var所指定的变量中,然后再执行text所包含的表达式。

每一次text会返回一个字符串,循环过程中,text的所返回的每个字符串会以空格分隔,最后当整个循环结束时,text所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。

VPATH

VPATH不是变量,这是一个 make 的关键字.

当我们定义VPATH,那么如果在我们当前目录下找不到目标文件和依赖文件,它可以到我们指定不同的文件中去寻找。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值